From 893251c8ebab1ce892b50435addd9672113fd7cc Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 22 Mar 2022 19:40:23 +0100 Subject: [PATCH] avb: add beginnings of MRP/MMRP/MSRP/MVRP/SRP --- src/modules/meson.build | 8 +- src/modules/module-avbtp/acmp.c | 33 ++++- src/modules/module-avbtp/adp.c | 15 +- src/modules/module-avbtp/aecp-aem.c | 9 +- src/modules/module-avbtp/aecp.c | 11 +- src/modules/module-avbtp/avdecc.c | 40 ++--- src/modules/module-avbtp/internal.h | 11 +- src/modules/module-avbtp/maap.c | 8 + src/modules/module-avbtp/mmrp.c | 76 ++++++++++ src/modules/module-avbtp/mmrp.h | 42 ++++++ src/modules/module-avbtp/mrp.c | 151 +++++++++++++++++++ src/modules/module-avbtp/mrp.h | 134 +++++++++++++++++ src/modules/module-avbtp/msrp.c | 218 ++++++++++++++++++++++++++++ src/modules/module-avbtp/msrp.h | 109 ++++++++++++++ src/modules/module-avbtp/mvrp.c | 76 ++++++++++ src/modules/module-avbtp/mvrp.h | 42 ++++++ src/modules/module-avbtp/srp.c | 59 ++++++++ src/modules/module-avbtp/srp.h | 32 ++++ src/modules/module-avbtp/utils.h | 2 + 19 files changed, 1034 insertions(+), 42 deletions(-) create mode 100644 src/modules/module-avbtp/mmrp.c create mode 100644 src/modules/module-avbtp/mmrp.h create mode 100644 src/modules/module-avbtp/mrp.c create mode 100644 src/modules/module-avbtp/mrp.h create mode 100644 src/modules/module-avbtp/msrp.c create mode 100644 src/modules/module-avbtp/msrp.h create mode 100644 src/modules/module-avbtp/mvrp.c create mode 100644 src/modules/module-avbtp/mvrp.h create mode 100644 src/modules/module-avbtp/srp.c create mode 100644 src/modules/module-avbtp/srp.h diff --git a/src/modules/meson.build b/src/modules/meson.build index c3c7aea47..c5a926f31 100644 --- a/src/modules/meson.build +++ b/src/modules/meson.build @@ -528,7 +528,13 @@ pipewire_module_avbtp = shared_library('pipewire-module-avbtp', 'module-avbtp/aecp.c', 'module-avbtp/aecp-aem.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], install : true, install_dir : modules_install_dir, diff --git a/src/modules/module-avbtp/acmp.c b/src/modules/module-avbtp/acmp.c index 0d59bc05c..6cfe74d49 100644 --- a/src/modules/module-avbtp/acmp.c +++ b/src/modules/module-avbtp/acmp.c @@ -30,6 +30,8 @@ #include "acmp.h" #include "internal.h" +static const uint8_t mac[6] = AVB_BROADCAST_MAC; + struct pending { struct spa_list link; 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); 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) @@ -113,7 +116,8 @@ static int retry_pending(struct acmp *acmp, uint64_t now, struct pending *p) struct avbtp_packet_acmp *cmd = p->ptr; p->retry++; 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) @@ -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_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) @@ -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); 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); @@ -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_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) @@ -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); 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); @@ -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_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) @@ -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_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) @@ -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) { struct acmp *acmp = data; + struct server *server = acmp->server; const struct avbtp_packet_acmp *p = message; const struct msg_info *info; 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) return 0; diff --git a/src/modules/module-avbtp/adp.c b/src/modules/module-avbtp/adp.c index 5bd27c65a..77f2c095a 100644 --- a/src/modules/module-avbtp/adp.c +++ b/src/modules/module-avbtp/adp.c @@ -31,6 +31,8 @@ #include "internal.h" #include "utils.h" +static const uint8_t mac[6] = AVB_BROADCAST_MAC; + struct entity { struct spa_list link; 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); 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; 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); 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; 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_ADP_SET_MESSAGE_TYPE(&p, AVBTP_ADP_MESSAGE_TYPE_ENTITY_DISCOVER); 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; } static int adp_message(void *data, uint64_t now, const void *message, int len) { struct adp *adp = data; + struct server *server = adp->server; const struct avbtp_packet_adp *p = message; struct entity *e; int message_type; char buf[128]; 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 || AVBTP_PACKET_GET_LENGTH(&p->hdr) < AVBTP_ADP_CONTROL_DATA_LENGTH) return 0; diff --git a/src/modules/module-avbtp/aecp-aem.c b/src/modules/module-avbtp/aecp-aem.c index 947c5d409..923b98625 100644 --- a/src/modules/module-avbtp/aecp-aem.c +++ b/src/modules/module-avbtp/aecp-aem.c @@ -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_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) @@ -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_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 */ @@ -180,7 +182,8 @@ static int handle_get_avb_info(struct aecp *aecp, const void *m, int len) i->flags = 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 */ diff --git a/src/modules/module-avbtp/aecp.c b/src/modules/module-avbtp/aecp.c index 4a1df3534..1f6dba17f 100644 --- a/src/modules/module-avbtp/aecp.c +++ b/src/modules/module-avbtp/aecp.c @@ -31,6 +31,8 @@ #include "aecp-aem.h" #include "internal.h" +static const uint8_t mac[6] = AVB_BROADCAST_MAC; + struct msg_info { uint16_t type; const char *name; @@ -46,7 +48,8 @@ static int reply_not_implemented(struct aecp *aecp, const void *p, int len) memcpy(reply, p, len); 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[] = { @@ -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) { struct aecp *aecp = data; + struct server *server = aecp->server; const struct avbtp_packet_aecp_header *p = message; const struct msg_info *info; 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) return 0; diff --git a/src/modules/module-avbtp/avdecc.c b/src/modules/module-avbtp/avdecc.c index d24b7d95b..e14dd165f 100644 --- a/src/modules/module-avbtp/avdecc.c +++ b/src/modules/module-avbtp/avdecc.c @@ -43,12 +43,13 @@ #include "adp.h" #include "aecp.h" #include "maap.h" +#include "mmrp.h" +#include "msrp.h" +#include "mvrp.h" #include "descriptors.h" #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_destroy(s) server_emit(s, destroy, 0) #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, (int)sizeof(struct avbtp_packet_header)); } 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); 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; int res = 0; memcpy(hdr->dest, dest, 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) { res = -errno; @@ -111,11 +105,6 @@ int avbtp_server_send_packet(struct server *server, const uint8_t dest[6], void 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) { struct impl *impl = server->impl; @@ -193,10 +182,10 @@ static int setup_socket(struct server *server) goto error_close; } value.tv_sec = 0; - value.tv_nsec = 1; + value.tv_nsec = 1; interval.tv_sec = DEFAULT_INTERVAL; - interval.tv_nsec = 0; - pw_loop_update_timer(impl->loop, server->timer, &value, &interval, false); + interval.tv_nsec = 0; + pw_loop_update_timer(impl->loop, server->timer, &value, &interval, false); return 0; @@ -227,8 +216,13 @@ struct server *avdecc_server_new(struct impl *impl, const char *ifname, struct s init_descriptors(server); + server->mrp = avbtp_mrp_new(server); + avbtp_aecp_register(server); avbtp_maap_register(server); + avbtp_mmrp_register(server); + avbtp_msrp_register(server); + avbtp_mvrp_register(server); avbtp_adp_register(server); avbtp_acmp_register(server); @@ -241,10 +235,8 @@ error_free: return NULL; } -void avdecc_server_add_listener(struct server *server, - struct spa_hook *listener, - const struct server_events *events, - void *data) +void avdecc_server_add_listener(struct server *server, struct spa_hook *listener, + const struct server_events *events, void *data) { spa_hook_list_append(&server->listener_list, listener, events, data); } diff --git a/src/modules/module-avbtp/internal.h b/src/modules/module-avbtp/internal.h index 5cf437d98..305fee454 100644 --- a/src/modules/module-avbtp/internal.h +++ b/src/modules/module-avbtp/internal.h @@ -31,6 +31,10 @@ extern "C" { #include +#define AVB_TSN_ETH 0x22f0 +#define AVB_BROADCAST_MAC { 0x91, 0xe0, 0xf0, 0x01, 0x00, 0x00 }; + + struct impl { struct pw_loop *loop; struct pw_context *context; @@ -64,6 +68,7 @@ struct descriptor { void *ptr; }; + struct server { struct spa_list link; struct impl *impl; @@ -81,6 +86,8 @@ struct server { struct spa_list descriptors; unsigned debug_messages:1; + + struct avbtp_mrp *mrp; }; 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, 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], 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 aecp { struct server *server; diff --git a/src/modules/module-avbtp/maap.c b/src/modules/module-avbtp/maap.c index c17edb19f..979e27f73 100644 --- a/src/modules/module-avbtp/maap.c +++ b/src/modules/module-avbtp/maap.c @@ -26,6 +26,8 @@ #include "maap.h" +static const uint8_t mac[6] = AVB_BROADCAST_MAC; + struct maap { struct server *server; 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) { struct maap *maap = data; + struct server *server = maap->server; 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) return 0; diff --git a/src/modules/module-avbtp/mmrp.c b/src/modules/module-avbtp/mmrp.c new file mode 100644 index 000000000..6b48f1b8c --- /dev/null +++ b/src/modules/module-avbtp/mmrp.c @@ -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 + +#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; +} diff --git a/src/modules/module-avbtp/mmrp.h b/src/modules/module-avbtp/mmrp.h new file mode 100644 index 000000000..14a4aa5c8 --- /dev/null +++ b/src/modules/module-avbtp/mmrp.h @@ -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 */ diff --git a/src/modules/module-avbtp/mrp.c b/src/modules/module-avbtp/mrp.c new file mode 100644 index 000000000..2cb892e2e --- /dev/null +++ b/src/modules/module-avbtp/mrp.c @@ -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 + +#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; +} diff --git a/src/modules/module-avbtp/mrp.h b/src/modules/module-avbtp/mrp.h new file mode 100644 index 000000000..184ce898c --- /dev/null +++ b/src/modules/module-avbtp/mrp.h @@ -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 */ diff --git a/src/modules/module-avbtp/msrp.c b/src/modules/module-avbtp/msrp.c new file mode 100644 index 000000000..410a7c71f --- /dev/null +++ b/src/modules/module-avbtp/msrp.c @@ -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 + +#include + +#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; +} diff --git a/src/modules/module-avbtp/msrp.h b/src/modules/module-avbtp/msrp.h new file mode 100644 index 000000000..977c1dcc9 --- /dev/null +++ b/src/modules/module-avbtp/msrp.h @@ -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 */ diff --git a/src/modules/module-avbtp/mvrp.c b/src/modules/module-avbtp/mvrp.c new file mode 100644 index 000000000..a7f7c5ac6 --- /dev/null +++ b/src/modules/module-avbtp/mvrp.c @@ -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 + +#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; +} diff --git a/src/modules/module-avbtp/mvrp.h b/src/modules/module-avbtp/mvrp.h new file mode 100644 index 000000000..63bab9efb --- /dev/null +++ b/src/modules/module-avbtp/mvrp.h @@ -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 */ diff --git a/src/modules/module-avbtp/srp.c b/src/modules/module-avbtp/srp.c new file mode 100644 index 000000000..867c96f53 --- /dev/null +++ b/src/modules/module-avbtp/srp.c @@ -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 + +#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; +} diff --git a/src/modules/module-avbtp/srp.h b/src/modules/module-avbtp/srp.h new file mode 100644 index 000000000..131385785 --- /dev/null +++ b/src/modules/module-avbtp/srp.h @@ -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 */ diff --git a/src/modules/module-avbtp/utils.h b/src/modules/module-avbtp/utils.h index ba6fde7ec..adbf3ea3f 100644 --- a/src/modules/module-avbtp/utils.h +++ b/src/modules/module-avbtp/utils.h @@ -25,6 +25,8 @@ #ifndef AVBTP_UTILS_H #define AVBTP_UTILS_H +#include + #include "internal.h" static inline char *avbtp_utils_format_id(char *str, size_t size, const uint64_t id)