Also known as: P25 site identity, RFSS and site ID semantics
P25 site identity is the pair of identifiers — RFSS ID plus site ID — that a trunking site broadcasts about itself on its control channel. The semantics look obvious and are widely mis-assumed. Every fact below was established the hard way while building GopherTrunk’s site tracking and site API, mostly against a large multi-site network, and each one contradicts a plausible first guess.
A grant’s site is not the radio’s location
On a multisite system, a wide-area talkgroup is granted on every participating site simultaneously — one press of PTT surfaces the same call under multiple site IDs at the same instant. Grant activity is therefore fine for “talkgroup activity by site” metrics and useless for answering “where is this radio.”
What does fix a radio to a site: unit registration and group affiliation are handled by the radio’s actual serving site, so those events are genuine location observations. That is the basis for RID-to-site mobility tracking (#698).
What keys a site — and what doesn’t
- Key on
(rfss_id, site_id)within a system. Nothing weaker works. - The NAC is not a site identifier. On the network where this was measured, roughly 12 NAC values were reused across 70+ sites (#698).
channel_idis a band-plan slot (an Identifier Update table index), not a per-site key — GopherTrunk deliberately omits it from/api/v1/sitesrows.- Voice-channel frequencies do not cluster near their site’s control channel. Nearest-frequency site matching produces wrong answers; resolve channels through the decoded band plan instead.
Network identity is decoded, never configured
A system’s WACN, system ID, RFSS, and site ID
only exist over the air: they arrive in the Network Status Broadcast
(TSBK opcode 0x3B) and RFSS Status Broadcast (0x3A).
GopherTrunk once served /api/v1/systems from the static config copy, so the System
Information panel sat on “Awaiting status broadcasts” forever while the identical decoded
values were already live on /api/v1/sites — the endpoint just never consulted the site
tracker (#673).
Phase 2 TDMA control channels need their own camped-site cache fed by the same two broadcasts, with the Color Code standing in for the NAC as the access code, per spec (#698).
Neighbor lists attach to the camped site
The Adjacent Status Broadcast (opcode 0x3C) carries a neighbor site
list, and the list belongs to the site that broadcast it — the one you are camped on, not the
neighbor. Each entry’s downlink_hz is the neighbor’s control-channel frequency, resolved
through the Identifier Update band plan. This enables passive backfill: sites you have never
directly decoded get their CC frequencies filled in from a neighbor’s advertisements — useful
for roaming (#864).
Hybrid systems: Phase 1 control channel, Phase 2 traffic
Many networks run a Phase 1 FDMA control channel granting Phase 2 TDMA voice channels. Three traps, all hit in the field:
OpIdentifierUpdateTDMA(0x33) must be dispatched. GopherTrunk once handled only the FDMA identifier variants (0x34,0x3D), so grants referencing a TDMA channel ID were black-holed with no band plan. A TDMA channel ID is typically the ×2 twin of an FDMA ID; the frequency-field bit packing matches the VHF/UHF variant (#345).- TDMA-ness must flow into the grant. The Identifier Update TDMA parse sets a per-channel
flag; the band plan’s
IsTDMA(channel_id)decides whether a grant is Phase 2. Until that plumbing existed, every grant was tagged plainp25and the Phase 2 voice chain was dead code (#376). - Real on-air Phase 2 is always PN44-scrambled, with the seed derived from
(WACN, system ID, NAC). GopherTrunk’s
p25_phase2_scrambler_modedefaults toofffor fixture compatibility — leaving it there on a live system decodes nothing (#376).
Symptom table
| Symptom | Looks like | Actually | Fix / check |
|---|---|---|---|
| One PTT appears under several site IDs at once | Duplicate or corrupted grants | Wide-area talkgroup granted on every participating site | Expected; use registration/affiliation for location |
| Two sites treated as one | Dedup bug | Keyed on NAC, which repeats across sites | Key on (rfss_id, site_id) |
| System panel stuck “Awaiting status broadcasts” | No 0x3A/0x3B on air | Endpoint served static config, never the decoded snapshot | Read identity from the live site tracker (#673) |
| Grants black-holed with no matching band plan | Site missing Identifier Updates | TDMA identifier variant (0x33) not dispatched |
Handle all Identifier Update opcodes (#345) |
| Phase 2 voice silent on a Phase-1-CC system | RF or vocoder problem | Grants never tagged Phase 2, or scrambler left off (on-air is always PN44) |
Wire IsTDMA into grants; enable PN44 (#376) |
One more consequence worth internalizing: because site identity is only known after a control channel decodes, anything that must be chosen before lock — such as the demodulator mode — cannot be keyed by RFSS/site and has to be keyed by frequency instead.
Provenance
- #698 — exposing P25 site identity in grants and the API; grant-vs-location, NAC reuse, keying rules.
- #673 — System Information panel stuck because network identity was read from config, not the air.
- #864 — neighbor-site lists (opcode 0x3C) attach to the camped site; passive CC-frequency backfill.
- #376 — hybrid Phase 1 CC / Phase 2 traffic plumbing and the always-PN44 scrambler gotcha.
- #345 — the undispatched TDMA Identifier Update that black-holed grants.