feat(sacn): E1.31-Pakete pruefen und zerlegen
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user