From 563203056df2a028b9db47ce3888e1a5f9d3e570 Mon Sep 17 00:00:00 2001 From: evgeny Date: Fri, 30 Oct 2026 23:54:27 +0100 Subject: [PATCH] Cover private address rotation and unrelated connected peers --- lib/ble/ble_bluez.c | 1 + lib/ble/tests/test_ble_bluez.c | 44 ++++++++++++++++++++++++++++++---- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/lib/ble/ble_bluez.c b/lib/ble/ble_bluez.c index 6a62fe2ee..3c51349ee 100644 --- a/lib/ble/ble_bluez.c +++ b/lib/ble/ble_bluez.c @@ -2,6 +2,7 @@ * Серверные DATA notifications и INVITE/ACK indications адресуются через AcquireNotify fd каждого клиента. * DATA завершается после send(fd); INVITE/ACK ждут байт 1 от BlueZ (ATT completion). */ #include "ble_backend.h" +#include "ble_identity.h" #include "../u_async.h" #include "../mem.h" #include "../debug_config.h" diff --git a/lib/ble/tests/test_ble_bluez.c b/lib/ble/tests/test_ble_bluez.c index 7b6662e9c..efc352b6f 100644 --- a/lib/ble/tests/test_ble_bluez.c +++ b/lib/ble/tests/test_ble_bluez.c @@ -1,5 +1,6 @@ /* Private D-Bus + настоящий backend: DATA/ACK без ATT ACK, адресные INVITE indications, два клиента. */ #include "ble_backend.h" +#include "ble_identity.h" #include "u_async.h" #include "mem.h" #include "debug_config.h" @@ -15,6 +16,7 @@ #define ROOT "/org/vibechat/ble" #define ADAPTER "/org/bluez/hci0" #define REMOTE ADAPTER "/dev_C" +#define ROTATED ADAPTER "/dev_D" static struct UASYNC* ua; static sd_bus* bus; static struct ble_transport* transport; @@ -25,6 +27,8 @@ static unsigned commands, requests, ack_requests, ack_values; static int ack_fds[2] = {-1, -1}; static int remote_resolved, remote_connected = 1; static unsigned remote_connects; +static unsigned rotated_connects; +static uint64_t remote_identity; struct reply { sd_bus_slot* slot; int done, fd, failed; }; static void poll_all(void) { for (int i = 0; i < 500; i++) { @@ -104,13 +108,31 @@ static int remote_write(sd_bus_message* m, void* arg, sd_bus_error* e) { } static int remote_state(sd_bus* b, const char* path, const char* i, const char* name, sd_bus_message* m, void* arg, sd_bus_error* e) { - (void)b; (void)path; (void)i; (void)arg; (void)e; - if (!strcmp(name, "ManufacturerData")) return sd_bus_message_append(m, "a{qv}", 1, 0xffff, "ay", 3, 'a', 'b', 'c'); + (void)b; (void)i; (void)arg; (void)e; + int rotated = !strcmp(path, ROTATED); + if (!strcmp(name, "ManufacturerData")) { + if (!remote_identity) return sd_bus_message_append(m, "a{qv}", 1, 0xffff, "ay", 3, 'a', 'b', 'c'); + uint8_t bytes[BLE_BROADCAST_MAX]; int len = ble_identity_encode(bytes, rotated ? 3 : remote_identity, ""); + int r = sd_bus_message_open_container(m, 'a', "{qv}"); + if (r >= 0) r = sd_bus_message_open_container(m, 'e', "qv"); + if (r >= 0) r = sd_bus_message_append(m, "q", 0xffff); + if (r >= 0) r = sd_bus_message_open_container(m, 'v', "ay"); + if (r >= 0) r = sd_bus_message_append_array(m, 'y', bytes, len); + if (r >= 0) r = sd_bus_message_close_container(m); + if (r >= 0) r = sd_bus_message_close_container(m); + if (r >= 0) r = sd_bus_message_close_container(m); + return r; + } + if (rotated) return sd_bus_message_append(m, "b", 0); return sd_bus_message_append(m, "b", !strcmp(name, "Connected") ? remote_connected : remote_resolved); } /* Повторный Connect существующего ACL недопустим: BlueZ может начать другой bearer (BR/EDR). */ static int remote_connect(sd_bus_message* m, void* arg, sd_bus_error* e) { - (void)arg; (void)e; CHECK(!remote_connected); + (void)arg; (void)e; + if (!strcmp(sd_bus_message_get_path(m), ROTATED)) { + rotated_connects++; return sd_bus_reply_method_errorf(m, "org.bluez.Error.Failed", "ACL already exists at old address"); + } + CHECK(!remote_connected); remote_connects++; remote_connected = 1; CHECK(sd_bus_emit_properties_changed(bus, REMOTE, "org.bluez.Device1", "Connected", NULL) >= 0); return sd_bus_reply_method_return(m, ""); @@ -187,7 +209,7 @@ int main(void) { debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN); size_t before = u_get_allocated_count(); CHECK(sd_bus_open_user(&bus) >= 0); CHECK(sd_bus_request_name(bus, "org.bluez", 0) >= 0); - sd_bus_slot *manager = NULL, *adapter = NULL, *gatt = NULL, *adv = NULL, *remote[5] = {0}; + sd_bus_slot *manager = NULL, *adapter = NULL, *gatt = NULL, *adv = NULL, *remote[6] = {0}; CHECK(sd_bus_add_object_manager(bus, &manager, "/") >= 0); CHECK(sd_bus_add_object_vtable(bus, &adapter, ADAPTER, "org.bluez.Adapter1", adapter_vtable, NULL) >= 0); CHECK(sd_bus_add_object_vtable(bus, &gatt, ADAPTER, "org.bluez.GattManager1", gatt_vtable, NULL) >= 0); @@ -298,9 +320,21 @@ int main(void) { ble_disconnect(transport, links[3]); poll_all(); CHECK(ble_connect(transport, &ep, 3)); poll_all(); CHECK(remote_connects == 1 && ready_links == 6 && commands == 4); + /* Новый RPA того же узла не требует второго ACL; чужой ID на старом ACL не подходит. */ + ble_disconnect(transport, links[3]); poll_all(); remote_resolved = 0; remote_identity = 2; + CHECK(sd_bus_add_object_vtable(bus, &remote[5], ROTATED, "org.bluez.Device1", device_vtable, NULL) >= 0); + struct ble_endpoint rotated = {ROTATED}; + CHECK(ble_connect(transport, &rotated, 3)); poll_all(); + CHECK(rotated_connects == 1 && ready_links == 6 && commands == 4); + remote_identity = 3; + CHECK(ble_connect(transport, &rotated, 3)); poll_all(); + CHECK(rotated_connects == 1 && remote_connects == 1 && ready_links == 6 && commands == 4); + remote_resolved = 1; + CHECK(sd_bus_emit_properties_changed(bus, REMOTE, "org.bluez.Device1", "ServicesResolved", NULL) >= 0); + poll_all(); CHECK(ready_links == 7 && commands == 5 && rotated_connects == 1 && remote_connects == 1); ble_stop(transport); power = ble_get_advertising_power(transport); CHECK(power.max_dbm == 127 && power.can_set == -1); ble_destroy(transport); uasync_destroy(ua, 0); - for (int i = 0; i < 5; i++) sd_bus_slot_unref(remote[i]); + for (int i = 0; i < 6; i++) sd_bus_slot_unref(remote[i]); sd_bus_slot_unref(manager); sd_bus_slot_unref(adapter); sd_bus_slot_unref(gatt); sd_bus_slot_unref(adv); sd_bus_close_unref(bus); CHECK(u_get_allocated_count() == before); puts("BlueZ private-bus tests PASS (existing/new ACL, DATA/ACK commands, INVITE indications, two clients, teardown)");