From 1b3269f76bb7db0333131afa761513ae21fe1508 Mon Sep 17 00:00:00 2001 From: evgeny Date: Mon, 19 Oct 2026 14:10:35 +0200 Subject: [PATCH] Require active subscription on radio acceptance and verify live BGP gating --- src/radio/radio_call.c | 8 +++++++- tests/test_radio.c | 18 ++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/radio/radio_call.c b/src/radio/radio_call.c index e997a892..91c3701a 100644 --- a/src/radio/radio_call.c +++ b/src/radio/radio_call.c @@ -3,6 +3,7 @@ * всеми deadline; callback не хранит указателей на освобождаемые сессии. */ #include #include "radio_call.h" +#include "radio.h" #include "../utun_instance.h" #include "../chat/chat_event.h" #include "../chat/member_sync.h" @@ -290,7 +291,12 @@ void radio_call_execute(const struct radio_call_request* req) { } if (get_time_tb() - s->started >= RADIO_CALL_RING_TB) { rc_finish(ctx, s, RADIO_CALL_NO_ANSWER, 1); return; } uint8_t reason = 0; - if (req->action == RADIO_CALL_ACCEPT && s->incoming) reason = RADIO_CALL_ACCEPTED; + if (req->action == RADIO_CALL_ACCEPT && s->incoming) { + reason = radio_is_active(req->inst, s->group) ? RADIO_CALL_ACCEPTED : RADIO_CALL_AUDIO_ERROR; + if (reason == RADIO_CALL_AUDIO_ERROR) DEBUG_ERROR(DEBUG_CATEGORY_RADIO, + "radio call accept without active channel subscription id=%016llx group=%016llx", + (unsigned long long)s->id, (unsigned long long)s->group); + } else if (req->action == RADIO_CALL_DECLINE && s->incoming) reason = RADIO_CALL_DECLINED; else if (req->action == RADIO_CALL_CANCEL) reason = RADIO_CALL_CANCELLED; else if (req->action == RADIO_CALL_FAIL) reason = RADIO_CALL_AUDIO_ERROR; diff --git a/tests/test_radio.c b/tests/test_radio.c index d86bc636..49a5fbad 100644 --- a/tests/test_radio.c +++ b/tests/test_radio.c @@ -109,7 +109,7 @@ static int g_member_radio[3][3]; static int g_member_lists[3]; static int g_member_event_bad; static int g_talk_on[3], g_talk_starts[3], g_talk_stops[3]; -static struct { int state, reason, finished, incoming; uint64_t finished_tb; } g_calls[6][3]; +static struct { int state, reason, finished, incoming; uint64_t finished_tb; } g_calls[8][3]; static int g_call_ready, g_drop_result, g_drop_ack; static etcp_recv_fn g_call_recv[3]; @@ -140,7 +140,7 @@ static void member_event(struct UTUN_INSTANCE* inst, int type, const uint8_t* da memcpy(&id, data, 8); memcpy(&group, data + 8, 8); memcpy(&peer, data + 16, 8); int idx = -1; for (int i = 0; i < 3; ++i) if (inst->node_id == g_sh.nid[i]) idx = i; - if (idx < 0 || id < 100 || id > 105 || group != strtoull(CH_ID, NULL, 10)) { g_member_event_bad = 1; return; } + if (idx < 0 || id < 100 || id > 107 || group != strtoull(CH_ID, NULL, 10)) { g_member_event_bad = 1; return; } g_calls[id - 100][idx].state = data[24]; g_calls[id - 100][idx].reason = data[25]; if (data[24] == RADIO_CALL_INCOMING) { ++g_calls[id - 100][idx].incoming; @@ -456,6 +456,19 @@ static void rad_tick(void* arg) { case 0: { uint8_t key[32]; if (member_sync_verified_ed25519(A, CH_ID, nc, key) || member_sync_verified_ed25519(C, CH_ID, na, key)) break; + struct TOPO_GROUP* cg = topo_groups_find(C->topo_groups, gid); + struct ETCP_CONN* path = topo_group_find_conn_for_node(cg, na); + if (!path) break; + int saved_up = path->links_up; + path->links_up = 0; + radio_action(C, 106, RADIO_CALL_START, na); + path->links_up = saved_up; + radio_action(C, 107, RADIO_CALL_START, nc); + if (g_calls[6][IDX_C].reason != RADIO_CALL_UNAVAILABLE || g_calls[7][IDX_C].reason != RADIO_CALL_UNAVAILABLE || + radio_call_busy(C)) { + DEBUG_ERROR(DEBUG_CATEGORY_RADIO, "test BGP without live path/self-call must fail before signaling"); + t->result = 2; uasync_stop(t->ua); return; + } for (int i = 0; i < 3; ++i) { g_call_recv[i] = t->inst[i]->router_bindings.callbacks[ETCP_RT_ID_RADIO_CALL]; t->inst[i]->router_bindings.callbacks[ETCP_RT_ID_RADIO_CALL] = call_packet_loss; @@ -479,6 +492,7 @@ static void rad_tick(void* arg) { break; case 2: if (g_calls[1][IDX_A].state == RADIO_CALL_RINGING) { + radio_set_active(C, gid, 1); radio_action(C, 101, RADIO_CALL_ACCEPT, 0); ++t->call_step; } break;