Also known as: HDU, header data unit, P25 voice header
The P25 Header Data Unit (HDU, DUID 0x0) is the frame that
opens a P25 Phase 1 voice transmission, sent once before the stream of
LDU voice frames begins.1 Its job is setup: it
carries the 72-bit Message Indicator (the cryptographic initialisation vector) together with
the algorithm, key, and talkgroup identifiers a receiver needs to prepare decryption before
the first voice frame arrives. The whole payload is protected by an inner
Golay code and an outer RS(36,20,17)
Reed-Solomon code.
How it works
After the frame sync and NID, the HDU’s information field is 120 bits, which map exactly onto the 20 six-bit information symbols of the outer RS code:
| Field | Bits | Purpose |
|---|---|---|
| Message Indicator (MI) | 72 | Crypto initialisation vector / keystream sync |
| Manufacturer ID (MFID) | 8 | Vendor namespace |
| Algorithm ID (ALGID) | 8 | Encryption algorithm (0x80 = clear/unencrypted) |
| Key ID (KID) | 16 | Which key within the algorithm |
| Talkgroup ID (TGID) | 16 | Destination talkgroup |
Those 20 symbols are encoded to a 36-symbol RS(36,20,17) codeword — able to correct up to 8 symbol errors — and each symbol is then wrapped in an inner shortened Golay codeword and interleaved for transmission. On receive the chain reverses: Golay-decode each inner codeword, reassemble the 36 RS symbols, and RS-decode to recover the 20 information symbols. The MI and ALGID/KID together tell the receiver whether the following voice is encrypted and, if so, how to initialise the keystream; a clear-mode HDU (ALGID 0x80) simply announces the talkgroup.
In practice
The HDU is a convenience, not a necessity, for a scanner. The same talkgroup and encryption identifiers reappear inside every LDU2’s Encryption Sync field throughout the call, so a decoder that tunes in mid-transmission — having missed the one-shot header — still recovers them. What the HDU adds is early setup: a receiver that catches it can begin decryption from the very first voice frame rather than waiting for the next LDU2.
GopherTrunk today implements the HDU’s protecting code — the RS(36,20,17) encoder, verifier, and corrector in the framing package — but does not yet have a dedicated HDU frame parser that strips the inner Golay layer, reassembles the payload, and surfaces the MI/ALGID/ KID/TGID fields. The outer FEC primitive is in place and round-trip tested; consuming a full on-air HDU frame is the remaining gap.
Relevance to SDR
The RS(36,20,17) support lives in internal/radio/framing/rs_gf64.go alongside the Link Control
and Encryption Sync codes, sharing the same GF(2⁶) field and Berlekamp-Massey / Chien / Forney
decoder. Because GopherTrunk reads the same encryption metadata from each call’s LDU2
Encryption Sync fields, missing the HDU parser does not lose
information over the life of a call — but a dedicated HDU parser would let the decoder report a
call’s algorithm and talkgroup from its opening frame instead of waiting for the first LDU2.
Sources
-
Project 25 — Wikipedia, on the P25 standard and its Phase 1 data units. ↩