@@ -290,6 +290,20 @@ static void index_removed_callback(uint16_t index, uint16_t length,
tester_post_teardown_complete();
}
+#define MAX_COREDUMP_LINE_LEN 40
+
+struct devcoredump_test_data {
+ enum devcoredump_state {
+ HCI_DEVCOREDUMP_IDLE,
+ HCI_DEVCOREDUMP_ACTIVE,
+ HCI_DEVCOREDUMP_DONE,
+ HCI_DEVCOREDUMP_ABORT,
+ HCI_DEVCOREDUMP_TIMEOUT,
+ } state;
+ unsigned int timeout;
+ char data[MAX_COREDUMP_LINE_LEN];
+};
+
struct hci_cmd_data {
uint16_t opcode;
uint8_t len;
@@ -362,6 +376,8 @@ struct generic_data {
bool set_adv;
const uint8_t *adv_data;
uint8_t adv_data_len;
+ const struct devcoredump_test_data *dump_data;
+ const char (*expect_dump_data)[MAX_COREDUMP_LINE_LEN];
};
static const uint8_t set_exp_feat_param_debug[] = {
@@ -12511,6 +12527,139 @@ static void test_suspend_resume_success_10(const void *test_data)
tester_wait(2, trigger_force_resume, NULL);
}
+#define MAX_COREDUMP_BUF_LEN 512
+
+static const struct devcoredump_test_data data_complete_dump = {
+ .state = HCI_DEVCOREDUMP_DONE,
+ .data = "test data",
+};
+
+static const char expected_complete_dump[][MAX_COREDUMP_LINE_LEN] = {
+ "Bluetooth devcoredump",
+ "State: 2",
+ "Controller Name: vhci_ctrl",
+ "Firmware Version: vhci_fw",
+ "Driver: vhci_drv",
+ "Vendor: vhci",
+ "--- Start dump ---",
+ "", /* end of header data */
+};
+
+static const struct generic_data dump_complete = {
+ .dump_data = &data_complete_dump,
+ .expect_dump_data = expected_complete_dump,
+};
+
+static const struct devcoredump_test_data data_abort_dump = {
+ .state = HCI_DEVCOREDUMP_ABORT,
+ .data = "test data",
+};
+
+static const char expected_abort_dump[][MAX_COREDUMP_LINE_LEN] = {
+ "Bluetooth devcoredump",
+ "State: 3",
+ "Controller Name: vhci_ctrl",
+ "Firmware Version: vhci_fw",
+ "Driver: vhci_drv",
+ "Vendor: vhci",
+ "--- Start dump ---",
+ "", /* end of header data */
+};
+
+static const struct generic_data dump_abort = {
+ .dump_data = &data_abort_dump,
+ .expect_dump_data = expected_abort_dump,
+};
+
+static const struct devcoredump_test_data data_timeout_dump = {
+ .state = HCI_DEVCOREDUMP_TIMEOUT,
+ .timeout = 1,
+ .data = "test data",
+};
+
+static const char expected_timeout_dump[][MAX_COREDUMP_LINE_LEN] = {
+ "Bluetooth devcoredump",
+ "State: 4",
+ "Controller Name: vhci_ctrl",
+ "Firmware Version: vhci_fw",
+ "Driver: vhci_drv",
+ "Vendor: vhci",
+ "--- Start dump ---",
+ "", /* end of header data */
+};
+
+static const struct generic_data dump_timeout = {
+ .dump_data = &data_timeout_dump,
+ .expect_dump_data = expected_timeout_dump,
+};
+
+static void verify_devcd(void *user_data)
+{
+ struct test_data *data = tester_get_data();
+ const struct generic_data *test = data->test_data;
+ struct vhci *vhci = hciemu_get_vhci(data->hciemu);
+ char buf[MAX_COREDUMP_BUF_LEN] = {0};
+ char delim[] = "\n";
+ char *line;
+ char *saveptr;
+ int i = 0;
+
+ /* Read the generated devcoredump file */
+ if (vhci_read_devcd(vhci, buf, sizeof(buf)) <= 0) {
+ tester_warn("Unable to read devcoredump");
+ tester_test_failed();
+ return;
+ }
+
+ /* Verify if all devcoredump header fields are present */
+ line = strtok_r(buf, delim, &saveptr);
+ while (strlen(test->expect_dump_data[i])) {
+ if (!line || strcmp(line, test->expect_dump_data[i])) {
+ tester_warn("Incorrect coredump data: %s (expected %s)",
+ line, test->expect_dump_data[i]);
+ tester_test_failed();
+ return;
+ }
+
+ if (!strcmp(strtok(line, ":"), "State")) {
+ /* After updating the devcoredump state, the HCI
+ * devcoredump API adds a `\0` at the end. Skip it
+ * before reading the next line.
+ */
+ saveptr++;
+ }
+
+ line = strtok_r(NULL, delim, &saveptr);
+ i++;
+ }
+
+ /* Verify the devcoredump data */
+ if (!line || strcmp(line, test->dump_data->data)) {
+ tester_warn("Incorrect coredump data: %s (expected %s)", line,
+ test->dump_data->data);
+ tester_test_failed();
+ return;
+ }
+
+ tester_test_passed();
+}
+
+static void test_hci_devcd(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ const struct generic_data *test = data->test_data;
+ struct vhci *vhci = hciemu_get_vhci(data->hciemu);
+
+ /* Triggers the devcoredump */
+ if (vhci_force_devcd(vhci, test->dump_data, sizeof(*test->dump_data))) {
+ tester_warn("Unable to set force_devcoredump");
+ tester_test_failed();
+ return;
+ }
+
+ tester_wait(test->dump_data->timeout + 1, verify_devcd, NULL);
+}
+
int main(int argc, char *argv[])
{
tester_init(&argc, &argv);
@@ -14651,5 +14800,29 @@ int main(int argc, char *argv[])
setup_ll_privacy_add_device,
test_command_generic);
+ /* HCI Devcoredump
+ * Setup : Power on
+ * Run: Trigger devcoredump via force_devcoredump
+ * Expect: Devcoredump is generated with correct data
+ */
+ test_bredrle("HCI Devcoredump - Dump Complete", &dump_complete, NULL,
+ test_hci_devcd);
+
+ /* HCI Devcoredump
+ * Setup : Power on
+ * Run: Trigger devcoredump via force_devcoredump
+ * Expect: Devcoredump is generated with correct data
+ */
+ test_bredrle("HCI Devcoredump - Dump Abort", &dump_abort, NULL,
+ test_hci_devcd);
+
+ /* HCI Devcoredump
+ * Setup : Power on
+ * Run: Trigger devcoredump via force_devcoredump
+ * Expect: Devcoredump is generated with correct data
+ */
+ test_bredrle_full("HCI Devcoredump - Dump Timeout", &dump_timeout, NULL,
+ test_hci_devcd, 3);
+
return tester_run();
}