avb: add beginnings of MRP/MMRP/MSRP/MVRP/SRP

This commit is contained in:
Wim Taymans 2022-03-22 19:40:23 +01:00
parent 911378651b
commit 893251c8eb
19 changed files with 1034 additions and 42 deletions

View file

@ -528,7 +528,13 @@ pipewire_module_avbtp = shared_library('pipewire-module-avbtp',
'module-avbtp/aecp.c', 'module-avbtp/aecp.c',
'module-avbtp/aecp-aem.c', 'module-avbtp/aecp-aem.c',
'module-avbtp/avdecc.c', 'module-avbtp/avdecc.c',
'module-avbtp/maap.c' ], 'module-avbtp/maap.c',
'module-avbtp/mmrp.c',
'module-avbtp/mrp.c',
'module-avbtp/msrp.c',
'module-avbtp/mvrp.c',
'module-avbtp/srp.c'
],
include_directories : [configinc], include_directories : [configinc],
install : true, install : true,
install_dir : modules_install_dir, install_dir : modules_install_dir,

View file

@ -30,6 +30,8 @@
#include "acmp.h" #include "acmp.h"
#include "internal.h" #include "internal.h"
static const uint8_t mac[6] = AVB_BROADCAST_MAC;
struct pending { struct pending {
struct spa_list link; struct spa_list link;
uint64_t last_time; uint64_t last_time;
@ -104,7 +106,8 @@ static int reply_not_supported(struct acmp *acmp, const void *m, int len)
memcpy(reply, m, len); memcpy(reply, m, len);
AVBTP_PACKET_ACMP_SET_STATUS(reply, AVBTP_ACMP_STATUS_NOT_SUPPORTED); AVBTP_PACKET_ACMP_SET_STATUS(reply, AVBTP_ACMP_STATUS_NOT_SUPPORTED);
return avbtp_server_send_packet(server, reply->hdr.eth.src, reply, len); return avbtp_server_send_packet(server, reply->hdr.eth.src,
AVB_TSN_ETH, reply, len);
} }
static int retry_pending(struct acmp *acmp, uint64_t now, struct pending *p) static int retry_pending(struct acmp *acmp, uint64_t now, struct pending *p)
@ -113,7 +116,8 @@ static int retry_pending(struct acmp *acmp, uint64_t now, struct pending *p)
struct avbtp_packet_acmp *cmd = p->ptr; struct avbtp_packet_acmp *cmd = p->ptr;
p->retry++; p->retry++;
p->last_time = now; p->last_time = now;
return avbtp_server_send_packet(server, cmd->hdr.eth.dest, cmd, p->size); return avbtp_server_send_packet(server, cmd->hdr.eth.dest,
AVB_TSN_ETH, cmd, p->size);
} }
static int handle_connect_tx_command(struct acmp *acmp, uint64_t now, const void *m, int len) static int handle_connect_tx_command(struct acmp *acmp, uint64_t now, const void *m, int len)
@ -130,7 +134,8 @@ static int handle_connect_tx_command(struct acmp *acmp, uint64_t now, const void
AVBTP_PACKET_ACMP_SET_MESSAGE_TYPE(reply, AVBTP_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE); AVBTP_PACKET_ACMP_SET_MESSAGE_TYPE(reply, AVBTP_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE);
AVBTP_PACKET_ACMP_SET_STATUS(reply, AVBTP_ACMP_STATUS_SUCCESS); AVBTP_PACKET_ACMP_SET_STATUS(reply, AVBTP_ACMP_STATUS_SUCCESS);
return avbtp_server_send_packet(server, reply->hdr.eth.dest, reply, len); return avbtp_server_send_packet(server, reply->hdr.eth.dest,
AVB_TSN_ETH, reply, len);
} }
static int handle_connect_tx_response(struct acmp *acmp, uint64_t now, const void *m, int len) static int handle_connect_tx_response(struct acmp *acmp, uint64_t now, const void *m, int len)
@ -156,7 +161,8 @@ static int handle_connect_tx_response(struct acmp *acmp, uint64_t now, const voi
reply->sequence_id = htons(pending->old_sequence_id); reply->sequence_id = htons(pending->old_sequence_id);
AVBTP_PACKET_ACMP_SET_MESSAGE_TYPE(reply, AVBTP_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE); AVBTP_PACKET_ACMP_SET_MESSAGE_TYPE(reply, AVBTP_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE);
res = avbtp_server_send_packet(server, reply->hdr.eth.dest, reply, pending->size); res = avbtp_server_send_packet(server, reply->hdr.eth.dest,
AVB_TSN_ETH, reply, pending->size);
pending_free(acmp, pending); pending_free(acmp, pending);
@ -177,7 +183,8 @@ static int handle_disconnect_tx_command(struct acmp *acmp, uint64_t now, const v
AVBTP_PACKET_ACMP_SET_MESSAGE_TYPE(reply, AVBTP_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE); AVBTP_PACKET_ACMP_SET_MESSAGE_TYPE(reply, AVBTP_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE);
AVBTP_PACKET_ACMP_SET_STATUS(reply, AVBTP_ACMP_STATUS_SUCCESS); AVBTP_PACKET_ACMP_SET_STATUS(reply, AVBTP_ACMP_STATUS_SUCCESS);
return avbtp_server_send_packet(server, reply->hdr.eth.dest, reply, len); return avbtp_server_send_packet(server, reply->hdr.eth.dest,
AVB_TSN_ETH, reply, len);
} }
static int handle_disconnect_tx_response(struct acmp *acmp, uint64_t now, const void *m, int len) static int handle_disconnect_tx_response(struct acmp *acmp, uint64_t now, const void *m, int len)
@ -203,7 +210,8 @@ static int handle_disconnect_tx_response(struct acmp *acmp, uint64_t now, const
reply->sequence_id = htons(pending->old_sequence_id); reply->sequence_id = htons(pending->old_sequence_id);
AVBTP_PACKET_ACMP_SET_MESSAGE_TYPE(reply, AVBTP_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE); AVBTP_PACKET_ACMP_SET_MESSAGE_TYPE(reply, AVBTP_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE);
res = avbtp_server_send_packet(server, reply->hdr.eth.dest, reply, pending->size); res = avbtp_server_send_packet(server, reply->hdr.eth.dest,
AVB_TSN_ETH, reply, pending->size);
pending_free(acmp, pending); pending_free(acmp, pending);
@ -227,7 +235,8 @@ static int handle_connect_rx_command(struct acmp *acmp, uint64_t now, const void
AVBTP_PACKET_ACMP_SET_MESSAGE_TYPE(cmd, AVBTP_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND); AVBTP_PACKET_ACMP_SET_MESSAGE_TYPE(cmd, AVBTP_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND);
AVBTP_PACKET_ACMP_SET_STATUS(cmd, AVBTP_ACMP_STATUS_SUCCESS); AVBTP_PACKET_ACMP_SET_STATUS(cmd, AVBTP_ACMP_STATUS_SUCCESS);
return avbtp_server_send_packet(server, cmd->hdr.eth.dest, cmd, len); return avbtp_server_send_packet(server, cmd->hdr.eth.dest,
AVB_TSN_ETH, cmd, len);
} }
static int handle_connect_rx_response(struct acmp *acmp, uint64_t now, const void *m, int len) static int handle_connect_rx_response(struct acmp *acmp, uint64_t now, const void *m, int len)
@ -252,7 +261,8 @@ static int handle_disconnect_rx_command(struct acmp *acmp, uint64_t now, const v
AVBTP_PACKET_ACMP_SET_MESSAGE_TYPE(cmd, AVBTP_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND); AVBTP_PACKET_ACMP_SET_MESSAGE_TYPE(cmd, AVBTP_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND);
AVBTP_PACKET_ACMP_SET_STATUS(cmd, AVBTP_ACMP_STATUS_SUCCESS); AVBTP_PACKET_ACMP_SET_STATUS(cmd, AVBTP_ACMP_STATUS_SUCCESS);
return avbtp_server_send_packet(server, cmd->hdr.eth.dest, cmd, len); return avbtp_server_send_packet(server, cmd->hdr.eth.dest,
AVB_TSN_ETH, cmd, len);
} }
static int handle_disconnect_rx_response(struct acmp *acmp, uint64_t now, const void *p, int len) static int handle_disconnect_rx_response(struct acmp *acmp, uint64_t now, const void *p, int len)
@ -291,10 +301,17 @@ static inline const struct msg_info *find_msg_info(uint16_t type, const char *na
static int acmp_message(void *data, uint64_t now, const void *message, int len) static int acmp_message(void *data, uint64_t now, const void *message, int len)
{ {
struct acmp *acmp = data; struct acmp *acmp = data;
struct server *server = acmp->server;
const struct avbtp_packet_acmp *p = message; const struct avbtp_packet_acmp *p = message;
const struct msg_info *info; const struct msg_info *info;
int message_type; int message_type;
if (ntohs(p->hdr.eth.type) != AVB_TSN_ETH)
return 0;
if (memcmp(p->hdr.eth.dest, mac, 6) != 0 &&
memcmp(p->hdr.eth.dest, server->mac_addr, 6) != 0)
return 0;
if (AVBTP_PACKET_GET_SUBTYPE(&p->hdr) != AVBTP_SUBTYPE_ACMP) if (AVBTP_PACKET_GET_SUBTYPE(&p->hdr) != AVBTP_SUBTYPE_ACMP)
return 0; return 0;

View file

@ -31,6 +31,8 @@
#include "internal.h" #include "internal.h"
#include "utils.h" #include "utils.h"
static const uint8_t mac[6] = AVB_BROADCAST_MAC;
struct entity { struct entity {
struct spa_list link; struct spa_list link;
struct avbtp_packet_adp packet; struct avbtp_packet_adp packet;
@ -64,7 +66,7 @@ static int send_departing(struct adp *adp, uint64_t now, struct entity *e)
{ {
AVBTP_PACKET_ADP_SET_MESSAGE_TYPE(&e->packet, AVBTP_ADP_MESSAGE_TYPE_ENTITY_DEPARTING); AVBTP_PACKET_ADP_SET_MESSAGE_TYPE(&e->packet, AVBTP_ADP_MESSAGE_TYPE_ENTITY_DEPARTING);
e->packet.available_index = htonl(adp->available_index++); e->packet.available_index = htonl(adp->available_index++);
avbtp_server_broadcast_packet(adp->server, &e->packet, sizeof(e->packet)); avbtp_server_send_packet(adp->server, mac, AVB_TSN_ETH, &e->packet, sizeof(e->packet));
e->last_time = now; e->last_time = now;
return 0; return 0;
} }
@ -73,7 +75,7 @@ static int send_advertise(struct adp *adp, uint64_t now, struct entity *e)
{ {
AVBTP_PACKET_ADP_SET_MESSAGE_TYPE(&e->packet, AVBTP_ADP_MESSAGE_TYPE_ENTITY_AVAILABLE); AVBTP_PACKET_ADP_SET_MESSAGE_TYPE(&e->packet, AVBTP_ADP_MESSAGE_TYPE_ENTITY_AVAILABLE);
e->packet.available_index = htonl(adp->available_index++); e->packet.available_index = htonl(adp->available_index++);
avbtp_server_broadcast_packet(adp->server, &e->packet, sizeof(e->packet)); avbtp_server_send_packet(adp->server, mac, AVB_TSN_ETH, &e->packet, sizeof(e->packet));
e->last_time = now; e->last_time = now;
return 0; return 0;
} }
@ -86,19 +88,26 @@ static int send_discover(struct adp *adp, uint64_t entity_id)
AVBTP_PACKET_SET_LENGTH(&p.hdr, AVBTP_ADP_CONTROL_DATA_LENGTH); AVBTP_PACKET_SET_LENGTH(&p.hdr, AVBTP_ADP_CONTROL_DATA_LENGTH);
AVBTP_PACKET_ADP_SET_MESSAGE_TYPE(&p, AVBTP_ADP_MESSAGE_TYPE_ENTITY_DISCOVER); AVBTP_PACKET_ADP_SET_MESSAGE_TYPE(&p, AVBTP_ADP_MESSAGE_TYPE_ENTITY_DISCOVER);
p.entity_id = htonl(entity_id); p.entity_id = htonl(entity_id);
avbtp_server_broadcast_packet(adp->server, &p, sizeof(p)); avbtp_server_send_packet(adp->server, mac, AVB_TSN_ETH, &p, sizeof(p));
return 0; return 0;
} }
static int adp_message(void *data, uint64_t now, const void *message, int len) static int adp_message(void *data, uint64_t now, const void *message, int len)
{ {
struct adp *adp = data; struct adp *adp = data;
struct server *server = adp->server;
const struct avbtp_packet_adp *p = message; const struct avbtp_packet_adp *p = message;
struct entity *e; struct entity *e;
int message_type; int message_type;
char buf[128]; char buf[128];
uint64_t entity_id; uint64_t entity_id;
if (ntohs(p->hdr.eth.type) != AVB_TSN_ETH)
return 0;
if (memcmp(p->hdr.eth.dest, mac, 6) != 0 &&
memcmp(p->hdr.eth.dest, server->mac_addr, 6) != 0)
return 0;
if (AVBTP_PACKET_GET_SUBTYPE(&p->hdr) != AVBTP_SUBTYPE_ADP || if (AVBTP_PACKET_GET_SUBTYPE(&p->hdr) != AVBTP_SUBTYPE_ADP ||
AVBTP_PACKET_GET_LENGTH(&p->hdr) < AVBTP_ADP_CONTROL_DATA_LENGTH) AVBTP_PACKET_GET_LENGTH(&p->hdr) < AVBTP_ADP_CONTROL_DATA_LENGTH)
return 0; return 0;

View file

@ -35,7 +35,8 @@ static int reply_status(struct aecp *aecp, int status, const void *m, int len)
AVBTP_PACKET_AECP_SET_MESSAGE_TYPE(reply, AVBTP_AECP_MESSAGE_TYPE_AEM_RESPONSE); AVBTP_PACKET_AECP_SET_MESSAGE_TYPE(reply, AVBTP_AECP_MESSAGE_TYPE_AEM_RESPONSE);
AVBTP_PACKET_AECP_SET_STATUS(reply, status); AVBTP_PACKET_AECP_SET_STATUS(reply, status);
return avbtp_server_send_packet(server, reply->hdr.eth.src, reply, len); return avbtp_server_send_packet(server, reply->hdr.eth.src,
AVB_TSN_ETH, reply, len);
} }
static int reply_not_implemented(struct aecp *aecp, const void *m, int len) static int reply_not_implemented(struct aecp *aecp, const void *m, int len)
@ -133,7 +134,8 @@ static int handle_read_descriptor(struct aecp *aecp, const void *m, int len)
AVBTP_PACKET_AECP_SET_STATUS(&reply->aecp, AVBTP_AECP_AEM_STATUS_SUCCESS); AVBTP_PACKET_AECP_SET_STATUS(&reply->aecp, AVBTP_AECP_AEM_STATUS_SUCCESS);
AVBTP_PACKET_SET_LENGTH(&reply->aecp.hdr, psize + 12); AVBTP_PACKET_SET_LENGTH(&reply->aecp.hdr, psize + 12);
return avbtp_server_send_packet(server, reply->aecp.hdr.eth.src, reply, size); return avbtp_server_send_packet(server, reply->aecp.hdr.eth.src,
AVB_TSN_ETH, reply, size);
} }
/* GET_AVB_INFO */ /* GET_AVB_INFO */
@ -180,7 +182,8 @@ static int handle_get_avb_info(struct aecp *aecp, const void *m, int len)
i->flags = 0; i->flags = 0;
i->msrp_mappings_count = htons(0); i->msrp_mappings_count = htons(0);
return avbtp_server_send_packet(server, reply->aecp.hdr.eth.src, reply, size); return avbtp_server_send_packet(server, reply->aecp.hdr.eth.src,
AVB_TSN_ETH, reply, size);
} }
/* AEM_COMMAND */ /* AEM_COMMAND */

View file

@ -31,6 +31,8 @@
#include "aecp-aem.h" #include "aecp-aem.h"
#include "internal.h" #include "internal.h"
static const uint8_t mac[6] = AVB_BROADCAST_MAC;
struct msg_info { struct msg_info {
uint16_t type; uint16_t type;
const char *name; const char *name;
@ -46,7 +48,8 @@ static int reply_not_implemented(struct aecp *aecp, const void *p, int len)
memcpy(reply, p, len); memcpy(reply, p, len);
AVBTP_PACKET_AECP_SET_STATUS(reply, AVBTP_AECP_STATUS_NOT_IMPLEMENTED); AVBTP_PACKET_AECP_SET_STATUS(reply, AVBTP_AECP_STATUS_NOT_IMPLEMENTED);
return avbtp_server_send_packet(server, reply->hdr.eth.src, reply, len); return avbtp_server_send_packet(server, reply->hdr.eth.src,
AVB_TSN_ETH, reply, len);
} }
static const struct msg_info msg_info[] = { static const struct msg_info msg_info[] = {
@ -76,10 +79,16 @@ static inline const struct msg_info *find_msg_info(uint16_t type, const char *na
static int aecp_message(void *data, uint64_t now, const void *message, int len) static int aecp_message(void *data, uint64_t now, const void *message, int len)
{ {
struct aecp *aecp = data; struct aecp *aecp = data;
struct server *server = aecp->server;
const struct avbtp_packet_aecp_header *p = message; const struct avbtp_packet_aecp_header *p = message;
const struct msg_info *info; const struct msg_info *info;
int message_type; int message_type;
if (ntohs(p->hdr.eth.type) != AVB_TSN_ETH)
return 0;
if (memcmp(p->hdr.eth.dest, mac, 6) != 0 &&
memcmp(p->hdr.eth.dest, server->mac_addr, 6) != 0)
return 0;
if (AVBTP_PACKET_GET_SUBTYPE(&p->hdr) != AVBTP_SUBTYPE_AECP) if (AVBTP_PACKET_GET_SUBTYPE(&p->hdr) != AVBTP_SUBTYPE_AECP)
return 0; return 0;

View file

@ -43,12 +43,13 @@
#include "adp.h" #include "adp.h"
#include "aecp.h" #include "aecp.h"
#include "maap.h" #include "maap.h"
#include "mmrp.h"
#include "msrp.h"
#include "mvrp.h"
#include "descriptors.h" #include "descriptors.h"
#define DEFAULT_INTERVAL 1 #define DEFAULT_INTERVAL 1
static const uint8_t AVB_MAC_BROADCAST[6] = { 0x91, 0xe0, 0xf0, 0x01, 0x00, 0x00 };
#define server_emit(s,m,v,...) spa_hook_list_call(&s->listener_list, struct server_events, m, v, ##__VA_ARGS__) #define server_emit(s,m,v,...) spa_hook_list_call(&s->listener_list, struct server_events, m, v, ##__VA_ARGS__)
#define server_emit_destroy(s) server_emit(s, destroy, 0) #define server_emit_destroy(s) server_emit(s, destroy, 0)
#define server_emit_message(s,n,m,l) server_emit(s, message, 0, n, m, l) #define server_emit_message(s,n,m,l) server_emit(s, message, 0, n, m, l)
@ -81,28 +82,21 @@ static void on_socket_data(void *data, int fd, uint32_t mask)
pw_log_warn("short packet received (%d < %d)", len, pw_log_warn("short packet received (%d < %d)", len,
(int)sizeof(struct avbtp_packet_header)); (int)sizeof(struct avbtp_packet_header));
} else { } else {
struct avbtp_ethernet_header *hdr = (struct avbtp_ethernet_header*)buffer;
if (htons(hdr->type) != ETH_P_TSN)
return;
if (memcmp(hdr->dest, AVB_MAC_BROADCAST, ETH_ALEN) != 0 &&
memcmp(hdr->dest, server->mac_addr, ETH_ALEN) != 0)
return;
clock_gettime(CLOCK_REALTIME, &now); clock_gettime(CLOCK_REALTIME, &now);
server_emit_message(server, SPA_TIMESPEC_TO_NSEC(&now), buffer, len); server_emit_message(server, SPA_TIMESPEC_TO_NSEC(&now), buffer, len);
} }
} }
} }
int avbtp_server_send_packet(struct server *server, const uint8_t dest[6], void *data, size_t size) int avbtp_server_send_packet(struct server *server, const uint8_t dest[6],
uint16_t type, void *data, size_t size)
{ {
struct avbtp_ethernet_header *hdr = (struct avbtp_ethernet_header*)data; struct avbtp_ethernet_header *hdr = (struct avbtp_ethernet_header*)data;
int res = 0; int res = 0;
memcpy(hdr->dest, dest, ETH_ALEN); memcpy(hdr->dest, dest, ETH_ALEN);
memcpy(hdr->src, server->mac_addr, ETH_ALEN); memcpy(hdr->src, server->mac_addr, ETH_ALEN);
hdr->type = htons(ETH_P_TSN); hdr->type = htons(type);
if (send(server->source->fd, data, size, 0) < 0) { if (send(server->source->fd, data, size, 0) < 0) {
res = -errno; res = -errno;
@ -111,11 +105,6 @@ int avbtp_server_send_packet(struct server *server, const uint8_t dest[6], void
return res; return res;
} }
int avbtp_server_broadcast_packet(struct server *server, void *data, size_t size)
{
return avbtp_server_send_packet(server, AVB_MAC_BROADCAST, data, size);
}
static int setup_socket(struct server *server) static int setup_socket(struct server *server)
{ {
struct impl *impl = server->impl; struct impl *impl = server->impl;
@ -227,8 +216,13 @@ struct server *avdecc_server_new(struct impl *impl, const char *ifname, struct s
init_descriptors(server); init_descriptors(server);
server->mrp = avbtp_mrp_new(server);
avbtp_aecp_register(server); avbtp_aecp_register(server);
avbtp_maap_register(server); avbtp_maap_register(server);
avbtp_mmrp_register(server);
avbtp_msrp_register(server);
avbtp_mvrp_register(server);
avbtp_adp_register(server); avbtp_adp_register(server);
avbtp_acmp_register(server); avbtp_acmp_register(server);
@ -241,10 +235,8 @@ error_free:
return NULL; return NULL;
} }
void avdecc_server_add_listener(struct server *server, void avdecc_server_add_listener(struct server *server, struct spa_hook *listener,
struct spa_hook *listener, const struct server_events *events, void *data)
const struct server_events *events,
void *data)
{ {
spa_hook_list_append(&server->listener_list, listener, events, data); spa_hook_list_append(&server->listener_list, listener, events, data);
} }

View file

@ -31,6 +31,10 @@ extern "C" {
#include <pipewire/pipewire.h> #include <pipewire/pipewire.h>
#define AVB_TSN_ETH 0x22f0
#define AVB_BROADCAST_MAC { 0x91, 0xe0, 0xf0, 0x01, 0x00, 0x00 };
struct impl { struct impl {
struct pw_loop *loop; struct pw_loop *loop;
struct pw_context *context; struct pw_context *context;
@ -64,6 +68,7 @@ struct descriptor {
void *ptr; void *ptr;
}; };
struct server { struct server {
struct spa_list link; struct spa_list link;
struct impl *impl; struct impl *impl;
@ -81,6 +86,8 @@ struct server {
struct spa_list descriptors; struct spa_list descriptors;
unsigned debug_messages:1; unsigned debug_messages:1;
struct avbtp_mrp *mrp;
}; };
static inline const struct descriptor *server_find_descriptor(struct server *server, static inline const struct descriptor *server_find_descriptor(struct server *server,
@ -118,8 +125,8 @@ void avdecc_server_free(struct server *server);
void avdecc_server_add_listener(struct server *server, struct spa_hook *listener, void avdecc_server_add_listener(struct server *server, struct spa_hook *listener,
const struct server_events *events, void *data); const struct server_events *events, void *data);
int avbtp_server_broadcast_packet(struct server *server, void *data, size_t size); int avbtp_server_send_packet(struct server *server, const uint8_t dest[6],
int avbtp_server_send_packet(struct server *server, const uint8_t dest[6], void *data, size_t size); uint16_t type, void *data, size_t size);
struct aecp { struct aecp {
struct server *server; struct server *server;

View file

@ -26,6 +26,8 @@
#include "maap.h" #include "maap.h"
static const uint8_t mac[6] = AVB_BROADCAST_MAC;
struct maap { struct maap {
struct server *server; struct server *server;
struct spa_hook server_listener; struct spa_hook server_listener;
@ -68,8 +70,14 @@ static void maap_message_debug(struct maap *maap, const struct avbtp_packet_maap
static int maap_message(void *data, uint64_t now, const void *message, int len) static int maap_message(void *data, uint64_t now, const void *message, int len)
{ {
struct maap *maap = data; struct maap *maap = data;
struct server *server = maap->server;
const struct avbtp_packet_maap *p = message; const struct avbtp_packet_maap *p = message;
if (ntohs(p->hdr.eth.type) != AVB_TSN_ETH)
return 0;
if (memcmp(p->hdr.eth.dest, mac, 6) != 0 &&
memcmp(p->hdr.eth.dest, server->mac_addr, 6) != 0)
return 0;
if (AVBTP_PACKET_GET_SUBTYPE(&p->hdr) != AVBTP_SUBTYPE_MAAP) if (AVBTP_PACKET_GET_SUBTYPE(&p->hdr) != AVBTP_SUBTYPE_MAAP)
return 0; return 0;

View file

@ -0,0 +1,76 @@
/* AVB support
*
* Copyright © 2022 Wim Taymans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <pipewire/pipewire.h>
#include "mmrp.h"
static const uint8_t mac[6] = AVB_MMRP_MAC;
struct mmrp {
struct server *server;
struct spa_hook server_listener;
};
static int mmrp_message(void *data, uint64_t now, const void *message, int len)
{
const struct avbtp_packet_mrp *p = message;
if (ntohs(p->eth.type) != AVB_MMRP_ETH)
return 0;
if (memcmp(p->eth.dest, mac, 6) != 0)
return 0;
pw_log_info("MMRP");
return 0;
}
static void mmrp_destroy(void *data)
{
struct mmrp *mmrp = data;
spa_hook_remove(&mmrp->server_listener);
free(mmrp);
}
static const struct server_events server_events = {
AVBTP_VERSION_SERVER_EVENTS,
.destroy = mmrp_destroy,
.message = mmrp_message
};
int avbtp_mmrp_register(struct server *server)
{
struct mmrp *mmrp;
mmrp = calloc(1, sizeof(*mmrp));
if (mmrp == NULL)
return -errno;
mmrp->server = server;
avdecc_server_add_listener(server, &mmrp->server_listener, &server_events, mmrp);
return 0;
}

View file

@ -0,0 +1,42 @@
/* AVB support
*
* Copyright © 2022 Wim Taymans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef AVBTP_MMRP_H
#define AVBTP_MMRP_H
#include "mrp.h"
#include "internal.h"
#define AVB_MMRP_ETH 0x88f6
#define AVB_MMRP_MAC { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x20 }
struct avbtp_packet_mmrp_msg {
uint8_t attribute_type;
uint8_t attribute_length;
uint8_t attribute_list[0];
} __attribute__ ((__packed__));
int avbtp_mmrp_register(struct server *server);
#endif /* AVBTP_MMRP_H */

View file

@ -0,0 +1,151 @@
/* AVB support
*
* Copyright © 2022 Wim Taymans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <pipewire/pipewire.h>
#include "mrp.h"
struct mrp {
struct server *server;
struct spa_hook server_listener;
};
static void mrp_destroy(void *data)
{
struct mrp *mrp = data;
spa_hook_remove(&mrp->server_listener);
free(mrp);
}
static const struct server_events server_events = {
AVBTP_VERSION_SERVER_EVENTS,
.destroy = mrp_destroy,
};
void avbtp_mrp_attribute_init(struct avbtp_mrp *mrp,
struct avbtp_mrp_attribute *attr,
uint8_t type, void *info)
{
}
static void stop_avb_timer(void)
{
}
static void start_avb_timer(void)
{
}
void avbtp_mrp_update_state(struct avbtp_mrp *mrp,
struct avbtp_mrp_attribute *attr, int event, uint8_t param)
{
switch (event) {
case AVBTP_MRP_EVENT_BEGIN:
attr->registrar_state = AVBTP_MRP_MT;
break;
case AVBTP_MRP_EVENT_RX_NEW:
if (attr->registrar_state == AVBTP_MRP_LV)
stop_avb_timer();
attr->registrar_state = AVBTP_MRP_IN;
attr->pending_indications |= AVBTP_PENDING_JOIN_NEW;
attr->param = param;
break;
case AVBTP_MRP_EVENT_RX_JOININ:
case AVBTP_MRP_EVENT_RX_JOINMT:
if (attr->registrar_state == AVBTP_MRP_LV)
stop_avb_timer();
if (attr->registrar_state == AVBTP_MRP_MT) {
attr->pending_indications |= AVBTP_PENDING_JOIN;
attr->param = param;
}
attr->registrar_state = AVBTP_MRP_IN;
break;
case AVBTP_MRP_EVENT_RX_LV:
case AVBTP_MRP_EVENT_RX_LVA:
case AVBTP_MRP_EVENT_TX_LVA:
case AVBTP_MRP_EVENT_REDECLARE:
if (attr->registrar_state == AVBTP_MRP_IN) {
start_avb_timer();
attr->registrar_state = AVBTP_MRP_LV;
}
break;
case AVBTP_MRP_EVENT_LV_TIMER:
case AVBTP_MRP_EVENT_FLUSH:
if (attr->registrar_state == AVBTP_MRP_LV) {
attr->pending_indications |= AVBTP_PENDING_LEAVE;
attr->param = param;
}
attr->registrar_state = AVBTP_MRP_MT;
break;
default:
break;
}
}
void avbtp_mrp_event(struct avbtp_mrp *mrp, struct avbtp_mrp_attribute *attr,
uint8_t event, uint8_t param)
{
static const int map[] = {
[AVBTP_MRP_ATTRIBUTE_EVENT_NEW] = AVBTP_MRP_EVENT_RX_NEW,
[AVBTP_MRP_ATTRIBUTE_EVENT_JOININ] = AVBTP_MRP_EVENT_RX_JOININ,
[AVBTP_MRP_ATTRIBUTE_EVENT_IN] = AVBTP_MRP_EVENT_RX_IN,
[AVBTP_MRP_ATTRIBUTE_EVENT_JOINMT] = AVBTP_MRP_EVENT_RX_JOINMT,
[AVBTP_MRP_ATTRIBUTE_EVENT_MT] = AVBTP_MRP_EVENT_RX_MT,
[AVBTP_MRP_ATTRIBUTE_EVENT_LV] = AVBTP_MRP_EVENT_RX_LV,
};
avbtp_mrp_update_state(mrp, attr, map[event], param);
}
void avbtp_mrp_mad_begin(struct avbtp_mrp *mrp, struct avbtp_mrp_attribute *attr)
{
}
void avbtp_mrp_mad_join(struct avbtp_mrp *mrp, struct avbtp_mrp_attribute *attr, bool is_new)
{
}
void avbtp_mrp_mad_leave(struct avbtp_mrp *mrp, struct avbtp_mrp_attribute *attr)
{
}
void avbtp_mrp_destroy(struct avbtp_mrp *mrp)
{
mrp_destroy(mrp);
}
struct avbtp_mrp *avbtp_mrp_new(struct server *server)
{
struct mrp *mrp;
mrp = calloc(1, sizeof(*mrp));
if (mrp == NULL)
return NULL;
mrp->server = server;
avdecc_server_add_listener(server, &mrp->server_listener, &server_events, mrp);
return (struct avbtp_mrp*)mrp;
}

View file

@ -0,0 +1,134 @@
/* AVB support
*
* Copyright © 2022 Wim Taymans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef AVBTP_MRP_H
#define AVBTP_MRP_H
#include "packets.h"
#include "internal.h"
struct avbtp_packet_mrp {
struct avbtp_ethernet_header eth;
uint8_t version;
} __attribute__ ((__packed__));
struct avbtp_packet_mrp_vector {
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned lva:3;
unsigned nv1:5;
#elif __BYTE_ORDER == __LITTLE_ENDIAN
unsigned nv1:5;
unsigned lva:3;
#endif
uint8_t nv2;
uint8_t first_value[0];
} __attribute__ ((__packed__));
#define AVBTP_MRP_VECTOR_SET_NUM_VALUES(a,v) ((a)->nv1 = ((v) >> 8),(p)->nv2 = (v))
#define AVBTP_MRP_VECTOR_GET_NUM_VALUES(a) ((a)->nv1 << 8 | (a)->nv2)
struct avbtp_packet_mrp_footer {
uint16_t end_mark;
} __attribute__ ((__packed__));
/* applicant states */
#define AVBTP_MRP_VO 0 /* Very anxious Observer */
#define AVBTP_MRP_VP 1 /* Very anxious Passive */
#define AVBTP_MRP_VN 2 /* Very anxious New */
#define AVBTP_MRP_AN 3 /* Anxious New */
#define AVBTP_MRP_AA 4 /* Anxious Active */
#define AVBTP_MRP_QA 5 /* Quiet Active */
#define AVBTP_MRP_LA 6 /* Leaving Active */
#define AVBTP_MRP_AO 7 /* Anxious Observer */
#define AVBTP_MRP_QO 8 /* Quiet Observer */
#define AVBTP_MRP_AP 9 /* Anxious Passive */
#define AVBTP_MRP_QP 10 /* Quiet Passive */
#define AVBTP_MRP_LO 11 /* Leaving Observer */
/* registrar states */
#define AVBTP_MRP_IN 16
#define AVBTP_MRP_LV 17
#define AVBTP_MRP_MT 18
/* events */
#define AVBTP_MRP_EVENT_BEGIN 0
#define AVBTP_MRP_EVENT_NEW 1
#define AVBTP_MRP_EVENT_JOIN 2
#define AVBTP_MRP_EVENT_LV 3
#define AVBTP_MRP_EVENT_TX 4
#define AVBTP_MRP_EVENT_TX_LVA 5
#define AVBTP_MRP_EVENT_TX_LVAF 6
#define AVBTP_MRP_EVENT_RX_NEW 7
#define AVBTP_MRP_EVENT_RX_JOININ 8
#define AVBTP_MRP_EVENT_RX_IN 9
#define AVBTP_MRP_EVENT_RX_JOINMT 10
#define AVBTP_MRP_EVENT_RX_MT 11
#define AVBTP_MRP_EVENT_RX_LV 12
#define AVBTP_MRP_EVENT_RX_LVA 13
#define AVBTP_MRP_EVENT_FLUSH 14
#define AVBTP_MRP_EVENT_REDECLARE 15
#define AVBTP_MRP_EVENT_PERIODIC 16
#define AVBTP_MRP_EVENT_LV_TIMER 17
#define AVBTP_MRP_EVENT_LVA_TIMER 18
/* attribute events */
#define AVBTP_MRP_ATTRIBUTE_EVENT_NEW 0
#define AVBTP_MRP_ATTRIBUTE_EVENT_JOININ 1
#define AVBTP_MRP_ATTRIBUTE_EVENT_IN 2
#define AVBTP_MRP_ATTRIBUTE_EVENT_JOINMT 3
#define AVBTP_MRP_ATTRIBUTE_EVENT_MT 4
#define AVBTP_MRP_ATTRIBUTE_EVENT_LV 5
#define AVBTP_PENDING_JOIN_NEW (1u<<0)
#define AVBTP_PENDING_JOIN (1u<<1)
#define AVBTP_PENDING_LEAVE (1u<<2)
struct avbtp_mrp_attribute {
uint8_t type;
uint8_t applicant_state;
uint8_t registrar_state;
uint16_t pending_indications;
uint8_t param;
struct avbtp_mrp_attribute *next;
void *attribute_info;
};
void avbtp_mrp_attribute_init(struct avbtp_mrp *mrp,
struct avbtp_mrp_attribute *attr,
uint8_t type, void *info);
void avbtp_mrp_update_state(struct avbtp_mrp *mrp,
struct avbtp_mrp_attribute *attr, int event, uint8_t param);
void avbtp_mrp_event(struct avbtp_mrp *mrp, struct avbtp_mrp_attribute *attr,
uint8_t event, uint8_t param);
void avbtp_mrp_mad_begin(struct avbtp_mrp *mrp, struct avbtp_mrp_attribute *attr);
void avbtp_mrp_mad_join(struct avbtp_mrp *mrp, struct avbtp_mrp_attribute *attr, bool is_new);
void avbtp_mrp_mad_leave(struct avbtp_mrp *mrp, struct avbtp_mrp_attribute *attr);
struct avbtp_mrp *avbtp_mrp_new(struct server *server);
void avbtp_mrp_destroy(struct avbtp_mrp *mrp);
#endif /* AVBTP_MRP_H */

View file

@ -0,0 +1,218 @@
/* AVB support
*
* Copyright © 2022 Wim Taymans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <spa/debug/mem.h>
#include <pipewire/pipewire.h>
#include "utils.h"
#include "msrp.h"
static const uint8_t mac[6] = AVB_MSRP_MAC;
struct attr {
struct spa_list link;
struct avbtp_mrp_attribute attr;
uint64_t stream_id;
};
struct msrp {
struct server *server;
struct spa_hook server_listener;
struct spa_list attributes;
};
static struct attr *find_attr_by_stream_id(struct msrp *msrp, uint64_t stream_id)
{
struct attr *a;
spa_list_for_each(a, &msrp->attributes, link)
if (a->stream_id == stream_id)
return a;
return NULL;
}
static void attr_event(struct msrp *msrp, uint8_t type, int event)
{
struct attr *a;
spa_list_for_each(a, &msrp->attributes, link)
if (a->attr.type == type)
avbtp_mrp_update_state(msrp->server->mrp, &a->attr, event, 0);
}
static void process_talker(struct msrp *msrp, uint8_t attr_type,
const void *m, uint8_t event, uint8_t param, int num)
{
const struct avbtp_packet_msrp_talker *t = m;
char buf[128];
struct attr *a;
pw_log_info("talker");
pw_log_info(" %s", avbtp_utils_format_id(buf, sizeof(buf), t->stream_id));
a = find_attr_by_stream_id(msrp, be64toh(t->stream_id));
if (a)
avbtp_mrp_event(msrp->server->mrp, &a->attr, event, param);
}
static void process_talker_fail(struct msrp *msrp, uint8_t attr_type,
const void *m, uint8_t event, uint8_t param, int num)
{
const struct avbtp_packet_msrp_talker_fail *t = m;
char buf[128];
pw_log_info("talker fail");
pw_log_info(" %s", avbtp_utils_format_id(buf, sizeof(buf), t->talker.stream_id));
}
static void process_listener(struct msrp *msrp, uint8_t attr_type,
const void *m, uint8_t event, uint8_t param, int num)
{
const struct avbtp_packet_msrp_listener *l = m;
char buf[128];
pw_log_info("listener");
pw_log_info(" %s", avbtp_utils_format_id(buf, sizeof(buf), l->stream_id));
}
static void process_domain(struct msrp *msrp, uint8_t attr_type,
const void *m, uint8_t event, uint8_t param, int num)
{
const struct avbtp_packet_msrp_domain *d = m;
pw_log_info("domain");
pw_log_info(" %d", d->sr_class_id);
pw_log_info(" %d", d->sr_class_priority);
pw_log_info(" %d", ntohs(d->sr_class_vid));
}
static const struct {
void (*dispatch) (struct msrp *msrp, uint8_t attr_type, const void *m, uint8_t event, uint8_t param, int num);
} dispatch[] = {
[AVBTP_MSRP_ATTRIBUTE_TYPE_TALKER_ADVERTISE] = { process_talker, },
[AVBTP_MSRP_ATTRIBUTE_TYPE_TALKER_FAILED] = { process_talker_fail, },
[AVBTP_MSRP_ATTRIBUTE_TYPE_LISTENER] = { process_listener, },
[AVBTP_MSRP_ATTRIBUTE_TYPE_DOMAIN] = { process_domain, },
};
static inline bool has_params(uint16_t type)
{
return type == AVBTP_MSRP_ATTRIBUTE_TYPE_LISTENER;
}
static int process(struct msrp *msrp, uint64_t now, const void *message, int len)
{
uint8_t *e = SPA_PTROFF(message, len, uint8_t);
uint8_t *m = SPA_PTROFF(message, sizeof(struct avbtp_packet_mrp), uint8_t);
while (m < e && (m[0] != 0 || m[1] != 0)) {
const struct avbtp_packet_msrp_msg *msg = (const struct avbtp_packet_msrp_msg*)m;
uint8_t attr_len = msg->attribute_length;
uint8_t attr_type = msg->attribute_type;
bool has_param = has_params(attr_type);
if (!AVBTP_MSRP_ATTRIBUTE_TYPE_VALID(attr_type))
return -EINVAL;
m += sizeof(*msg);
while (m < e && (m[0] != 0 || m[1] != 0)) {
const struct avbtp_packet_mrp_vector *v =
(const struct avbtp_packet_mrp_vector*)m;
uint16_t i, num_values = AVBTP_MRP_VECTOR_GET_NUM_VALUES(v);
uint8_t event_len = (num_values+2)/3;
uint8_t param_len = has_param ? (num_values+3)/4 : 0;
int len = sizeof(*v) + attr_len + event_len + param_len;
const uint8_t *first = v->first_value;
uint8_t event[3], param[4] = { 0, };
if (m + len > e)
return -EPROTO;
if (v->lva)
attr_event(msrp, attr_type, AVBTP_MRP_EVENT_RX_LVA);
for (i = 0; i < num_values; i++) {
if (i % 3 == 0) {
uint8_t ep = first[attr_len + i/3];
event[2] = ep % 6; ep /= 6;
event[1] = ep % 6; ep /= 6;
event[0] = ep % 6;
}
if (has_param && (i % 4 == 0)) {
uint8_t ep = first[attr_len + event_len + i/4];
param[3] = ep % 4; ep /= 4;
param[2] = ep % 4; ep /= 4;
param[1] = ep % 4; ep /= 4;
param[0] = ep % 4;
}
dispatch[attr_type].dispatch(msrp,
attr_type, first, event[i%3], param[i%4], i);
}
m += len;
}
}
return 0;
}
static int msrp_message(void *data, uint64_t now, const void *message, int len)
{
struct msrp *msrp = data;
const struct avbtp_packet_mrp *p = message;
if (ntohs(p->eth.type) != AVB_MSRP_ETH)
return 0;
if (memcmp(p->eth.dest, mac, 6) != 0)
return 0;
pw_log_info("MSRP");
return process(msrp, now, message, len);
}
static void msrp_destroy(void *data)
{
struct msrp *msrp = data;
spa_hook_remove(&msrp->server_listener);
free(msrp);
}
static const struct server_events server_events = {
AVBTP_VERSION_SERVER_EVENTS,
.destroy = msrp_destroy,
.message = msrp_message
};
int avbtp_msrp_register(struct server *server)
{
struct msrp *msrp;
msrp = calloc(1, sizeof(*msrp));
if (msrp == NULL)
return -errno;
msrp->server = server;
spa_list_init(&msrp->attributes);
avdecc_server_add_listener(server, &msrp->server_listener, &server_events, msrp);
return 0;
}

View file

@ -0,0 +1,109 @@
/* AVB support
*
* Copyright © 2022 Wim Taymans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef AVBTP_MSRP_H
#define AVBTP_MSRP_H
#include "internal.h"
#include "mrp.h"
#define AVB_MSRP_ETH 0x22ea
#define AVB_MSRP_MAC { 0x01, 0x80, 0xc2, 0x00, 0x00, 0xe };
#define AVBTP_MSRP_ATTRIBUTE_TYPE_TALKER_ADVERTISE 1
#define AVBTP_MSRP_ATTRIBUTE_TYPE_TALKER_FAILED 2
#define AVBTP_MSRP_ATTRIBUTE_TYPE_LISTENER 3
#define AVBTP_MSRP_ATTRIBUTE_TYPE_DOMAIN 4
#define AVBTP_MSRP_ATTRIBUTE_TYPE_VALID(t) ((t)>=1 && (t)<=4)
struct avbtp_packet_msrp_msg {
uint8_t attribute_type;
uint8_t attribute_length;
uint16_t attribute_list_length;
uint8_t attribute_list[0];
} __attribute__ ((__packed__));
#define AVBTP_MSRP_TSPEC_MAX_INTERVAL_FRAMES_DEFAULT 1
#define AVBTP_MSRP_RANK_DEFAULT 1
#define AVBTP_MSRP_PRIORITY_DEFAULT 3
struct avbtp_packet_msrp_talker {
uint64_t stream_id;
uint8_t dest_addr[6];
uint16_t vlan_id;
uint16_t tspec_max_frame_size;
uint16_t tspec_max_interval_frames;
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned priority:3;
unsigned rank:1;
unsigned reserved:4;
#elif __BYTE_ORDER == __LITTLE_ENDIAN
unsigned reserved:4;
unsigned rank:1;
unsigned priority:3;
#endif
uint32_t accumulated_latency;
} __attribute__ ((__packed__));
/* failure codes */
#define AVBTP_MRP_FAIL_BANDWIDTH 1
#define AVBTP_MRP_FAIL_BRIDGE 2
#define AVBTP_MRP_FAIL_TC_BANDWIDTH 3
#define AVBTP_MRP_FAIL_ID_BUSY 4
#define AVBTP_MRP_FAIL_DSTADDR_BUSY 5
#define AVBTP_MRP_FAIL_PREEMPTED 6
#define AVBTP_MRP_FAIL_LATENCY_CHNG 7
#define AVBTP_MRP_FAIL_PORT_NOT_AVB 8
#define AVBTP_MRP_FAIL_DSTADDR_FULL 9
#define AVBTP_MRP_FAIL_AVBTP_MRP_RESOURCE 10
#define AVBTP_MRP_FAIL_MMRP_RESOURCE 11
#define AVBTP_MRP_FAIL_DSTADDR_FAIL 12
#define AVBTP_MRP_FAIL_PRIO_NOT_SR 13
#define AVBTP_MRP_FAIL_FRAME_SIZE 14
#define AVBTP_MRP_FAIL_FANIN_EXCEED 15
#define AVBTP_MRP_FAIL_STREAM_CHANGE 16
#define AVBTP_MRP_FAIL_VLAN_BLOCKED 17
#define AVBTP_MRP_FAIL_VLAN_DISABLED 18
#define AVBTP_MRP_FAIL_SR_PRIO_ERR 19
struct avbtp_packet_msrp_talker_fail {
struct avbtp_packet_msrp_talker talker;
uint64_t bridge_id;
uint8_t failure_code;
} __attribute__ ((__packed__));
struct avbtp_packet_msrp_listener {
uint64_t stream_id;
} __attribute__ ((__packed__));
/* domain discovery */
struct avbtp_packet_msrp_domain {
uint8_t sr_class_id;
uint8_t sr_class_priority;
uint16_t sr_class_vid;
} __attribute__ ((__packed__));
int avbtp_msrp_register(struct server *server);
#endif /* AVBTP_MSRP_H */

View file

@ -0,0 +1,76 @@
/* AVB support
*
* Copyright © 2022 Wim Taymans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <pipewire/pipewire.h>
#include "mvrp.h"
static const uint8_t mac[6] = AVB_MVRP_MAC;
struct mvrp {
struct server *server;
struct spa_hook server_listener;
};
static int mvrp_message(void *data, uint64_t now, const void *message, int len)
{
const struct avbtp_packet_mrp *p = message;
if (ntohs(p->eth.type) != AVB_MVRP_ETH)
return 0;
if (memcmp(p->eth.dest, mac, 6) != 0)
return 0;
pw_log_info("MVRP");
return 0;
}
static void mvrp_destroy(void *data)
{
struct mvrp *mvrp = data;
spa_hook_remove(&mvrp->server_listener);
free(mvrp);
}
static const struct server_events server_events = {
AVBTP_VERSION_SERVER_EVENTS,
.destroy = mvrp_destroy,
.message = mvrp_message
};
int avbtp_mvrp_register(struct server *server)
{
struct mvrp *mvrp;
mvrp = calloc(1, sizeof(*mvrp));
if (mvrp == NULL)
return -errno;
mvrp->server = server;
avdecc_server_add_listener(server, &mvrp->server_listener, &server_events, mvrp);
return 0;
}

View file

@ -0,0 +1,42 @@
/* AVB support
*
* Copyright © 2022 Wim Taymans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef AVBTP_MVRP_H
#define AVBTP_MVRP_H
#include "mrp.h"
#include "internal.h"
#define AVB_MVRP_ETH 0x88f5
#define AVB_MVRP_MAC { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x21 };
struct avbtp_packet_mvrp_msg {
uint8_t attribute_type;
uint8_t attribute_length;
uint8_t attribute_list[0];
} __attribute__ ((__packed__));
int avbtp_mvrp_register(struct server *server);
#endif /* AVBTP_MVRP_H */

View file

@ -0,0 +1,59 @@
/* AVB support
*
* Copyright © 2022 Wim Taymans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <pipewire/pipewire.h>
#include "srp.h"
struct srp {
struct server *server;
struct spa_hook server_listener;
};
static void srp_destroy(void *data)
{
struct srp *srp = data;
spa_hook_remove(&srp->server_listener);
free(srp);
}
static const struct server_events server_events = {
AVBTP_VERSION_SERVER_EVENTS,
.destroy = srp_destroy,
};
int avbtp_srp_register(struct server *server)
{
struct srp *srp;
srp = calloc(1, sizeof(*srp));
if (srp == NULL)
return -errno;
srp->server = server;
avdecc_server_add_listener(server, &srp->server_listener, &server_events, srp);
return 0;
}

View file

@ -0,0 +1,32 @@
/* AVB support
*
* Copyright © 2022 Wim Taymans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef AVBTP_SRP_H
#define AVBTP_SRP_H
#include "internal.h"
int avbtp_srp_register(struct server *server);
#endif /* AVBTP_SRP_H */

View file

@ -25,6 +25,8 @@
#ifndef AVBTP_UTILS_H #ifndef AVBTP_UTILS_H
#define AVBTP_UTILS_H #define AVBTP_UTILS_H
#include <spa/utils/json.h>
#include "internal.h" #include "internal.h"
static inline char *avbtp_utils_format_id(char *str, size_t size, const uint64_t id) static inline char *avbtp_utils_format_id(char *str, size_t size, const uint64_t id)