* [PATCH BlueZ v2 2/3] emulator: Add support for LL Extended Feature Set
2025-11-04 14:25 [PATCH BlueZ v2 1/3] monitor: Decode Bluetooth 6.0 version Luiz Augusto von Dentz
@ 2025-11-04 14:25 ` Luiz Augusto von Dentz
2025-11-04 14:25 ` [PATCH BlueZ v2 3/3] mgmt-tester: Add tests for 5.2 and 6.0 Bluetooth version Luiz Augusto von Dentz
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Luiz Augusto von Dentz @ 2025-11-04 14:25 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds support for emulating LL Extended Feature Set introduced in 6.0
that adds the following:
Commands:
- HCI_LE_Read_All_Local_Supported_Features(0x2087)(Feature:47,1)
- HCI_LE_Read_All_Remote_Features(0x2088)(Feature:47,2)
Events:
- HCI_LE_Read_All_Remote_Features_Complete(0x2b)(Mask bit:42)
---
emulator/btdev.c | 101 ++++++++++++++++++++++++++++++++++++++++++++--
emulator/btdev.h | 1 +
emulator/hciemu.c | 3 ++
emulator/hciemu.h | 1 +
emulator/main.c | 2 +-
5 files changed, 103 insertions(+), 5 deletions(-)
diff --git a/emulator/btdev.c b/emulator/btdev.c
index c53db7040d39..839b4941ca05 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -178,7 +178,7 @@ struct btdev {
uint8_t country_code;
uint8_t bdaddr[6];
uint8_t random_addr[6];
- uint8_t le_features[8];
+ uint8_t le_features[248];
uint8_t le_states[8];
const struct btdev_cmd *cmds;
uint16_t msft_opcode;
@@ -7362,6 +7362,75 @@ static const struct btdev_cmd cmd_le[] = {
{}
};
+static int cmd_le_read_all_local_features(struct btdev *dev, const void *data,
+ uint8_t len)
+{
+ struct bt_hci_rsp_le_read_all_local_features rsp;
+
+ memset(&rsp, 0, sizeof(rsp));
+ rsp.status = BT_HCI_ERR_SUCCESS;
+ memcpy(rsp.features, dev->le_features, 248);
+
+ cmd_complete(dev, BT_HCI_CMD_LE_READ_ALL_LOCAL_FEATURES, &rsp,
+ sizeof(rsp));
+
+ return 0;
+}
+
+static int cmd_le_read_all_remote_features(struct btdev *dev, const void *data,
+ uint8_t len)
+{
+ const struct bt_hci_cmd_le_read_all_remote_features *cmd = data;
+ struct bt_hci_evt_le_read_all_remote_features_complete ev;
+ struct btdev_conn *conn;
+ uint8_t status = BT_HCI_ERR_SUCCESS;
+
+ conn = queue_find(dev->conns, match_handle,
+ UINT_TO_PTR(le16_to_cpu(cmd->handle)));
+ if (!conn)
+ status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+
+ cmd_status(dev, status, BT_HCI_CMD_LE_READ_ALL_REMOTE_FEATURES);
+
+ if (status)
+ return 0;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.status = BT_HCI_ERR_SUCCESS;
+ ev.handle = cpu_to_le16(conn->handle);
+ ev.max_pages = 1;
+ ev.valid_pages = 1;
+ memcpy(ev.features, conn->link->dev->le_features, 248);
+
+ le_meta_event(dev, BT_HCI_EVT_LE_READ_ALL_REMOTE_FEATURES_COMPLETE, &ev,
+ sizeof(ev));
+
+ return 0;
+}
+
+#define CMD_LE_60 \
+ CMD(BT_HCI_CMD_LE_READ_ALL_LOCAL_FEATURES, \
+ cmd_le_read_all_local_features, NULL), \
+ CMD(BT_HCI_CMD_LE_READ_ALL_REMOTE_FEATURES, \
+ cmd_le_read_all_remote_features, NULL)
+
+static const struct btdev_cmd cmd_le_6_0[] = {
+ CMD_COMMON_ALL,
+ CMD_COMMON_BREDR_LE,
+ CMD_LE,
+ CMD_LE_50,
+ CMD_LE_52,
+ CMD_LE_60,
+ {}
+};
+
+static void set_le_60_commands(struct btdev *btdev)
+{
+ btdev->commands[47] |= BIT(2); /* LE Read All Local Features */
+ btdev->commands[47] |= BIT(3); /* LE Read All Remote Features */
+ btdev->cmds = cmd_le_6_0;
+}
+
static void set_le_commands(struct btdev *btdev)
{
set_common_commands_all(btdev);
@@ -7427,6 +7496,12 @@ static void set_le_commands(struct btdev *btdev)
set_le_52_commands(btdev);
btdev->cmds = cmd_le_5_2;
}
+
+ /* Extra LE commands for >= 6.0 adapters */
+ if (btdev->type >= BTDEV_TYPE_BREDRLE52) {
+ set_le_60_commands(btdev);
+ btdev->cmds = cmd_le_6_0;
+ }
}
static int cmd_set_event_mask_2(struct btdev *dev, const void *data,
@@ -7607,6 +7682,7 @@ static void set_bredrle_features(struct btdev *btdev)
}
if (btdev->type >= BTDEV_TYPE_BREDRLE52) {
+ btdev->version = 0x0b;
btdev->le_features[1] |= 0x20; /* LE PER ADV */
btdev->le_features[3] |= BIT(0); /* LE PAST Sender */
btdev->le_features[3] |= BIT(1); /* LE PAST Receiver */
@@ -7617,6 +7693,11 @@ static void set_bredrle_features(struct btdev *btdev)
btdev->le_features[4] |= 0x01; /* LE ISO channels */
}
+ if (btdev->type >= BTDEV_TYPE_BREDRLE60) {
+ btdev->version = 0x0e;
+ btdev->le_features[7] |= BIT(7); /* LL Extended Features */
+ }
+
btdev->feat_page_2[0] |= 0x01; /* CPB - Central Operation */
btdev->feat_page_2[0] |= 0x02; /* CPB - Peripheral Operation */
btdev->feat_page_2[0] |= 0x04; /* Synchronization Train */
@@ -7717,14 +7798,23 @@ struct btdev *btdev_create(enum btdev_type type, uint16_t id)
memset(btdev, 0, sizeof(*btdev));
- if (type == BTDEV_TYPE_BREDRLE || type == BTDEV_TYPE_LE ||
- type == BTDEV_TYPE_BREDRLE50 ||
- type == BTDEV_TYPE_BREDRLE52) {
+ switch (type) {
+ case BTDEV_TYPE_BREDRLE:
+ case BTDEV_TYPE_LE:
+ case BTDEV_TYPE_BREDRLE50:
+ case BTDEV_TYPE_BREDRLE52:
+ case BTDEV_TYPE_BREDRLE60:
btdev->crypto = bt_crypto_new();
if (!btdev->crypto) {
free(btdev);
return NULL;
}
+ break;
+ case BTDEV_TYPE_BREDR:
+ case BTDEV_TYPE_BREDR20:
+ case BTDEV_TYPE_AMP:
+ default:
+ break;
}
btdev->type = type;
@@ -7736,6 +7826,7 @@ struct btdev *btdev_create(enum btdev_type type, uint16_t id)
case BTDEV_TYPE_BREDRLE:
case BTDEV_TYPE_BREDRLE50:
case BTDEV_TYPE_BREDRLE52:
+ case BTDEV_TYPE_BREDRLE60:
btdev->version = 0x09;
set_bredrle_features(btdev);
set_bredrle_commands(btdev);
@@ -8448,6 +8539,7 @@ int btdev_set_msft_opcode(struct btdev *btdev, uint16_t opcode)
case BTDEV_TYPE_BREDRLE:
case BTDEV_TYPE_BREDRLE50:
case BTDEV_TYPE_BREDRLE52:
+ case BTDEV_TYPE_BREDRLE60:
btdev->msft_opcode = opcode;
btdev->msft_cmds = cmd_msft;
return 0;
@@ -8505,6 +8597,7 @@ int btdev_set_emu_opcode(struct btdev *btdev, uint16_t opcode)
case BTDEV_TYPE_BREDRLE:
case BTDEV_TYPE_BREDRLE50:
case BTDEV_TYPE_BREDRLE52:
+ case BTDEV_TYPE_BREDRLE60:
btdev->emu_opcode = opcode;
btdev->emu_cmds = cmd_emu;
return 0;
diff --git a/emulator/btdev.h b/emulator/btdev.h
index c7b3b468ac4c..d473bd4b3414 100644
--- a/emulator/btdev.h
+++ b/emulator/btdev.h
@@ -52,6 +52,7 @@ enum btdev_type {
BTDEV_TYPE_BREDR20,
BTDEV_TYPE_BREDRLE50,
BTDEV_TYPE_BREDRLE52,
+ BTDEV_TYPE_BREDRLE60,
};
enum btdev_hook_type {
diff --git a/emulator/hciemu.c b/emulator/hciemu.c
index 3521e99948d7..8c73a07eede0 100644
--- a/emulator/hciemu.c
+++ b/emulator/hciemu.c
@@ -382,6 +382,9 @@ struct hciemu *hciemu_new_num(enum hciemu_type type, uint8_t num)
case HCIEMU_TYPE_BREDRLE52:
hciemu->btdev_type = BTDEV_TYPE_BREDRLE52;
break;
+ case HCIEMU_TYPE_BREDRLE60:
+ hciemu->btdev_type = BTDEV_TYPE_BREDRLE60;
+ break;
default:
return NULL;
}
diff --git a/emulator/hciemu.h b/emulator/hciemu.h
index 9fbe34316f61..1164be6510a3 100644
--- a/emulator/hciemu.h
+++ b/emulator/hciemu.h
@@ -21,6 +21,7 @@ enum hciemu_type {
HCIEMU_TYPE_LEGACY,
HCIEMU_TYPE_BREDRLE50,
HCIEMU_TYPE_BREDRLE52,
+ HCIEMU_TYPE_BREDRLE60,
};
enum hciemu_hook_type {
diff --git a/emulator/main.c b/emulator/main.c
index bdc2f0deb738..456fcd98eed0 100644
--- a/emulator/main.c
+++ b/emulator/main.c
@@ -92,7 +92,7 @@ int main(int argc, char *argv[])
bool serial_enabled = false;
int letest_count = 0;
int vhci_count = 0;
- enum btdev_type type = BTDEV_TYPE_BREDRLE52;
+ enum btdev_type type = BTDEV_TYPE_BREDRLE60;
int i;
mainloop_init();
--
2.51.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH BlueZ v2 3/3] mgmt-tester: Add tests for 5.2 and 6.0 Bluetooth version
2025-11-04 14:25 [PATCH BlueZ v2 1/3] monitor: Decode Bluetooth 6.0 version Luiz Augusto von Dentz
2025-11-04 14:25 ` [PATCH BlueZ v2 2/3] emulator: Add support for LL Extended Feature Set Luiz Augusto von Dentz
@ 2025-11-04 14:25 ` Luiz Augusto von Dentz
2025-11-04 16:11 ` [BlueZ,v2,1/3] monitor: Decode Bluetooth 6.0 version bluez.test.bot
2025-11-06 23:10 ` [PATCH BlueZ v2 1/3] " patchwork-bot+bluetooth
3 siblings, 0 replies; 5+ messages in thread
From: Luiz Augusto von Dentz @ 2025-11-04 14:25 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds the following tests that attempt to initialize controllers
with version 5.2 and 6.0:
- Set Low Energy on 5.2 - Success 4
- Set Low Energy on 6.0 - Success 5
---
tools/mgmt-tester.c | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 242909117987..663879a8fcd7 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -576,6 +576,20 @@ static void test_condition_complete(struct test_data *data)
#define test_bredrle50(name, data, setup, func) \
test_bredrle50_full(name, data, setup, func, 2)
+#define test_bredrle52_full(name, data, setup, func, timeout) \
+ test_full(name, data, setup, func, timeout, HCIEMU_TYPE_BREDRLE52, \
+ 0x0b, 0x0001beff, 0x00000080)
+
+#define test_bredrle52(name, data, setup, func) \
+ test_bredrle52_full(name, data, setup, func, 2)
+
+#define test_bredrle60_full(name, data, setup, func, timeout) \
+ test_full(name, data, setup, func, timeout, HCIEMU_TYPE_BREDRLE60, \
+ 0x0e, 0x0001beff, 0x00000080)
+
+#define test_bredrle60(name, data, setup, func) \
+ test_bredrle60_full(name, data, setup, func, 2)
+
#define test_hs_full(name, data, setup, func, timeout) \
test_full(name, data, setup, func, timeout, HCIEMU_TYPE_BREDRLE, \
0x09, 0x0001bfff, 0x00000080)
@@ -1696,6 +1710,7 @@ static const char set_le_invalid_param[] = { 0x02 };
static const char set_le_garbage_param[] = { 0x01, 0x00 };
static const char set_le_settings_param_1[] = { 0x80, 0x02, 0x00, 0x00 };
static const char set_le_settings_param_2[] = { 0x81, 0x02, 0x00, 0x00 };
+static const char set_le_settings_param_4[] = { 0x81, 0x02, 0xfc, 0x01 };
static const char set_le_on_write_le_host_param[] = { 0x01, 0x00 };
static const struct generic_data set_le_on_success_test_1 = {
@@ -1736,6 +1751,20 @@ static const struct generic_data set_le_on_success_test_3 = {
.expect_hci_len = sizeof(set_le_on_write_le_host_param),
};
+static const struct generic_data set_le_on_success_test_4 = {
+ .setup_settings = settings_le,
+ .send_opcode = MGMT_OP_SET_POWERED,
+ .send_param = set_powered_on_param,
+ .send_len = sizeof(set_powered_on_param),
+ .expect_status = MGMT_STATUS_SUCCESS,
+ .expect_param = set_le_settings_param_4,
+ .expect_len = sizeof(set_le_settings_param_4),
+ .expect_settings_set = MGMT_SETTING_LE,
+ .expect_hci_command = BT_HCI_CMD_WRITE_LE_HOST_SUPPORTED,
+ .expect_hci_param = set_le_on_write_le_host_param,
+ .expect_hci_len = sizeof(set_le_on_write_le_host_param),
+};
+
static const struct generic_data set_le_on_invalid_param_test_1 = {
.send_opcode = MGMT_OP_SET_LE,
.expect_status = MGMT_STATUS_INVALID_PARAMS,
@@ -13231,6 +13260,12 @@ int main(int argc, char *argv[])
test_bredrle("Set Low Energy on - Success 3",
&set_le_on_success_test_3,
NULL, test_command_generic);
+ test_bredrle52("Set Low Energy on 5.2 - Success 4",
+ &set_le_on_success_test_4,
+ NULL, test_command_generic);
+ test_bredrle60("Set Low Energy on 6.0 - Success 5",
+ &set_le_on_success_test_4,
+ NULL, test_command_generic);
test_bredrle("Set Low Energy on - Invalid parameters 1",
&set_le_on_invalid_param_test_1,
NULL, test_command_generic);
--
2.51.0
^ permalink raw reply related [flat|nested] 5+ messages in thread