mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-04-27 06:46:48 -04:00
Merge branch '5017-lock-make-it-effective' into 'master'
milan-avb: lock: ensure correct behavior See merge request pipewire/pipewire!2792
This commit is contained in:
commit
c651001882
5 changed files with 112 additions and 0 deletions
|
|
@ -71,6 +71,41 @@ static int handle_unsol_lock_entity_milanv12(struct aecp *aecp, struct descripto
|
|||
}
|
||||
|
||||
|
||||
void handle_cmd_lock_entity_expired_milan_v12(struct aecp *aecp, int64_t now)
|
||||
{
|
||||
struct server *server = aecp->server;
|
||||
struct descriptor *desc;
|
||||
struct aecp_aem_entity_milan_state *entity_state;
|
||||
struct aecp_aem_lock_state *lock;
|
||||
|
||||
desc = server_find_descriptor(server, AVB_AEM_DESC_ENTITY, 0);
|
||||
if (desc == NULL)
|
||||
return;
|
||||
|
||||
entity_state = desc->ptr;
|
||||
lock = &entity_state->state.lock_state;
|
||||
|
||||
if (!lock->is_locked)
|
||||
return;
|
||||
|
||||
if (lock->base_info.expire_timeout >= now)
|
||||
return;
|
||||
|
||||
pw_log_info("entity lock held by %" PRIx64 " expired after %lus, releasing",
|
||||
lock->locked_id, AECP_AEM_LOCK_ENTITY_EXPIRE_TIMEOUT_SECOND);
|
||||
|
||||
lock->is_locked = false;
|
||||
lock->locked_id = 0;
|
||||
/*
|
||||
* No specific triggering controller (this is a timeout, not a command).
|
||||
* Setting controller_entity_id to 0 combined with internal=true ensures
|
||||
* reply_unsol_send notifies ALL registered controllers, including the
|
||||
* one whose lock just expired.
|
||||
*/
|
||||
lock->base_info.controller_entity_id = 0;
|
||||
handle_unsol_lock_common(aecp, lock, true);
|
||||
}
|
||||
|
||||
/* LOCK_ENTITY */
|
||||
/* Milan v1.2, Sec. 5.4.2.2; IEEE 1722.1-2021, Sec. 7.4.2*/
|
||||
int handle_cmd_lock_entity_milan_v12(struct aecp *aecp, int64_t now, const void *m, int len)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,15 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief Checks whether the Milan entity lock has expired and releases it.
|
||||
*
|
||||
* Called once per second from the AECP periodic handler. If the lock is
|
||||
* active and its timeout (set at lock time) is earlier than @p now, the
|
||||
* lock is cleared.
|
||||
*/
|
||||
void handle_cmd_lock_entity_expired_milan_v12(struct aecp *aecp, int64_t now);
|
||||
|
||||
/**
|
||||
* @brief Command handling will generate the response for the lock command
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "aecp-aem.h"
|
||||
#include "aecp-aem-descriptors.h"
|
||||
#include "aecp-aem-state.h"
|
||||
#include "aecp-aem-cmds-resps/cmd-resp-helpers.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
|
@ -370,6 +371,44 @@ static const struct {
|
|||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Stub that queries the AECP entity lock state.
|
||||
*
|
||||
* Returns true when the entity is currently locked by a *different* controller
|
||||
* than the one sending the command, meaning the command must be rejected with
|
||||
* ENTITY_LOCKED. Returns false in all other cases (not locked, lock expired,
|
||||
* or requester is the lock owner).
|
||||
*
|
||||
* Only Milan V1.2 entities maintain a lock state; legacy AVB entities always
|
||||
* return false (unlocked).
|
||||
*/
|
||||
static bool check_locked(struct aecp *aecp, int64_t now,
|
||||
const struct avb_packet_aecp_aem *p)
|
||||
{
|
||||
struct server *server = aecp->server;
|
||||
const struct descriptor *desc;
|
||||
const struct aecp_aem_entity_milan_state *entity_state;
|
||||
const struct aecp_aem_lock_state *lock;
|
||||
|
||||
if (server->avb_mode != AVB_MODE_MILAN_V12)
|
||||
return false;
|
||||
|
||||
desc = server_find_descriptor(server, AVB_AEM_DESC_ENTITY, 0);
|
||||
if (desc == NULL)
|
||||
return false;
|
||||
|
||||
entity_state = desc->ptr;
|
||||
lock = &entity_state->state.lock_state;
|
||||
|
||||
/* A lock that has expired is treated as if the entity is unlocked. */
|
||||
if (lock->base_info.expire_timeout < now)
|
||||
return false;
|
||||
|
||||
/* Locked by a different controller → reject. */
|
||||
return lock->is_locked &&
|
||||
(lock->locked_id != htobe64(p->aecp.controller_guid));
|
||||
}
|
||||
|
||||
int avb_aecp_aem_handle_command(struct aecp *aecp, const void *m, int len)
|
||||
{
|
||||
const struct avb_ethernet_header *h = m;
|
||||
|
|
@ -402,9 +441,30 @@ int avb_aecp_aem_handle_command(struct aecp *aecp, const void *m, int len)
|
|||
|
||||
now = SPA_TIMESPEC_TO_NSEC(&ts_now);
|
||||
|
||||
/*
|
||||
* For write (non-readonly) commands, check whether the entity is locked
|
||||
* by a different controller before dispatching the handler. Readonly
|
||||
* commands are always allowed regardless of lock state.
|
||||
*/
|
||||
if (!info->is_readonly && check_locked(aecp, now, p)) {
|
||||
pw_log_info("aem command %s rejected: entity locked",
|
||||
cmd_names[cmd_type]);
|
||||
return reply_entity_locked(aecp, m, len);
|
||||
}
|
||||
|
||||
return info->handle_command(aecp, now, m, len);
|
||||
}
|
||||
|
||||
void avb_aecp_aem_periodic(struct aecp *aecp, int64_t now)
|
||||
{
|
||||
struct server *server = aecp->server;
|
||||
|
||||
if (server->avb_mode != AVB_MODE_MILAN_V12)
|
||||
return;
|
||||
|
||||
handle_cmd_lock_entity_expired_milan_v12(aecp, now);
|
||||
}
|
||||
|
||||
int avb_aecp_aem_handle_response(struct aecp *aecp, const void *m, int len)
|
||||
{
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -249,5 +249,6 @@ struct avb_packet_aecp_aem {
|
|||
|
||||
int avb_aecp_aem_handle_command(struct aecp *aecp, const void *m, int len);
|
||||
int avb_aecp_aem_handle_response(struct aecp *aecp, const void *m, int len);
|
||||
void avb_aecp_aem_periodic(struct aecp *aecp, int64_t now);
|
||||
|
||||
#endif /* AVB_AEM_H */
|
||||
|
|
|
|||
|
|
@ -86,6 +86,12 @@ static int aecp_message(void *data, uint64_t now, const void *message, int len)
|
|||
return info->handle(aecp, message, len);
|
||||
}
|
||||
|
||||
static void aecp_periodic(void *data, uint64_t now)
|
||||
{
|
||||
struct aecp *aecp = data;
|
||||
avb_aecp_aem_periodic(aecp, (int64_t)now);
|
||||
}
|
||||
|
||||
static void aecp_destroy(void *data)
|
||||
{
|
||||
struct aecp *aecp = data;
|
||||
|
|
@ -124,6 +130,7 @@ static const struct server_events server_events = {
|
|||
AVB_VERSION_SERVER_EVENTS,
|
||||
.destroy = aecp_destroy,
|
||||
.message = aecp_message,
|
||||
.periodic = aecp_periodic,
|
||||
.command = aecp_command
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue