milan-avb: move teh descriptor FAM at the end of the structure to avoid overflow

This commit is contained in:
hackerman-kl 2026-04-26 13:03:10 +02:00 committed by Wim Taymans
parent 4d33f57325
commit 0bf4864d84
14 changed files with 126 additions and 204 deletions

View file

@ -7,121 +7,63 @@
#include "aecp-aem-state.h"
#include "utils.h"
/**
* \brief The goal of this modules is to create a an entity and
* attache the necessary status or resources to it so they
* do no have to be seperated and referenced somewhere else.
*
* In a sense, it encapsulates the descriptor, and the states
* information that will be altered either by a aecp/acmp commands
* or internal state changes reflected into the counters.
*/
/** The callback type used for the different entity descriptor */
typedef struct descriptor *(*es_builder_cb_t) (struct server *server, uint16_t type,
uint16_t index, size_t size, void *ptr);
uint16_t index, size_t size, const void *ptr);
/** Structure holding all necessary cb
* \todo for the future of compatibility between milan's version
* and plain AVB, add the right callback, that would reduce
* code complexity and increase reusability.
* As well as having multiple entity model defined using different
* entity on the same machine
*/
struct es_builder_st {
es_builder_cb_t build_descriptor_cb;
};
/*
* \brief The Entity keeps track of multiple things, the locks the current
* configuration use for instance. That tragets the Milan V1.2 mode only
*/
static struct descriptor *es_builder_desc_entity_milan_v12(struct server *server,
uint16_t type, uint16_t index, size_t size, void *ptr)
uint16_t type, uint16_t index, size_t size, const void *ptr)
{
struct aecp_aem_entity_milan_state entity_state = {0};
struct descriptor *desc;
struct aecp_aem_entity_state *state =
(struct aecp_aem_entity_state *) &entity_state;
memcpy(&state->desc, ptr, size);
desc = server_add_descriptor(server, type, index, sizeof(entity_state),
&entity_state);
if (!desc) {
pw_log_error("Error during allocation\n");
spa_assert(0);
}
return desc;
return server_add_descriptor(server, type, index,
sizeof(struct aecp_aem_entity_milan_state), size, ptr);
}
/**
* \brief A generic function to avoid code duplicate for the streams */
static struct descriptor *es_buidler_desc_stream_general_prepare(struct server *server,
uint16_t type, uint16_t index, size_t size, void *ptr)
uint16_t type, uint16_t index, size_t size, const void *ptr)
{
struct descriptor *desc;
struct stream *stream;
enum spa_direction direction;
switch (type) {
case AVB_AEM_DESC_STREAM_INPUT:
struct aecp_aem_stream_input_state *pstream_input;
/* Milan v1.2 ACMP code casts the descriptor pointer to
* struct aecp_aem_stream_input_state_milan_v12 * and reads
* acmp_sta, which sits *after* the bare stream input state.
* Allocate the wrapper size so that read/write of acmp_sta is
* within the descriptor buffer. The bare struct is the prefix
* of the wrapper, so existing direct-access paths remain valid. */
struct aecp_aem_stream_input_state_milan_v12 stream_input_w = { 0 };
struct aecp_aem_stream_input_state *stream_input = &stream_input_w.stream_in_sta;
if (type == AVB_AEM_DESC_STREAM_INPUT) {
struct aecp_aem_stream_input_state_milan_v12 *w;
memcpy(&stream_input->desc, ptr, size);
desc = server_add_descriptor(server, type, index,
sizeof(*w), size, ptr);
if (!desc) {
pw_log_error("Allocation failed\n");
return NULL;
}
w = desc->ptr;
/* Milan v1.2 Section 5.3.8.7: started/stopped state defaults to started. */
stream_input->started = true;
desc = server_add_descriptor(server, type, index,
sizeof(stream_input_w), &stream_input_w);
if (!desc) {
pw_log_error("Allocation failed\n");
return NULL;
}
pstream_input = desc->ptr;
stream = &pstream_input->common.stream;
w->stream_in_sta.started = true;
stream = &w->stream_in_sta.common.stream;
direction = SPA_DIRECTION_INPUT;
} else if (type == AVB_AEM_DESC_STREAM_OUTPUT) {
struct aecp_aem_stream_output_state_milan_v12 *w;
break;
case AVB_AEM_DESC_STREAM_OUTPUT:
struct aecp_aem_stream_output_state *pstream_output;
struct aecp_aem_stream_output_state_milan_v12 stream_output_w = { 0 };
struct aecp_aem_stream_output_state *stream_output = &stream_output_w.stream_out_sta;
memcpy(&stream_output->desc, ptr, size);
/* Milan v1.2 Section 5.3.7.6: default presentation time offset is 2 ms. */
stream_output->presentation_time_offset_ns = 2000000;
desc = server_add_descriptor(server, type, index,
sizeof(stream_output_w), &stream_output_w);
sizeof(*w), size, ptr);
if (!desc) {
pw_log_error("Allocation failed\n");
return NULL;
}
pstream_output = desc->ptr;
stream = &pstream_output->common.stream;
w = desc->ptr;
/* Milan v1.2 Section 5.3.7.6: default presentation time offset is 2 ms. */
w->stream_out_sta.presentation_time_offset_ns = 2000000;
stream = &w->stream_out_sta.common.stream;
direction = SPA_DIRECTION_OUTPUT;
break;
default:
} else {
pw_log_error("Only STREAM_INPUT and STREAM_OUTPUT\n");
return NULL;
}
/**
* In this place the stream register interanlly SRP / MVRP state machines
*/
if (!server_create_stream(server, stream, direction, index)) {
pw_log_error("Could not create/initialize a stream");
return NULL;
@ -131,16 +73,13 @@ static struct descriptor *es_buidler_desc_stream_general_prepare(struct server *
}
static struct descriptor *es_buidler_desc_avb_interface(struct server *server,
uint16_t type, uint16_t index, size_t size, void *ptr)
uint16_t type, uint16_t index, size_t size, const void *ptr)
{
struct aecp_aem_avb_interface_state if_state = {0};
struct aecp_aem_avb_interface_state *if_ptr;
struct descriptor *desc;
memcpy(&if_state.desc, ptr, size);
desc = server_add_descriptor(server, type, index, sizeof(if_state),
&if_state);
desc = server_add_descriptor(server, type, index,
sizeof(*if_ptr), size, ptr);
if (!desc) {
pw_log_error("Error durring allocation\n");
spa_assert(0);
@ -171,12 +110,10 @@ static struct descriptor *es_buidler_desc_avb_interface(struct server *server,
return desc;
}
// Assign a ID to an specific builder
#define HELPER_ES_BUIDLER(type, callback) \
[type] = { .build_descriptor_cb = callback }
[type] = { .build_descriptor_cb = callback }
/** All callback that needs a status information for the AVB/Milan V1.2 */
static const struct es_builder_st es_builder_milan_v12[] =
static const struct es_builder_st es_builder_milan_v12[AVB_AEM_DESC_LAST_RESERVED_17221 + 1] =
{
HELPER_ES_BUIDLER(AVB_AEM_DESC_ENTITY, es_builder_desc_entity_milan_v12),
HELPER_ES_BUIDLER(AVB_AEM_DESC_STREAM_OUTPUT, es_buidler_desc_stream_general_prepare),
@ -184,42 +121,31 @@ static const struct es_builder_st es_builder_milan_v12[] =
HELPER_ES_BUIDLER(AVB_AEM_DESC_AVB_INTERFACE, es_buidler_desc_avb_interface),
};
/** All callback that needs a status information for Legacy AVB*/
static const struct es_builder_st es_builder_legacy_avb[] =
static const struct es_builder_st es_builder_legacy_avb[AVB_AEM_DESC_LAST_RESERVED_17221 + 1] =
{
HELPER_ES_BUIDLER(AVB_AEM_DESC_STREAM_OUTPUT, es_buidler_desc_stream_general_prepare),
HELPER_ES_BUIDLER(AVB_AEM_DESC_STREAM_INPUT, es_buidler_desc_stream_general_prepare),
};
/**
* \brief keep the list of the supported avb flavors here
*/
static const struct {
const struct es_builder_st *es_builder;
/** Number of elements in the es_builder */
size_t count;
} es_builders[] = {
[AVB_MODE_LEGACY] = {
.es_builder = es_builder_legacy_avb,
.count = ARRAY_SIZE(es_builder_legacy_avb),
.count = SPA_N_ELEMENTS(es_builder_legacy_avb),
},
[AVB_MODE_MILAN_V12] = {
.es_builder = es_builder_milan_v12,
.count = ARRAY_SIZE(es_builder_milan_v12),
.count = SPA_N_ELEMENTS(es_builder_milan_v12),
},
};
/**
* \brief, should be called when creating an a descriptor, it will attach
* the right state variable that are necessary for counters, stream info
* and so on...
*/
void es_builder_add_descriptor(struct server *server, uint16_t type,
uint16_t index, size_t size, void *ptr_aem)
{
const struct es_builder_st *es_builder;
struct descriptor *desc;
enum avb_mode avb_mode;
bool std_processing = false;
@ -234,34 +160,26 @@ void es_builder_add_descriptor(struct server *server, uint16_t type,
spa_assert(0);
}
es_builder = es_builders[avb_mode].es_builder;
if (type > es_builders[avb_mode].count) {
if (type >= es_builders[avb_mode].count) {
std_processing = true;
} else if (!es_builder[type].build_descriptor_cb) {
std_processing = true;
} else {
if (!es_builder[type].build_descriptor_cb) {
std_processing = true;
}
}
if (std_processing) {
if (!server_add_descriptor(server, type, index, size, ptr_aem)) {
if (!server_add_descriptor(server, type, index, 0, size, ptr_aem)) {
pw_log_error("Could not allocate descriptor %u at "
"index %u the avb aem type\n", type, index);
spa_assert(0);
}
} else {
desc = es_builder[type].build_descriptor_cb(server, type,
index, size, ptr_aem);
if (!desc) {
if (!es_builder[type].build_descriptor_cb(server, type,
index, size, ptr_aem)) {
pw_log_error("Could not allocate specific descriptr "
"%u at index %u the avb aem type\n",
type, index);
spa_assert(0);
}
desc->size = size;
}
}