_master_datagram_received and _peer_datagram_received each carried the same
32 lines: global SUB_ACL, the TG list for the frame's slot, then the system's
own three, every rejection logging once per stream through _laststrid. The two
copies were identical down to the wording of the six log messages, so a fix in
one could silently miss the other.
They now call _acl_rejects_dmrd, which keeps the legacy order, the same
messages and the same once-per-stream guard, and reads the TG list as
TG{slot}_ACL instead of spelling out slot 1 and slot 2. The frame's slot is
always 1 or 2 (it comes from bit 0x80), so no branch is lost.
tests/hbp/test_acl_gate.py covers both paths, the per-slot TG list and the
on-demand unit-service exemption; three of its four tests pass unchanged
against the previous code.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dedupe the INFO line when a peer keys into a busy TG during an active QSO,
bind RX_STREAM_ID on silent activation to avoid per-frame re-entry, and
clear the dedupe marker on suppressed-stream VTERM.
* fix: raise UDP SO_RCVBUF on voice listeners (C-LOCAL)
Apply a 4 MB receive buffer on system and proxy UDP sockets to reduce
kernel RcvbufErrors under OBP load; size is configurable via GLOBAL.UDP_RCVBUF.
* fix: exclude byte-identical duplicates from HBP rate counter (A.2)
Check lastData before incrementing the ingress packet counter so compressed
duplicate bursts do not trigger legitimate RATE DROP on call start.
* fix: duplicate-safe TA embed phase and REPEAT VHEAD DMRA (B)
Ignore byte-identical B-E embed bursts so duplicate uplinks do not desync the
TA phase machine, and re-emit DMRA on every VHEAD on the REPEAT path.
* chore: document echo point-to-point and logged_in reconciliation (EN/ES)
Document multi-hotspot echo/service delivery via RX_PEER, the lst_seen
logged_in reconcile loop, and cross-links between user and dev guides.
Enforce one active group QSO per peer/slot (SINGLE=0 and SINGLE=1) at the
downlink layer instead of treating the shared MASTER STATUS[slot] as a single
RF slot. Concurrent streams from different hotspots to different TGs are now
legitimate on ingress; contention is decided per-peer.
- Ingress: hbp_ingress_new_stream_collision honours per_peer=True so a second
hotspot is not silenced by the first; hbp_master_ingress_repeat_allowed
applies the same multi-hotspot rule and always passes VTERMs so listener
sessions close and mid-call join works.
- Silent activation: TX onto a TG with an active QSO activates the TG
dynamically, suppresses the uplink, and delivers the in-progress QSO
downlink. Only a TG in GROUP_HANGTIME (no live stream) is rejected.
- Downlink: peer_voice_slots tracks one listen TG per peer/slot with
GROUP_HANGTIME and bridge-hold semantics; stale sessions expire after
STREAM_TO; duplex slots stay independent.
- Non-regression tests for slot contention, silent activation, stale session
expiry, and duplex independence.
Introduce downlink.py as the single authority for hotspot eligibility (OPTIONS,
slot busy, post-TX GROUP_HANGTIME). send_peer and BRDG fan-out share the same
gate; monitor events carry stream id from BRDG so new QSOs after hangtime
display without replaying calls blocked during the hangtime window.
Planned release: 2.2.0
Normalize all Python sources to the standard ADN copyright block with
complete GPLv3 notice. Add legacy attribution on routing and dmr_utils
ports; drop SemVer wording from changelog and fix an unused test import.
Replace internal bridge terminology with routing (RoutingUseCases, AclRouter,
routing_table export). SubscriptionStore remains runtime authority with O(1)
indexes for router and downlink filters. Fix STATIC TG parity on OPTIONS/RPTO,
parrot in-band edge cases, and remove per-packet routing_table export from the
hot path that caused high CPU under multi-hotspot OBP load.