mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-04-30 06:46:49 -04:00
150 lines
3.7 KiB
C
150 lines
3.7 KiB
C
|
|
/* AVB support */
|
||
|
|
/* SPDX-FileCopyrightText: Copyright © 2026 PipeWire contributors */
|
||
|
|
/* SPDX-License-Identifier: MIT */
|
||
|
|
|
||
|
|
#ifndef AVB_TRANSPORT_LOOPBACK_H
|
||
|
|
#define AVB_TRANSPORT_LOOPBACK_H
|
||
|
|
|
||
|
|
#include <string.h>
|
||
|
|
#include <errno.h>
|
||
|
|
#include <fcntl.h>
|
||
|
|
#include <unistd.h>
|
||
|
|
#include <sys/eventfd.h>
|
||
|
|
|
||
|
|
#include "internal.h"
|
||
|
|
#include "packets.h"
|
||
|
|
|
||
|
|
#define AVB_LOOPBACK_MAX_PACKETS 64
|
||
|
|
#define AVB_LOOPBACK_MAX_PACKET_SIZE 2048
|
||
|
|
|
||
|
|
struct avb_loopback_packet {
|
||
|
|
uint8_t dest[6];
|
||
|
|
uint16_t type;
|
||
|
|
size_t size;
|
||
|
|
uint8_t data[AVB_LOOPBACK_MAX_PACKET_SIZE];
|
||
|
|
};
|
||
|
|
|
||
|
|
struct avb_loopback_transport {
|
||
|
|
struct avb_loopback_packet packets[AVB_LOOPBACK_MAX_PACKETS];
|
||
|
|
int packet_count;
|
||
|
|
int packet_read;
|
||
|
|
};
|
||
|
|
|
||
|
|
static inline int avb_loopback_setup(struct server *server)
|
||
|
|
{
|
||
|
|
struct avb_loopback_transport *t;
|
||
|
|
static const uint8_t test_mac[6] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x01 };
|
||
|
|
|
||
|
|
t = calloc(1, sizeof(*t));
|
||
|
|
if (t == NULL)
|
||
|
|
return -errno;
|
||
|
|
|
||
|
|
server->transport_data = t;
|
||
|
|
|
||
|
|
memcpy(server->mac_addr, test_mac, 6);
|
||
|
|
server->ifindex = 1;
|
||
|
|
server->entity_id = (uint64_t)server->mac_addr[0] << 56 |
|
||
|
|
(uint64_t)server->mac_addr[1] << 48 |
|
||
|
|
(uint64_t)server->mac_addr[2] << 40 |
|
||
|
|
(uint64_t)0xff << 32 |
|
||
|
|
(uint64_t)0xfe << 24 |
|
||
|
|
(uint64_t)server->mac_addr[3] << 16 |
|
||
|
|
(uint64_t)server->mac_addr[4] << 8 |
|
||
|
|
(uint64_t)server->mac_addr[5];
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static inline int avb_loopback_send_packet(struct server *server,
|
||
|
|
const uint8_t dest[6], uint16_t type, void *data, size_t size)
|
||
|
|
{
|
||
|
|
struct avb_loopback_transport *t = server->transport_data;
|
||
|
|
struct avb_loopback_packet *pkt;
|
||
|
|
struct avb_ethernet_header *hdr = (struct avb_ethernet_header*)data;
|
||
|
|
|
||
|
|
if (t->packet_count >= AVB_LOOPBACK_MAX_PACKETS)
|
||
|
|
return -ENOSPC;
|
||
|
|
if (size > AVB_LOOPBACK_MAX_PACKET_SIZE)
|
||
|
|
return -EMSGSIZE;
|
||
|
|
|
||
|
|
/* Fill in the ethernet header like the raw transport does */
|
||
|
|
memcpy(hdr->dest, dest, 6);
|
||
|
|
memcpy(hdr->src, server->mac_addr, 6);
|
||
|
|
hdr->type = htons(type);
|
||
|
|
|
||
|
|
pkt = &t->packets[t->packet_count % AVB_LOOPBACK_MAX_PACKETS];
|
||
|
|
memcpy(pkt->dest, dest, 6);
|
||
|
|
pkt->type = type;
|
||
|
|
pkt->size = size;
|
||
|
|
memcpy(pkt->data, data, size);
|
||
|
|
t->packet_count++;
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Return a dummy fd for protocol handlers that create their own sockets.
|
||
|
|
* Uses eventfd so pw_loop_add_io() has a valid fd to work with.
|
||
|
|
*/
|
||
|
|
static inline int avb_loopback_make_socket(struct server *server,
|
||
|
|
uint16_t type, const uint8_t mac[6])
|
||
|
|
{
|
||
|
|
int fd;
|
||
|
|
|
||
|
|
fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
|
||
|
|
if (fd < 0)
|
||
|
|
return -errno;
|
||
|
|
|
||
|
|
return fd;
|
||
|
|
}
|
||
|
|
|
||
|
|
static inline void avb_loopback_destroy(struct server *server)
|
||
|
|
{
|
||
|
|
free(server->transport_data);
|
||
|
|
server->transport_data = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
static const struct avb_transport_ops avb_transport_loopback = {
|
||
|
|
.setup = avb_loopback_setup,
|
||
|
|
.send_packet = avb_loopback_send_packet,
|
||
|
|
.make_socket = avb_loopback_make_socket,
|
||
|
|
.destroy = avb_loopback_destroy,
|
||
|
|
};
|
||
|
|
|
||
|
|
/** Get the number of captured sent packets */
|
||
|
|
static inline int avb_loopback_get_packet_count(struct server *server)
|
||
|
|
{
|
||
|
|
struct avb_loopback_transport *t = server->transport_data;
|
||
|
|
return t->packet_count - t->packet_read;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Read the next captured sent packet, returns packet size or -1 */
|
||
|
|
static inline int avb_loopback_get_packet(struct server *server,
|
||
|
|
void *buf, size_t bufsize)
|
||
|
|
{
|
||
|
|
struct avb_loopback_transport *t = server->transport_data;
|
||
|
|
struct avb_loopback_packet *pkt;
|
||
|
|
|
||
|
|
if (t->packet_read >= t->packet_count)
|
||
|
|
return -1;
|
||
|
|
|
||
|
|
pkt = &t->packets[t->packet_read % AVB_LOOPBACK_MAX_PACKETS];
|
||
|
|
t->packet_read++;
|
||
|
|
|
||
|
|
if (pkt->size > bufsize)
|
||
|
|
return -1;
|
||
|
|
|
||
|
|
memcpy(buf, pkt->data, pkt->size);
|
||
|
|
return pkt->size;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Clear all captured packets */
|
||
|
|
static inline void avb_loopback_clear_packets(struct server *server)
|
||
|
|
{
|
||
|
|
struct avb_loopback_transport *t = server->transport_data;
|
||
|
|
t->packet_count = 0;
|
||
|
|
t->packet_read = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif /* AVB_TRANSPORT_LOOPBACK_H */
|