mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	avb: add beginnings of MRP/MMRP/MSRP/MVRP/SRP
This commit is contained in:
		
							parent
							
								
									911378651b
								
							
						
					
					
						commit
						893251c8eb
					
				
					 19 changed files with 1034 additions and 42 deletions
				
			
		| 
						 | 
					@ -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,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										76
									
								
								src/modules/module-avbtp/mmrp.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								src/modules/module-avbtp/mmrp.c
									
										
									
									
									
										Normal 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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										42
									
								
								src/modules/module-avbtp/mmrp.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/modules/module-avbtp/mmrp.h
									
										
									
									
									
										Normal 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 */
 | 
				
			||||||
							
								
								
									
										151
									
								
								src/modules/module-avbtp/mrp.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								src/modules/module-avbtp/mrp.c
									
										
									
									
									
										Normal 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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										134
									
								
								src/modules/module-avbtp/mrp.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								src/modules/module-avbtp/mrp.h
									
										
									
									
									
										Normal 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 */
 | 
				
			||||||
							
								
								
									
										218
									
								
								src/modules/module-avbtp/msrp.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										218
									
								
								src/modules/module-avbtp/msrp.c
									
										
									
									
									
										Normal 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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										109
									
								
								src/modules/module-avbtp/msrp.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								src/modules/module-avbtp/msrp.h
									
										
									
									
									
										Normal 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 */
 | 
				
			||||||
							
								
								
									
										76
									
								
								src/modules/module-avbtp/mvrp.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								src/modules/module-avbtp/mvrp.c
									
										
									
									
									
										Normal 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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										42
									
								
								src/modules/module-avbtp/mvrp.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/modules/module-avbtp/mvrp.h
									
										
									
									
									
										Normal 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 */
 | 
				
			||||||
							
								
								
									
										59
									
								
								src/modules/module-avbtp/srp.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/modules/module-avbtp/srp.c
									
										
									
									
									
										Normal 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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										32
									
								
								src/modules/module-avbtp/srp.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/modules/module-avbtp/srp.h
									
										
									
									
									
										Normal 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 */
 | 
				
			||||||
| 
						 | 
					@ -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)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue