mirror of
https://github.com/n0mjs710/dmrlink3
synced 2026-11-08 04:19:24 +00:00
- const.py: add ID_MIN, ID_MAX, PEER_MAX constants - config.py: port merge_ranges(), acl_build(), acl_check(), process_acls() from hblink3; parse USE_ACL/SUB_ACL in [GLOBAL] and REG_ACL per system - dmrlink.py: import acl_check; gate master_reg_req() with per-system REG_ACL - bridge.py: remove old file-based build_acl() and allow_sub closure; remove -s/--sub-acl CLI arg; call process_acls(CONFIG); use acl_check() with global SUB_ACL in group_voice() - dmrlink-SAMPLE.cfg: document and add USE_ACL, SUB_ACL, REG_ACL entries ACL semantics: REG_ACL is per-master-system (ignored on peers, which cannot control who registers on their upstream master); SUB_ACL is global and gates source IDs from propagating through the bridge. No TGID ACLs — bridge rules already control TGID propagation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
146 lines
5.4 KiB
Python
146 lines
5.4 KiB
Python
#!/usr/bin/env python
|
|
#
|
|
###############################################################################
|
|
# Copyright (C) 2013-2026 Cortney T. Buffington, N0MJS <n0mjs@me.com>
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software Foundation,
|
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
###############################################################################
|
|
|
|
# IPSC Protocol Constants and Bitmasks -- merged from ipsc_const.py and ipsc_mask.py
|
|
|
|
# Known IPSC Message Types
|
|
CALL_CONFIRMATION = b'\x05'
|
|
TXT_MESSAGE_ACK = b'\x54'
|
|
CALL_MON_STATUS = b'\x61'
|
|
CALL_MON_RPT = b'\x62'
|
|
REPEATER_BLOCKED = b'\x63' # signal interference / BSI blocking event
|
|
XCMP_XNL = b'\x70'
|
|
GROUP_VOICE = b'\x80'
|
|
PVT_VOICE = b'\x81'
|
|
GROUP_DATA = b'\x83'
|
|
PVT_DATA = b'\x84'
|
|
RPT_WAKE_UP = b'\x85'
|
|
CALL_INTERRUPT_REQ = b'\x86' # call interrupt request
|
|
MASTER_REG_REQ = b'\x90'
|
|
MASTER_REG_REPLY = b'\x91'
|
|
PEER_LIST_REQ = b'\x92'
|
|
PEER_LIST_REPLY = b'\x93'
|
|
PEER_REG_REQ = b'\x94'
|
|
PEER_REG_REPLY = b'\x95'
|
|
MASTER_ALIVE_REQ = b'\x96'
|
|
MASTER_ALIVE_REPLY = b'\x97'
|
|
PEER_ALIVE_REQ = b'\x98'
|
|
PEER_ALIVE_REPLY = b'\x99'
|
|
DE_REG_REQ = b'\x9A'
|
|
DE_REG_REPLY = b'\x9B'
|
|
SYSTEM_MAP_REQ = b'\x9C' # system topology query; purpose not fully known
|
|
SYSTEM_MAP_REPLY = b'\x9D'
|
|
UNKNOWN_9E = b'\x9E' # possibly extended peer registration
|
|
WIRELINE = b'\xB2' # MNIS data sub-protocol
|
|
REMOTE_PROG_REQ = b'\xE0' # CPS remote programming session request
|
|
REMOTE_PROG_REPLY = b'\xE1'
|
|
OPCODE_0xF0 = b'\xF0' # observed, benign, no response needed
|
|
|
|
# IPSC Version Information
|
|
IPSC_VER_14 = b'\x00'
|
|
IPSC_VER_15 = b'\x00'
|
|
IPSC_VER_15A = b'\x00'
|
|
IPSC_VER_16 = b'\x01'
|
|
IPSC_VER_17 = b'\x02'
|
|
IPSC_VER_18 = b'\x02'
|
|
IPSC_VER_19 = b'\x03'
|
|
IPSC_VER_22 = b'\x04'
|
|
|
|
LINK_TYPE_IPSC = b'\x04'
|
|
|
|
# IPSC Version field used in registration packets
|
|
IPSC_VER = LINK_TYPE_IPSC + IPSC_VER_17 + LINK_TYPE_IPSC + IPSC_VER_16
|
|
|
|
# GROUP_VOICE burst type byte values (data[GV_BURST_TYPE_OFF] returns int in Python 3)
|
|
VOICE_HEAD = 0x01
|
|
VOICE_TERM = 0x02
|
|
SLOT1_VOICE = 0x0A
|
|
SLOT2_VOICE = 0x8A
|
|
|
|
# GROUP_VOICE packet field offsets
|
|
GV_CALL_INFO_OFF = 17 # timeslot/end flags byte
|
|
GV_RTP_TS_OFF = 22 # 4-byte RTP timestamp (8 kHz clock, +480 per burst)
|
|
GV_BURST_TYPE_OFF = 30 # burst type byte (see VOICE_HEAD / SLOT1_VOICE etc.)
|
|
GV_BE_FLAG = 0x16 # data[32] value that identifies a burst-E superframe
|
|
GV_BE_LC_FLCO_OFF = 56 # FLCO field within burst-E embedded LC
|
|
GV_MIN_LEN = 33 # minimum valid GROUP_VOICE packet length
|
|
FLCO_GROUP = 0x00 # FLCO value for a group voice call (not Talker Alias)
|
|
|
|
# Packet type membership lists
|
|
ANY_PEER_REQUIRED = [GROUP_VOICE, PVT_VOICE, GROUP_DATA, PVT_DATA, CALL_MON_STATUS,
|
|
CALL_MON_RPT, REPEATER_BLOCKED, CALL_INTERRUPT_REQ, XCMP_XNL,
|
|
RPT_WAKE_UP, DE_REG_REQ]
|
|
PEER_REQUIRED = [PEER_ALIVE_REQ, PEER_ALIVE_REPLY, PEER_REG_REQ, PEER_REG_REPLY]
|
|
MASTER_REQUIRED = [PEER_LIST_REPLY, MASTER_ALIVE_REPLY]
|
|
USER_PACKETS = [GROUP_VOICE, PVT_VOICE, GROUP_DATA, PVT_DATA]
|
|
|
|
# RCM Timeslot constants
|
|
TS = {b'\x00': '1', b'\x01': '2'}
|
|
|
|
# DMR ID range constants (matches hblink3)
|
|
ID_MIN = 1
|
|
ID_MAX = 16776415
|
|
PEER_MAX = 4294967295
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# IPSC Bitmasks (from ipsc_mask.py)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# LINKING STATUS byte flags
|
|
# xx.. .... Peer Operational (01 = operational)
|
|
# ..xx .... Peer MODE: 00=No Radio, 01=Analog, 10=Digital
|
|
# .... xx.. IPSC Slot 1: 10=on, 01=off
|
|
# .... ..xx IPSC Slot 2: 10=on, 01=off
|
|
PEER_OP_MSK = 0b01000000
|
|
PEER_MODE_MSK = 0b00110000
|
|
PEER_MODE_ANALOG = 0b00010000
|
|
PEER_MODE_DIGITAL = 0b00100000
|
|
IPSC_TS1_MSK = 0b00001100
|
|
IPSC_TS2_MSK = 0b00000011
|
|
|
|
# SERVICE FLAGS byte 3
|
|
CSBK_MSK = 0b10000000
|
|
RPT_MON_MSK = 0b01000000
|
|
CON_APP_MSK = 0b00100000
|
|
|
|
# SERVICE FLAGS byte 4
|
|
XNL_STAT_MSK = 0b10000000
|
|
XNL_MSTR_MSK = 0b01000000
|
|
XNL_SLAVE_MSK = 0b00100000
|
|
PKT_AUTH_MSK = 0b00010000
|
|
DATA_CALL_MSK = 0b00001000
|
|
VOICE_CALL_MSK = 0b00000100
|
|
MSTR_PEER_MSK = 0b00000001
|
|
|
|
# TIMESLOT CALL & STATUS byte (GV_CALL_INFO_OFF = byte 17 of voice/data packets)
|
|
# .x.. .... End flag (0=in-progress, 1=end)
|
|
# ..x. .... Timeslot (0=TS1, 1=TS2)
|
|
END_MSK = 0b01000000
|
|
TS_CALL_MSK = 0b00100000
|
|
|
|
# RTP header bitmasks
|
|
RTP_VER_MSK = 0b11000000
|
|
RTP_PAD_MSK = 0b00100000
|
|
RTP_EXT_MSK = 0b00010000
|
|
RTP_CSIC_MSK = 0b00001111
|
|
RTP_MRKR_MSK = 0b10000000
|
|
RTP_PAY_TYPE_MSK = 0b01111111
|