From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH BlueZ v1 3/9] monitor: Add LL decoding for HDT
Date: Tue, 3 Nov 2026 17:19:37 -0500 [thread overview]
Message-ID: <20261103221944.4072041-4-luiz.dentz@gmail.com> (raw)
In-Reply-To: <20261103221944.4072041-1-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Decode the LL_ENC_ECDH_REQ/RSP, LL_HDT_CONFIG_REQ/RSP and
LL_HDT_LQF_REPORTING_IND Link Layer PDUs introduced by HDT and EKS.
---
monitor/ll.c | 331 ++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 330 insertions(+), 1 deletion(-)
diff --git a/monitor/ll.c b/monitor/ll.c
index 6c0f67b5dcae..2d4161c8f09b 100644
--- a/monitor/ll.c
+++ b/monitor/ll.c
@@ -537,7 +537,9 @@ static void length_req_rsp(const void *data, uint8_t size)
static const struct bitfield_data le_phys[] = {
{ 0, "LE 1M" },
{ 1, "LE 2M" },
- { 2, "LE Coded"},
+ { 2, "LE Coded S=8"},
+ { 3, "LE Coded S=2"},
+ { 4, "LE HDT" },
{ }
};
@@ -759,6 +761,303 @@ static void feature_ext_rsp(const void *data, uint8_t size)
packet_print_features_ext_ll(rsp->page, rsp->features);
}
+static const struct bitfield_data coded_rates[] = {
+ { 0, "CODED S=8" },
+ { 1, "CODED S=0" },
+ { }
+};
+
+static const struct bitfield_data hdt_rates[] = {
+ { 0, "HDT 2M" },
+ { 1, "HDT 3M" },
+ { 2, "HDT 4M" },
+ { 3, "HDT 6M" },
+ { 4, "HDT 7.5M" },
+ { }
+};
+
+static void print_rates(const char *prefix, uint8_t phy, uint16_t rates)
+{
+ const struct bitfield_data *fields = NULL;
+
+ switch (phy) {
+ case 0x01:
+ case 0x02:
+ break;
+ case 0x03:
+ fields = coded_rates;
+ break;
+ case 0x04:
+ fields = hdt_rates;
+ break;
+ default:
+ break;
+ }
+
+ print_field("%s: 0x%4.4x", prefix, rates);
+
+ if (fields) {
+ uint16_t mask = print_bitfield(2, rates, fields);
+ if (mask)
+ print_text(COLOR_UNKNOWN_OPTIONS_BIT, " Reserved"
+ " (0x%4.4x)", mask);
+ }
+}
+
+static void print_le_phy(const char *prefix, uint8_t phy)
+{
+ const char *str;
+
+ switch (phy) {
+ case 0x01:
+ str = "LE 1M";
+ break;
+ case 0x02:
+ str = "LE 2M";
+ break;
+ case 0x03:
+ str = "LE Coded";
+ break;
+ case 0x04:
+ str = "LE HDT";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("%s: %s (0x%2.2x)", prefix, str, phy);
+}
+
+static void cis_req_v3(const void *data, uint8_t size)
+{
+ const struct bt_ll_cis_req_v3 *cmd = data;
+
+ print_field("CIG ID: 0x%2.2x", cmd->cig);
+ print_field("CIS ID: 0x%2.2x", cmd->cis);
+
+ print_le_phy("Central to Peripheral PHY", cmd->c_phy);
+ print_le_phy("Peripheral To Central PHY", cmd->p_phy);
+
+ print_field("Central to Peripheral Maximum SDU: %u", cmd->c_sdu);
+ print_field("Peripheral to Central Maximum SDU: %u", cmd->p_sdu);
+
+ print_field("Central to Peripheral Interval: %u",
+ get_le24(cmd->c_interval));
+ print_field("Peripheral to Central Interval: %u",
+ get_le24(cmd->p_interval));
+
+ print_field("Central to Peripheral Maximum Payload: %u", cmd->c_pdu);
+ print_field("Peripheral to Central Maximum Payload: %u", cmd->p_pdu);
+
+ print_field("BN: %u", cmd->bn);
+
+ print_field("Sub-Interval: %u", get_le24(cmd->sub_interval));
+
+ print_field("NSE: %u", cmd->nse);
+
+ print_field("Central to Peripheral Flush Timeout: %u", cmd->c_ft);
+ print_field("Peripheral to Central Flush Timeout: %u", cmd->p_ft);
+
+ print_field("ISO Interval: %u", le16_to_cpu(cmd->iso_interval));
+
+ print_field("CIS Offset Minimum: %u", get_le24(cmd->offset_min));
+ print_field("CIS Offset Maximum: %u", get_le24(cmd->offset_max));
+
+ print_field("Connection Event Count: %u", cmd->conn_event_count);
+
+ print_rates("Central to Peripheral Rates", cmd->c_phy, cmd->c_rates);
+ print_rates("Peripheral To Central Rates", cmd->p_phy, cmd->p_rates);
+
+ print_field("Config ID: %u", cmd->config_id);
+ print_field("TL Group ID: 0x%2.2x", cmd->tl_group_id);
+
+ print_field("Central to Peripheral Windows Size: %u",
+ cmd->wincfg | (BIT(0) & BIT(1)));
+ print_field("Peripheral to Central Windows Size: %u",
+ cmd->wincfg | (BIT(2) & BIT(3)));
+ print_field("MIC Length: %u", cmd->wincfg & BIT(4));
+}
+
+static const struct bitfield_data lqf_transports[] = {
+ { 0, "ACL" },
+ { 1, "CIS" },
+ { }
+};
+
+static void hdt_lqf_ind(const void *data, uint8_t size)
+{
+ const struct bt_ll_hdt_lqf_ind *pdu = data;
+ uint8_t mask;
+
+ print_field("Transport: 0x%2.2x", pdu->transport);
+
+ mask = print_bitfield(2, pdu->transport, lqf_transports);
+ if (mask)
+ print_text(COLOR_UNKNOWN_OPTIONS_BIT, " Reserved"
+ " (0x%2.2x)", mask);
+}
+
+static void hdt_config_req(const void *data, uint8_t size)
+{
+ const struct bt_ll_hdt_config_req *pdu = data;
+
+ print_field("ACL RX Payload Windows Size: %u",
+ pdu->wincfg & (BIT(0) & BIT(1)));
+ print_field("Max CIS TX Windows Size: %u",
+ pdu->wincfg & (BIT(2) & BIT(3)));
+ print_field("Max CIS RX Windows Size: %u",
+ pdu->wincfg & (BIT(4) & BIT(5)));
+ print_rates("ACL RX Rates", 0x04, pdu->acl_rx_rates);
+ print_field("Max ACL RX Packet Size: %u", pdu->acl_rx_mtu);
+}
+
+static void hdt_config_rsp(const void *data, uint8_t size)
+{
+ const struct bt_ll_hdt_config_rsp *pdu = data;
+
+ print_field("ACL RX Payload Windows Size: %u",
+ pdu->wincfg & (BIT(0) & BIT(1)));
+ print_field("Max CIS TX Windows Size: %u",
+ pdu->wincfg & (BIT(2) & BIT(3)));
+ print_field("Max CIS RX Windows Size: %u",
+ pdu->wincfg & (BIT(4) & BIT(5)));
+ print_rates("ACL RX Rates", 0x04, pdu->acl_rx_rates);
+ print_field("Max ACL RX Packet Size: %u", pdu->acl_rx_mtu);
+}
+
+static void phy_update_ind_v2(const void *data, uint8_t size)
+{
+ const struct bt_ll_phy_update_ind_v2 *pdu = data;
+ uint8_t mask;
+
+ print_field("C_TO_P_PHY: 0x%2.2x", pdu->c_phy);
+
+ mask = print_bitfield(2, pdu->c_phy, le_phys);
+ if (mask)
+ print_text(COLOR_UNKNOWN_OPTIONS_BIT, " Reserved"
+ " (0x%2.2x)", mask);
+
+ print_field("P_TO_C_PHY: 0x%2.2x", pdu->p_phy);
+
+ mask = print_bitfield(2, pdu->p_phy, le_phys);
+ if (mask)
+ print_text(COLOR_UNKNOWN_OPTIONS_BIT, " Reserved"
+ " (0x%2.2x)", mask);
+
+ print_field("Instant: 0x%4.4x", pdu->instant);
+
+ print_field("Address: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
+ pdu->address[0], pdu->address[1], pdu->address[2],
+ pdu->address[3], pdu->address[4]);
+}
+
+static void cis_ind_v2(const void *data, uint8_t size)
+{
+ const struct bt_ll_cis_ind_v2 *ind = data;
+
+ print_field("CIS Access Address: 0x%4.4x", le32_to_cpu(ind->addr));
+ print_field("CIS Offset: 0x%6.6x", get_le24(ind->cis_offset));
+
+ print_field("CIG Synchronization Delay: %u us",
+ get_le24(ind->cig_sync_delay));
+ print_field("CIS Synchronization Delay: %u us",
+ get_le24(ind->cis_sync_delay));
+ print_field("Connection Event Count: %u", ind->conn_event_count);
+ print_field("PCA-H: 0x%2.2x", ind->pca_h);
+}
+
+static const struct bitfield_data ecdh_flags[] = {
+ { 0, "Allow 64-bit MIC length" },
+ { 1, "Opportunistic encryption" },
+ { }
+};
+
+static void print_key_type(const char *str, uint8_t type)
+{
+ switch (type) {
+ case 0x00:
+ print_field("%s: Public key P-256 (0x00)", str);
+ break;
+ default:
+ print_field("%s: Reserved (0x%2.2x)", str, type);
+ break;
+ }
+}
+
+static void enc_ecdh_req(const void *data, uint8_t size)
+{
+ const struct bt_ll_enc_ecdh_req *cmd = data;
+ uint8_t mask;
+
+ print_field("Flags: 0x%2.2x", cmd->flags);
+
+ mask = print_bitfield(2, cmd->flags, ecdh_flags);
+ if (mask)
+ print_text(COLOR_UNKNOWN_OPTIONS_BIT, " Reserved"
+ " (0x%2.2x)", mask);
+
+ print_hex_field("Rand", cmd->rand, 16);
+ print_key_type("Key Type", cmd->key_type);
+ print_hex_field("Public Key", cmd->pubkey, 64);
+}
+
+static void enc_ecdh_rsp(const void *data, uint8_t size)
+{
+ const struct bt_ll_enc_ecdh_rsp *rsp = data;
+ uint8_t mask;
+
+ print_field("Flags: 0x%2.2x", rsp->flags);
+
+ mask = print_bitfield(2, rsp->flags, ecdh_flags);
+ if (mask)
+ print_text(COLOR_UNKNOWN_OPTIONS_BIT, " Reserved"
+ " (0x%2.2x)", mask);
+
+ print_hex_field("Rand", rsp->rand, 16);
+ print_key_type("Key Type", rsp->key_type);
+ print_hex_field("Public Key", rsp->pubkey, 64);
+}
+
+static const struct bitfield_data refresh_flags[] = {
+ { 0, "64-bit MIC length preferred" },
+ { }
+};
+
+static void refresh_enc_req(const void *data, uint8_t size)
+{
+ const struct bt_ll_refresh_enc_req *pdu = data;
+ uint8_t mask;
+
+ print_field("Flags: 0x%2.2x", pdu->flags);
+
+ mask = print_bitfield(2, pdu->flags, refresh_flags);
+ if (mask)
+ print_text(COLOR_UNKNOWN_OPTIONS_BIT, " Reserved"
+ " (0x%2.2x)", mask);
+}
+
+static void refresh_enc_rsp(const void *data, uint8_t size)
+{
+ const struct bt_ll_refresh_enc_req *pdu = data;
+ uint8_t mask;
+
+ print_field("Flags: 0x%2.2x", pdu->flags);
+
+ mask = print_bitfield(2, pdu->flags, refresh_flags);
+ if (mask)
+ print_text(COLOR_UNKNOWN_OPTIONS_BIT, " Reserved"
+ " (0x%2.2x)", mask);
+}
+
+static void refresh_enc_ind(const void *data, uint8_t size)
+{
+ const struct bt_ll_refresh_enc_ind *pdu = data;
+
+ print_field("MIC length: %u", pdu->mic_len);
+ print_field("Instant: 0x%4.4x", pdu->instant);
+}
+
struct llcp_data {
uint8_t opcode;
const char *str;
@@ -767,6 +1066,12 @@ struct llcp_data {
bool fixed;
};
+#define LLCP_OP_VL(_op, _str, _func, _type) \
+ { _op, _str, _func, sizeof(_type), false }
+
+#define LLCP_OP(_op, _str, _func, _type) \
+ { _op, _str, _func, sizeof(_type), true }
+
static const struct llcp_data llcp_table[] = {
{ 0x00, "LL_CONNECTION_UPDATE_REQ", conn_update_req, 11, true },
{ 0x01, "LL_CHANNEL_MAP_REQ", channel_map_req, 7, true },
@@ -814,6 +1119,30 @@ static const struct llcp_data llcp_table[] = {
{ BT_LL_CIS_RSP, "LL_FEATURE_EXT_RSP", feature_ext_rsp,
sizeof(struct bt_ll_feature_ext_rsp),
true },
+ /* HDT LLCP commands */
+ LLCP_OP(BT_LL_CIS_REQ_V3, "LL_CIS_REQ[v3]", cis_req_v3,
+ struct bt_ll_cis_req_v3),
+ LLCP_OP(BT_LL_HDT_LQF_REPORTING_IND, "LL_HDT_LQF_REPORTING_IND",
+ hdt_lqf_ind, struct bt_ll_hdt_lqf_ind),
+ LLCP_OP(BT_LL_HDT_CONFIG_REQ, "LL_HDT_CONFIG_REQ", hdt_config_req,
+ struct bt_ll_hdt_config_req),
+ LLCP_OP(BT_LL_HDT_CONFIG_RSP, "LL_HDT_CONFIG_RSP", hdt_config_rsp,
+ struct bt_ll_hdt_config_rsp),
+ LLCP_OP(BT_LL_PHY_UPDATE_IND_V2, "LL_PHY_UPDATE_IND[v2]",
+ phy_update_ind_v2,
+ struct bt_ll_phy_update_ind_v2),
+ LLCP_OP(BT_LL_CIS_IND_V2, "LL_CIS_IND[v2]", cis_ind_v2,
+ struct bt_ll_cis_ind_v2),
+ LLCP_OP(BT_LL_ENC_ECDH_REQ, "LL_ENC_ECDH_REQ", enc_ecdh_req,
+ struct bt_ll_enc_ecdh_req),
+ LLCP_OP(BT_LL_ENC_ECDH_RSP, "LL_ENC_ECDH_RSP", enc_ecdh_rsp,
+ struct bt_ll_enc_ecdh_rsp),
+ LLCP_OP(BT_LL_REFRESH_ENC_REQ, "LL_REFRESH_ENC_REQ", refresh_enc_req,
+ struct bt_ll_refresh_enc_req),
+ LLCP_OP(BT_LL_REFRESH_ENC_RSP, "LL_REFRESH_ENC_RSP", refresh_enc_rsp,
+ struct bt_ll_refresh_enc_rsp),
+ LLCP_OP(BT_LL_REFRESH_ENC_IND, "LL_REFRESH_ENC_IND", refresh_enc_ind,
+ struct bt_ll_refresh_enc_ind),
{ }
};
--
2.56.0
next prev parent reply other threads:[~2026-11-03 22:19 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-03 22:19 [PATCH BlueZ v1 0/9] Add support for HDT and EKS Luiz Augusto von Dentz
2026-11-03 22:19 ` [PATCH BlueZ v1 1/9] lib: Add HDT definitions Luiz Augusto von Dentz
2026-11-04 2:34 ` Add support for HDT and EKS bluez.test.bot
2026-11-03 22:19 ` [PATCH BlueZ v1 2/9] monitor: Add HCI decoding for HDT Luiz Augusto von Dentz
2026-11-03 22:19 ` Luiz Augusto von Dentz [this message]
2026-11-03 22:19 ` [PATCH BlueZ v1 4/9] emulator: Add HDT support to btdev Luiz Augusto von Dentz
2026-11-03 22:19 ` [PATCH BlueZ v1 5/9] emulator: Add HDT support to bthost Luiz Augusto von Dentz
2026-11-03 22:19 ` [PATCH BlueZ v1 6/9] shared/gatt: Add MIC length permission checks Luiz Augusto von Dentz
2026-11-03 22:19 ` [PATCH BlueZ v1 7/9] main.conf: Add HDT configuration Luiz Augusto von Dentz
2026-11-03 22:19 ` [PATCH BlueZ v1 8/9] l2cap-tester, iso-tester, mgmt-tester: Add HDT tests Luiz Augusto von Dentz
2026-11-03 22:19 ` [PATCH BlueZ v1 9/9] l2test: Add HDT options Luiz Augusto von Dentz
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261103221944.4072041-4-luiz.dentz@gmail.com \
--to=luiz.dentz@gmail.com \
--cc=linux-bluetooth@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox