feat(sacn): E1.31-Pakete pruefen und zerlegen

This commit is contained in:
Michael Sauer
2026-09-19 23:44:55 +02:00
parent 71a579c0f9
commit cdbbe31831
5 changed files with 286 additions and 0 deletions
+57
View File
@@ -0,0 +1,57 @@
#include "net/nl_e131.h"
#include <string.h>
static uint16_t be16(const uint8_t *p) { return (uint16_t)(((uint16_t)p[0] << 8) | p[1]); }
static uint32_t be32(const uint8_t *p)
{
return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | p[3];
}
/* Flags (obere 4 Bit) muessen 0x7 sein, die Laenge (untere 12 Bit) muss exakt den Rest des
* Datagramms ab `from` beschreiben. Ein Paket, dessen Laengenfelder nicht zueinander passen,
* ist entweder verstuemmelt oder ein Angriffsversuch - in beiden Faellen: weg damit. */
static bool pdu_len_ok(const uint8_t *p, size_t len, size_t from)
{
uint16_t fl = be16(p + from);
if ((fl & 0xf000u) != 0x7000u)
return false;
return (size_t)(fl & 0x0fffu) == len - from;
}
bool nl_e131_parse(const uint8_t *buf, size_t len, nl_e131_packet_t *out)
{
static const uint8_t acn_pid[12] = { 'A', 'S', 'C', '-', 'E', '1', '.', '1', '7', 0, 0, 0 };
uint16_t pvc;
if (len < NL_E131_MIN_PACKET || len > NL_E131_MIN_PACKET + 512u)
return false;
if (be16(buf) != 0x0010u || be16(buf + 2) != 0x0000u)
return false;
if (memcmp(buf + 4, acn_pid, sizeof acn_pid) != 0)
return false;
if (!pdu_len_ok(buf, len, 16) || be32(buf + 18) != 0x00000004u)
return false;
if (!pdu_len_ok(buf, len, 38) || be32(buf + 40) != 0x00000002u)
return false;
if (!pdu_len_ok(buf, len, 115) || buf[117] != 0x02u)
return false;
if (buf[118] != 0xa1u || be16(buf + 119) != 0x0000u || be16(buf + 121) != 0x0001u)
return false;
pvc = be16(buf + 123);
if (pvc < 1u || (size_t)(pvc - 1u) != len - NL_E131_MIN_PACKET)
return false;
if (buf[125] != 0x00u) /* nur Start-Code 0 ist Lichtinhalt (0xdd waere Kanalprioritaet) */
return false;
if (buf[112] & 0x80u) /* Preview-Daten duerfen laut E1.31 nicht ausgegeben werden */
return false;
out->universe = be16(buf + 113);
out->priority = buf[108];
out->sequence = buf[111];
out->terminated = (buf[112] & 0x40u) != 0u;
out->slot_count = (uint16_t)(pvc - 1u);
out->slots = buf + NL_E131_MIN_PACKET;
return true;
}
+26
View File
@@ -0,0 +1,26 @@
#ifndef NL_E131_H
#define NL_E131_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define NL_E131_PORT 5568u
#define NL_E131_MAX_PACKET 640u /* ein volles Paket ist 638 Byte; 640 laesst Luft zum Erkennen
* ueberlanger Datagramme, ohne den Puffer unnoetig aufzublaehen */
#define NL_E131_MIN_PACKET 126u
typedef struct {
uint16_t universe;
uint8_t priority;
uint8_t sequence;
bool terminated; /* Options-Bit "stream terminated" */
uint16_t slot_count; /* Nutzdaten ohne Start-Code, 0..512 */
const uint8_t *slots; /* zeigt in den uebergebenen Puffer, wird nicht kopiert */
} nl_e131_packet_t;
/* true = gueltiges DMX-Datenpaket (Start-Code 0, kein Preview). Alles andere: false.
* `out` wird nur bei true beschrieben. */
bool nl_e131_parse(const uint8_t *buf, size_t len, nl_e131_packet_t *out);
#endif