NXDN Reflector Protocol
Vexillum’s NXDN mode is a minimal reflector protocol: a client polls with a talkgroup, and the reflector accepts or ignores it depending on whether that talkgroup matches its own configuration. There is no authentication and no per-module partitioning - every accepted session shares one talkgroup and one active stream.
Status
Section titled “Status”| Field | Value |
|---|---|
| Transport | UDP only |
| Default listen port | 41400 |
| Authentication | None |
| Default talkgroup | 61000 |
Design overview
Section titled “Design overview”A client should handle:
NXDNPpoll, gated by matching talkgroupNXDNUdisconnect, also gated by matching talkgroupNXDNDfixed-size data frames, with group-call and stream-end flag bits- A single shared stream per reflector instance - there is no module concept
Packet format
Section titled “Packet format”All integer fields are big-endian. Tags are 5-byte ASCII.
| Tag | Length | Layout | Purpose |
|---|---|---|---|
NXDNP |
17 |
[0:5] tag NXDNP, [5:15] callsign (10 bytes), [15:17] talkgroup (u16) |
Poll / login |
NXDNU |
17 |
[0:5] tag NXDNU, [5:15] callsign (10 bytes), [15:17] talkgroup (u16) |
Disconnect |
NXDND |
43 |
[0:5] tag NXDND, [5:7] source ID (u16), [7:9] destination ID (u16), [9] flags, [9:43] rest of frame |
Data frame |
NXDND flags byte
Section titled “NXDND flags byte”| Bit | Mask | Meaning |
|---|---|---|
0 |
0x01 |
Group call |
3 |
0x08 |
Stream end |
Byte offset 9 of the frame carries both bits. The remaining 33 bytes (offsets
9-42, flags byte included) are forwarded to other sessions verbatim.
Talkgroup gating
Section titled “Talkgroup gating”Every NXDNP poll, NXDNU disconnect, and NXDND data frame carries a
talkgroup or destination ID. The reflector only acts on a packet whose
talkgroup/destination matches its own single configured talkgroup:
- A poll or disconnect whose talkgroup doesn’t match the reflector’s configured talkgroup is silently ignored - no session is created, no acknowledgment is sent, and (for disconnect) no session is removed.
- A data frame is only forwarded if its destination ID equals the configured talkgroup and the group-call flag bit is set. A frame that fails either check is dropped without forwarding, even from an already-polled session.
There is exactly one talkgroup per reflector instance - unlike DMR, there’s no concept of switching talkgroups mid-session.
Session behavior
Section titled “Session behavior”| Parameter | Value |
|---|---|
| Session timeout | 120 seconds |
| Cleanup tick interval | 30 seconds |
| Stream idle timeout | 3 seconds |
| Session cap | 4096 |
Follows the general session/stream lifecycle described in the reference overview.
Single shared stream
Section titled “Single shared stream”Unlike DMR or M17, which partition streams per module, Vexillum’s NXDN reflector admits one active stream across the entire instance, regardless of talkgroup or sender. The first sender to have a group-call data frame accepted holds the stream exclusively until it ends explicitly or goes idle for 3 seconds; every other sender’s data frames are dropped in the meantime, even though they all share the same single configured talkgroup anyway.
Session handshake
Section titled “Session handshake”The reflector only replies if the poll’s talkgroup matches its configured talkgroup. Unlike YSF’s poll acknowledgment, NXDN’s ack echoes back the exact callsign and talkgroup the client sent - not the reflector’s own identity.
Stream behavior and ending a transmission
Section titled “Stream behavior and ending a transmission”- The first accepted
NXDNDgroup-call frame (destination matches the configured talkgroup) opens the reflector’s single active stream. - While a stream is active, only frames from that same sender are forwarded.
- A stream ends when a frame’s flags byte has bit
0x08set, or when the stream is idle for 3 seconds. - Accepted frames are forwarded verbatim to every other polled session, regardless of that session’s own talkgroup value (since all sessions share the reflector’s one configured talkgroup by construction).
Minimal client state machine
Section titled “Minimal client state machine”Terminal conditions: transport failure, session timeout (120 seconds without
traffic), inbound NXDNU, or user shutdown.
Common implementation mistakes
Section titled “Common implementation mistakes”Using the wrong talkgroup
Section titled “Using the wrong talkgroup”If a poll’s talkgroup doesn’t exactly match the reflector’s configured value, the reflector does nothing - no ack, no error, no log line visible to the client. A client that doesn’t hear back from a poll should double-check its configured talkgroup before assuming a network problem.
Forgetting the group-call flag bit
Section titled “Forgetting the group-call flag bit”A data frame with the correct destination ID but without bit 0x01 set in its
flags byte is dropped, even from a session that has already successfully polled.
Assuming per-talkgroup stream isolation
Section titled “Assuming per-talkgroup stream isolation”Because there’s only one talkgroup per instance, there’s also only one stream. Don’t design a client assuming it can run two independent conversations against a single NXDN instance.
Example packet values
Section titled “Example packet values”A poll for callsign W1AW, talkgroup 65000:
| Field | Value |
|---|---|
| Tag | NXDNP |
| Callsign | W1AW······ (space-padded to 10) |
| Talkgroup | 65000 (bytes 0xFD 0xE8) |
A data frame, source 100, destination 65000, group call:
| Field | Value |
|---|---|
| Tag | NXDND |
| Source ID | 100 (bytes 0x00 0x64) |
| Destination ID | 65000 (bytes 0xFD 0xE8) |
| Flags | 0x01 (group call) |
Relationship to Vexillum
Section titled “Relationship to Vexillum”NXDN is implemented as a Vexillum mode runtime (internal/modes/nxdn). The tag
names and general shape borrow NXDN terminology, but the wire format, session
model, and single-stream-per-instance behavior are entirely Vexillum-specific.
Current limitations
Section titled “Current limitations”- One talkgroup per reflector instance.
- One active stream reflector-wide, not per-talkgroup or per-module.
- No authentication.
- No real NXDN frame structure (ICV, RAN, or channel access parsing) - data frames are opaque payload beyond the flags byte.
Development recommendations
Section titled “Development recommendations”- Confirm your poll’s talkgroup exactly matches the reflector’s configured talkgroup before debugging anything else.
- Implement
NXDNPpoll and acknowledgment. - Implement
NXDNDdata forwarding, including the group-call and stream-end flag bits. - Add
NXDNUdisconnect. - Test against a running Vexillum NXDN instance before assuming compatibility with real NXDN infrastructure.