From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH BlueZ v1 2/2] monitor: Add decoding for Short Connection Interval feature
Date: Mon, 4 May 2026 17:13:02 -0400 [thread overview]
Message-ID: <20260504211303.1081876-2-luiz.dentz@gmail.com> (raw)
In-Reply-To: <20260504211303.1081876-1-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds deconding support for SCI related commands, command bits, event
event mask bit and feature bits:
Events:
HCI_LE_Connection_Rate_Change(0x37)
Commands:
HCI_LE_Connection_Rate_Request(0x20a1)
HCI_LE_Set_Default_Rate_Parameters(0x20a2)
HCI_LE_Read_Minimum_Supported_Connection_Interval(0x20a3)
---
monitor/bt.h | 54 ++++++++++++++++++++
monitor/packet.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 184 insertions(+)
diff --git a/monitor/bt.h b/monitor/bt.h
index 147b76537e97..60fe2efbf143 100644
--- a/monitor/bt.h
+++ b/monitor/bt.h
@@ -3196,6 +3196,49 @@ struct bt_hci_cmd_le_fsu {
uint8_t types;
} __attribute__ ((packed));
+#define BT_HCI_CMD_LE_CONN_RATE 0x20a1
+#define BT_HCI_BIT_LE_CONN_RATE BT_HCI_CMD_BIT(48, 5)
+struct bt_hci_cmd_le_conn_rate {
+ uint16_t handle;
+ uint16_t interval_min;
+ uint16_t interval_max;
+ uint16_t subrate_min;
+ uint16_t subrate_max;
+ uint16_t max_latency;
+ uint16_t cont_num;
+ uint16_t supv_timeout;
+ uint16_t min_ce_len;
+ uint16_t max_ce_len;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_SET_DEF_RATE 0x20a2
+#define BT_HCI_BIT_LE_SET_DEF_RATE BT_HCI_CMD_BIT(48, 6)
+struct bt_hci_cmd_le_set_def_rate {
+ uint16_t interval_min;
+ uint16_t interval_max;
+ uint16_t subrate_min;
+ uint16_t subrate_max;
+ uint16_t max_latency;
+ uint16_t cont_num;
+ uint16_t supv_timeout;
+ uint16_t min_ce_len;
+ uint16_t max_ce_len;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_READ_CONN_INTERVAL 0x20a3
+#define BT_HCI_BIT_LE_READ_CONN_INTERVAL BT_HCI_CMD_BIT(48, 7)
+struct bt_hci_le_conn_interval_group {
+ uint16_t min;
+ uint16_t max;
+ uint16_t stride;
+} __attribute__ ((packed));
+
+struct bt_hci_rsp_le_read_conn_interval {
+ uint8_t status;
+ uint8_t num_grps;
+ struct bt_hci_le_conn_interval_group grps[0];
+} __attribute__ ((packed));
+
#define BT_HCI_EVT_INQUIRY_COMPLETE 0x01
struct bt_hci_evt_inquiry_complete {
uint8_t status;
@@ -4154,6 +4197,17 @@ struct bt_hci_evt_le_fsu_complete {
uint8_t types;
} __attribute__ ((packed));
+#define BT_HCI_EVT_LE_CONN_RATE_CHANGE 0x37
+struct bt_hci_evt_le_conn_rate_change {
+ uint8_t status;
+ uint16_t handle;
+ uint16_t interval;
+ uint16_t subrate;
+ uint16_t latency;
+ uint16_t cont_number;
+ uint16_t supv_timeout;
+} __attribute__ ((packed));
+
#define BT_HCI_ERR_SUCCESS 0x00
#define BT_HCI_ERR_UNKNOWN_COMMAND 0x01
#define BT_HCI_ERR_UNKNOWN_CONN_ID 0x02
diff --git a/monitor/packet.c b/monitor/packet.c
index 4697eea099a9..a0bf7a70987e 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -2415,6 +2415,12 @@ static void print_rssi(int8_t rssi)
packet_print_rssi("RSSI", rssi);
}
+static void print_slot_125u(const char *label, uint16_t value)
+{
+ print_field("%s: %.3f msec (0x%4.4x)", label,
+ le16_to_cpu(value) * 0.125, le16_to_cpu(value));
+}
+
static void print_slot_625(const char *label, uint16_t value)
{
print_field("%s: %.3f msec (0x%4.4x)", label,
@@ -3341,6 +3347,8 @@ static const struct bitfield_data events_le_table[] = {
{ 50, "LE CS Test End Complete" },
{ 51, "LE Monitored Advertisers Report" },
{ 52, "LE Frame Space Update Complete" },
+ { 53, "LE UTP Received" },
+ { 54, "LE Connection Rate Change" },
{ }
};
@@ -9836,6 +9844,89 @@ static void le_fsu_cmd(uint16_t index, const void *data, uint8_t size)
print_fsu_types(cmd->types);
}
+static void le_conn_rate_cmd(uint16_t index, const void *data, uint8_t size)
+{
+ const struct bt_hci_cmd_le_conn_rate *cmd = data;
+
+ print_handle(cmd->handle);
+ print_slot_125u("Connection Interval Min", cmd->interval_min);
+ print_slot_125u("Connection Interval Max", cmd->interval_max);
+ print_field("Subrate Min: %u (0x%4.4x)",
+ le16_to_cpu(cmd->subrate_min),
+ le16_to_cpu(cmd->subrate_min));
+ print_field("Subrate Max: %u (0x%4.4x)",
+ le16_to_cpu(cmd->subrate_max),
+ le16_to_cpu(cmd->subrate_max));
+ print_field("Max Latency: %u (0x%4.4x)",
+ le16_to_cpu(cmd->max_latency),
+ le16_to_cpu(cmd->max_latency));
+ print_field("Continuation Number: %u (0x%4.4x)",
+ le16_to_cpu(cmd->cont_num),
+ le16_to_cpu(cmd->cont_num));
+ print_field("Supervision Timeout: %d ms (0x%4.4x)",
+ le16_to_cpu(cmd->supv_timeout) * 10,
+ le16_to_cpu(cmd->supv_timeout));
+ print_slot_125u("Minimum CE Length", cmd->min_ce_len);
+ print_slot_125u("Maximum CE Length", cmd->max_ce_len);
+}
+
+static void le_set_def_rate_cmd(uint16_t index, const void *data, uint8_t size)
+{
+ const struct bt_hci_cmd_le_set_def_rate *cmd = data;
+
+ print_slot_125u("Connection Interval Min", cmd->interval_min);
+ print_slot_125u("Connection Interval Max", cmd->interval_max);
+ print_field("Subrate Min: %u (0x%4.4x)",
+ le16_to_cpu(cmd->subrate_min),
+ le16_to_cpu(cmd->subrate_min));
+ print_field("Subrate Max: %u (0x%4.4x)",
+ le16_to_cpu(cmd->subrate_max),
+ le16_to_cpu(cmd->subrate_max));
+ print_field("Max Latency: %u (0x%4.4x)",
+ le16_to_cpu(cmd->max_latency),
+ le16_to_cpu(cmd->max_latency));
+ print_field("Continuation Number: %u (0x%4.4x)",
+ le16_to_cpu(cmd->cont_num),
+ le16_to_cpu(cmd->cont_num));
+ print_field("Supervision Timeout: %d ms (0x%4.4x)",
+ le16_to_cpu(cmd->supv_timeout) * 10,
+ le16_to_cpu(cmd->supv_timeout));
+ print_slot_125u("Minimum CE Length", cmd->min_ce_len);
+ print_slot_125u("Maximum CE Length", cmd->max_ce_len);
+}
+
+static void le_read_conn_interval_rsp(uint16_t index, const void *data,
+ uint8_t size)
+{
+ const struct bt_hci_rsp_le_read_conn_interval *rsp = data;
+ struct iovec iov;
+ uint8_t i;
+
+ print_status(rsp->status);
+ print_field("Number of Groups: %u", rsp->num_grps);
+
+ if (!rsp->num_grps)
+ return;
+
+ iov.iov_base = (void *)rsp->grps;
+ iov.iov_len = size - sizeof(*rsp);
+
+ for (i = 0; i < rsp->num_grps; i++) {
+ const struct bt_hci_le_conn_interval_group *grp;
+
+ grp = util_iov_pull(&iov, sizeof(*grp));
+ if (!grp) {
+ print_text(COLOR_ERROR, " invalid group");
+ break;
+ }
+
+ print_field("Group %u:", i);
+ print_slot_125u(" Interval Min", grp->min);
+ print_slot_125u(" Interval Max", grp->max);
+ print_slot_125u(" Interval Stride", grp->stride);
+ }
+}
+
struct opcode_data {
uint16_t opcode;
int bit;
@@ -10907,6 +10998,21 @@ static const struct opcode_data opcode_table[] = {
"LE Frame Space Update", le_fsu_cmd,
sizeof(struct bt_hci_cmd_le_fsu),
true, status_rsp, 1, true },
+ { BT_HCI_CMD_LE_CONN_RATE, BT_HCI_BIT_LE_CONN_RATE,
+ "LE Connection Rate Request", le_conn_rate_cmd,
+ sizeof(struct bt_hci_cmd_le_conn_rate),
+ true, status_rsp, 1, true },
+ { BT_HCI_CMD_LE_SET_DEF_RATE, BT_HCI_BIT_LE_SET_DEF_RATE,
+ "LE Set Default Rate Parameteres",
+ le_set_def_rate_cmd,
+ sizeof(struct bt_hci_cmd_le_set_def_rate),
+ true, status_rsp, 1, true },
+ { BT_HCI_CMD_LE_READ_CONN_INTERVAL,
+ BT_HCI_BIT_LE_READ_CONN_INTERVAL,
+ "LE Read Minimum Supported Connection Interval",
+ null_cmd, 0, true, le_read_conn_interval_rsp,
+ sizeof(struct bt_hci_rsp_le_read_conn_interval),
+ true },
{ }
};
@@ -13400,6 +13506,26 @@ static void le_fsu_evt(struct timeval *tv, uint16_t index,
print_fsu_types(evt->types);
}
+static void le_conn_rate_change_evt(struct timeval *tv, uint16_t index,
+ const void *data, uint8_t size)
+{
+ const struct bt_hci_evt_le_conn_rate_change *evt = data;
+
+ print_handle(evt->handle);
+ print_slot_125u("Connection Interval", le16_to_cpu(evt->interval));
+ print_field("Subrate Factor: %u (0x%4.4x)", le16_to_cpu(evt->subrate),
+ le16_to_cpu(evt->subrate));
+ print_field("Peripheral Latency: %u (0x%4.4x)",
+ le16_to_cpu(evt->latency),
+ le16_to_cpu(evt->latency));
+ print_field("Continuation Number: %u (0x%4.4x)",
+ le16_to_cpu(evt->cont_number),
+ le16_to_cpu(evt->cont_number));
+ print_field("Supervision Timeout: %u ms (0x%4.4X)",
+ le16_to_cpu(evt->supv_timeout),
+ le16_to_cpu(evt->supv_timeout));
+}
+
struct subevent_data {
uint8_t subevent;
const char *str;
@@ -13566,6 +13692,10 @@ static const struct subevent_data le_meta_event_table[] = {
{ BT_HCI_EVT_LE_FSU_COMPLETE,
"LE Frame Space Update Complete",
le_fsu_evt, sizeof(struct bt_hci_evt_le_fsu_complete) },
+ { BT_HCI_EVT_LE_CONN_RATE_CHANGE,
+ "LE Connection Rate Change",
+ le_conn_rate_change_evt,
+ sizeof(struct bt_hci_evt_le_conn_rate_change) },
{ }
};
--
2.53.0
next prev parent reply other threads:[~2026-05-04 21:13 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-04 21:13 [PATCH BlueZ v1 1/2] monitor: Add features bits defined in 6.2 Luiz Augusto von Dentz
2026-05-04 21:13 ` Luiz Augusto von Dentz [this message]
2026-05-04 22:42 ` [BlueZ,v1,1/2] " bluez.test.bot
2026-05-06 13:30 ` [PATCH BlueZ v1 1/2] " patchwork-bot+bluetooth
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=20260504211303.1081876-2-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