first draft for ACMP/ timeout handling, and communication between SRP/ADP and the ACMP state machine

This commit is contained in:
hackerman-kl 2026-01-19 09:39:49 +01:00 committed by Wim Taymans
parent ad543e37f5
commit 4856f85de2
18 changed files with 2970 additions and 285 deletions

View file

@ -13,7 +13,6 @@
#include "internal.h"
#include "stream.h"
#include "aecp-aem-descriptors.h"
#include "aecp-aem-state.h"
#include "acmp-cmds-resps/acmp-common.h"
#include "acmp-cmds-resps/acmp-legacy-avb.h"
@ -27,16 +26,35 @@ static int handle_ignore(struct acmp *acmp, uint64_t now, const void *m, int len
}
static const char * const acmp_cmd_names[] = {
[AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND] = "connect-tx-command",
[AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE] = "connect-tx-response",
/** Milan V1.2 Section 5.5.2.2 (PDU) */
[AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND] =
"connect-tx-command/probe-tx-command",
/** Milan V1.2 Section 5.5.2.2 (PDU) */
[AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE] =
"connect-tx-response/probe-tx-response",
[AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND] = "disconnect-tx-command",
[AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE] = "disconnect-tx-response",
[AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_COMMAND] = "get-tx-state-command",
[AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE] = "get-tx-state-response",
[AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_COMMAND] = "connect-rx-command",
[AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE] = "connect-rx-response",
[AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_COMMAND] = "disconnect-rx-command",
[AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE] = "disconnect-rx-response",
/** Milan V1.2 Section 5.5.2.2 (PDU) */
[AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_COMMAND] =
"connect-rx-command/bind-rx-command",
/** Milan V1.2 Section 5.5.2.2 (PDU) */
[AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE] =
"connect-rx-response/bind-rx-response",
/** Milan V1.2 Section 5.5.2.2 (PDU) */
[AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_COMMAND] =
"disconnect-rx-command/unbind-rx-command",
/** Milan V1.2 Section 5.5.2.2 (PDU) */
[AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE] =
"disconnect-rx-response/unbind-rx-response",
[AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_COMMAND] = "get-rx-state-command",
[AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_RESPONSE] = "get-rx-state-response",
[AVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_COMMAND] = "get-tx-connection-command",
@ -51,15 +69,32 @@ struct acmp_cmds {
[mtype] = { .handle = handler }
static const struct acmp_cmds acmp_cmds_legacy_avb[] = {
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND, handle_connect_tx_command_legacy_avb),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE, handle_connect_tx_response_legacy_avb),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND, handle_disconnect_tx_command_legacy_avb),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE, handle_disconnect_tx_response_legacy_avb),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND,
handle_connect_tx_command_legacy_avb),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE,
handle_connect_tx_response_legacy_avb),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND,
handle_disconnect_tx_command_legacy_avb),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE,
handle_disconnect_tx_response_legacy_avb),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_COMMAND, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE, handle_ignore),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_COMMAND, handle_connect_rx_command_legacy_avb),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE, handle_ignore),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_COMMAND, handle_disconnect_rx_command_legacy_avb),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE,
handle_ignore),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_COMMAND,
handle_connect_rx_command_legacy_avb),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE,
handle_ignore),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_COMMAND,
handle_disconnect_rx_command_legacy_avb),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_COMMAND, handle_ignore),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_RESPONSE, handle_ignore),
@ -68,19 +103,37 @@ static const struct acmp_cmds acmp_cmds_legacy_avb[] = {
};
static const struct acmp_cmds acmp_cmds_milan_v12[] = {
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_COMMAND, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_COMMAND, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND,
handle_probe_tx_command_milan_v12),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE,
handle_probe_tx_response_milan_v12),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_COMMAND,
handle_bind_rx_command_milan_v12),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_COMMAND,
handle_unbind_rx_command_milan_v12),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND,
handle_unbind_rx_command_milan_v12),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE,
handle_ignore),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_COMMAND,
handle_get_rx_state_command_milan_v12),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_COMMAND, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_COMMAND, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_RESPONSE, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_COMMAND, NULL),
/** Milan V1.2 Section 5.5.2.2 (PDU) , Milan does not requires them */
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_COMMAND, handle_ignore),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE, handle_ignore),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_RESPONSE, NULL),
AVB_ACMP_CMD_HANDLER(AVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_RESPONSE, NULL),
};
@ -115,7 +168,7 @@ static int acmp_message(void *data, uint64_t now, const void *message, int len)
return 0;
if (memcmp(h->dest, mac, 6) != 0 &&
memcmp(h->dest, server->mac_addr, 6) != 0)
memcmp(h->dest, server->mac_addr, 6) != 0)
return 0;
if (AVB_PACKET_GET_SUBTYPE(&p->hdr) != AVB_SUBTYPE_ACMP)
@ -126,11 +179,11 @@ static int acmp_message(void *data, uint64_t now, const void *message, int len)
pw_log_info("got ACMP message %s", acmp_cmd_names[mtype]);
if (mtype < 0 || (size_t)mtype >= acmp_cmds_modes[server->avb_mode].count) {
return reply_not_supported(acmp, mtype | 1, message, len);
return acmp_reply_not_supported(acmp, mtype | 1, message, len);
}
if (acmp_cmds_modes[server->avb_mode].cmds[mtype].handle == NULL)
return reply_not_supported(acmp, mtype | 1, message, len);
return acmp_reply_not_supported(acmp, mtype | 1, message, len);
return acmp_cmds_modes[server->avb_mode].cmds[mtype].handle(acmp, now, message, len);
}
@ -138,41 +191,27 @@ static int acmp_message(void *data, uint64_t now, const void *message, int len)
static void acmp_destroy(void *data)
{
struct acmp *acmp = data;
spa_hook_remove(&acmp->server_listener);
pending_destroy(acmp);
free(acmp);
}
static void check_timeout(struct acmp *acmp, uint64_t now, uint16_t type)
{
struct pending *p, *t;
spa_list_for_each_safe(p, t, &acmp->pending[type], link) {
if (p->last_time + p->timeout > now)
continue;
if (p->retry == 0) {
pw_log_info("%p: pending timeout, retry", p);
retry_pending(acmp, now, p);
} else {
pw_log_info("%p: pending timeout, fail", p);
pending_free(acmp, p);
}
switch (acmp->server->avb_mode) {
case AVB_MODE_MILAN_V12:
acmp_destroy_milan_v12(acmp);
break;
case AVB_MODE_LEGACY:
acmp_server_destroy_legacy_avb(acmp);
break;
default:
pw_log_warn("Unknown avb_mode");
break;
}
spa_hook_remove(&acmp->server_listener);
}
static void acmp_periodic(void *data, uint64_t now)
{
struct acmp *acmp = data;
check_timeout(acmp, now, PENDING_TALKER);
check_timeout(acmp, now, PENDING_LISTENER);
check_timeout(acmp, now, PENDING_CONTROLLER);
}
static int do_help(struct acmp *acmp, const char *args, FILE *out)
{
fprintf(out, "{ \"type\": \"help\","
"\"text\": \""
"/adp/help: this help \\n"
" /acmp/help: this help \\n"
"\" }");
return 0;
}
@ -189,12 +228,108 @@ static int acmp_command(void *data, uint64_t now, const char *command, const cha
if (spa_streq(command, "help"))
res = do_help(acmp, args, out);
else if (spa_streq(command, "milan_v12"))
res = handle_acmp_cli_cmd_milan_v12(acmp, args, out);
else
res = -ENOTSUP;
return res;
}
static void acmp_periodic(void *data, uint64_t now)
{
struct acmp *acmp = (struct acmp*)data;
switch (acmp->server->avb_mode) {
case AVB_MODE_MILAN_V12:
acmp_periodic_milan_v12(acmp, now);
break;
case AVB_MODE_LEGACY:
acmp_periodic_avb_legacy(acmp, now);
break;
default:
pw_log_warn("Unknown avb_mode");
break;
}
}
int handle_evt_tk_discovered(struct avb_acmp *avb_acmp, uint64_t entity)
{
struct acmp *acmp = (struct acmp*)avb_acmp;
switch (acmp->server->avb_mode) {
case AVB_MODE_MILAN_V12:
return handle_evt_tk_discovered_milan_v12(acmp, entity);
break;
case AVB_MODE_LEGACY:
pw_log_warn("not implemented for legacy avb");
break;
default:
pw_log_warn("Unknown avb_mode");
break;
}
return -1;
}
int handle_evt_tk_departed(struct avb_acmp *avb_acmp, uint64_t entity)
{
struct acmp *acmp = (struct acmp*)avb_acmp;
switch (acmp->server->avb_mode) {
case AVB_MODE_MILAN_V12:
return handle_evt_tk_departed_milan_v12(acmp, entity);
break;
case AVB_MODE_LEGACY:
pw_log_warn("not implemented for legacy avb");
break;
default:
pw_log_warn("Unknown avb_mode");
break;
}
return 0;
}
int handle_evt_tk_registered(struct avb_acmp *avb_acmp, uint64_t entity)
{
struct acmp *acmp = (struct acmp*)avb_acmp;
switch (acmp->server->avb_mode) {
case AVB_MODE_MILAN_V12:
return handle_evt_tk_registered_milan_v12(acmp, entity);
break;
case AVB_MODE_LEGACY:
pw_log_warn("not implemented for legacy avb");
break;
default:
pw_log_warn("Unknown avb_mode");
break;
}
return -1;
}
int handle_evt_tk_unregistered(struct avb_acmp *avb_acmp, uint64_t entity)
{
struct acmp *acmp = (struct acmp*)avb_acmp;
switch (acmp->server->avb_mode) {
case AVB_MODE_MILAN_V12:
return handle_evt_tk_unregistered_milan_v12(acmp, entity);
break;
case AVB_MODE_LEGACY:
pw_log_warn("not implemented for legacy avb");
break;
default:
pw_log_warn("Unknown avb_mode");
break;
}
return -1;
}
static const struct server_events server_events = {
AVB_VERSION_SERVER_EVENTS,
.destroy = acmp_destroy,
@ -203,19 +338,81 @@ static const struct server_events server_events = {
.command = acmp_command
};
int acmp_init_listener_stream_output(struct avb_acmp *avb_acmp,
struct aecp_aem_stream_output_state *stream_st)
{
int rc = 0;
pw_log_warn("Not implemented");
#if 0
switch (acmp->server->avb_mode) {
case AVB_MODE_MILAN_V12:
rc = acmp_init_talker_stream_milan_v12(acmp, stream_st);
break;
case AVB_MODE_LEGACY:
default:
break;
}
#endif
return rc;
}
int acmp_init_listener_stream_input(struct avb_acmp *avb_acmp,
struct aecp_aem_stream_input_state *stream_st)
{
int rc = 0;
pw_log_warn("Not implemented");
#if 0
switch (acmp->server->avb_mode) {
case AVB_MODE_MILAN_V12:
break;
case AVB_MODE_LEGACY:
default:
break;
}
#endif
return rc;
}
int acmp_fini_stream(struct acmp *acmp, struct stream *stream)
{
int rc = 0;
#if 0
switch (acmp->server->avb_mode) {
case AVB_MODE_MILAN_V12:
rc = acmp_fini_stream_milan_v12(acmp, stream);
break;
case AVB_MODE_LEGACY:
default:
break;
}
#endif
return rc;
}
struct avb_acmp *avb_acmp_register(struct server *server)
{
struct acmp *acmp;
acmp = calloc(1, sizeof(*acmp));
switch (server->avb_mode) {
case AVB_MODE_MILAN_V12:
acmp = acmp_server_init_milan_v12();
break;
case AVB_MODE_LEGACY:
acmp = acmp_server_init_legacy_avb();
break;
default:
acmp = NULL;
break;
}
if (acmp == NULL)
return NULL;
acmp->server = server;
spa_list_init(&acmp->pending[PENDING_TALKER]);
spa_list_init(&acmp->pending[PENDING_LISTENER]);
spa_list_init(&acmp->pending[PENDING_CONTROLLER]);
avdecc_server_add_listener(server, &acmp->server_listener, &server_events, acmp);
return (struct avb_acmp*)acmp;