diff --git a/FreeDMR-MINIMAL.cfg b/FreeDMR-MINIMAL.cfg new file mode 100755 index 0000000..0f7a827 --- /dev/null +++ b/FreeDMR-MINIMAL.cfg @@ -0,0 +1,42 @@ +#This empty config file will use defaults for everything apart from OBP and HBP config +#This is usually a sensible choice. + + +[GLOBAL] +SERVER_ID: 0000 + +[REPORTS] + +[LOGGER] + +[ALIASES] + +[ALLSTAR] + +[SYSTEM] +MODE: MASTER +ENABLED: True +REPEAT: True +MAX_PEERS: 1 +EXPORT_AMBE: False +IP: 127.0.0.1 +PORT: 54000 +PASSPHRASE: +GROUP_HANGTIME: 5 +USE_ACL: True +REG_ACL: DENY:1 +SUB_ACL: DENY:1 +TGID_TS1_ACL: PERMIT:ALL +TGID_TS2_ACL: PERMIT:ALL +DEFAULT_UA_TIMER: 60 +SINGLE_MODE: True +VOICE_IDENT: True +TS1_STATIC: +TS2_STATIC: +DEFAULT_REFLECTOR: 0 +ANNOUNCEMENT_LANGUAGE: en_GB +GENERATOR: 100 +ALLOW_UNREG_ID: False +PROXY_CONTROL: True +OVERRIDE_IDENT_TG: + diff --git a/FreeDMR-SAMPLE.cfg b/FreeDMR-SAMPLE.cfg index e3ecc7a..fbeb09e 100755 --- a/FreeDMR-SAMPLE.cfg +++ b/FreeDMR-SAMPLE.cfg @@ -9,7 +9,7 @@ TGID_TS1_ACL: PERMIT:ALL TGID_TS2_ACL: PERMIT:ALL GEN_STAT_BRIDGES: True ALLOW_NULL_PASSPHRASE: True -ANNOUNCEMENT_LANGUAGES: en_GB,en_US,es_ES,fr_FR,de_DE,dk_DK,it_IT,no_NO,pl_PL,se_SE,pt_PT,cy_GB,el_GR,CW +ANNOUNCEMENT_LANGUAGES: SERVER_ID: 0000 DATA_GATEWAY: False VALIDATE_SERVER_IDS: True diff --git a/a b/a deleted file mode 100644 index e69de29..0000000 diff --git a/bridge_master.py b/bridge_master.py index d7cd7b9..bd73887 100644 --- a/bridge_master.py +++ b/bridge_master.py @@ -2536,7 +2536,7 @@ if __name__ == '__main__': if cli_args.LOG_LEVEL: CONFIG['LOGGER']['LOG_LEVEL'] = cli_args.LOG_LEVEL logger = log.config_logging(CONFIG['LOGGER']) - logger.info('\n\nCopyright (c) 2020, 2021, 2022 Simon G7RZU simon@gb7fr.org.uk') + logger.info('\n\nCopyright (c) 2020, 2021, 2022, 2023 Simon G7RZU simon@gb7fr.org.uk') logger.info('Copyright (c) 2013, 2014, 2015, 2016, 2018, 2019\n\tThe Regents of the K0USY Group. All rights reserved.\n') logger.debug('(GLOBAL) Logging system started, anything from here on gets logged') diff --git a/config.py b/config.py index 16f74ed..3eed4e2 100755 --- a/config.py +++ b/config.py @@ -182,7 +182,7 @@ def build_config(_config_file): 'TGID_URL': config.get(section, 'TGID_URL', fallback='https://freedmr-lh.gb7fr.org.uk/json/talkgroup_ids.json'), 'STALE_TIME': config.getint(section, 'STALE_DAYS', fallback=1) * 86400, 'SUB_MAP_FILE': config.get(section, 'SUB_MAP_FILE', fallback='sub_map.pkl'), - 'LOCAL_SUBSCRIBER_FILE': config.get(section, 'LOCAL_SUBSCRIBER_FILE', fallback=''), + 'LOCAL_SUBSCRIBER_FILE': config.get(section, 'LOCAL_SUBSCRIBER_FILE', fallback='local_subscribers.json'), 'SERVER_ID_URL': config.get(section, 'SERVER_ID_URL', fallback='https://freedmr-lh.gb7fr.org.uk/json/server_ids.tsv'), 'SERVER_ID_FILE': config.get(section, 'SERVER_ID_FILE', fallback='server_ids.tsv'), 'CHECKSUM_URL': config.get(section, 'CHECKSUM_URL', fallback='https://freedmr-lh.gb7fr.org.uk/file_checksums.json'), @@ -304,52 +304,55 @@ def build_config(_config_file): elif config.get(section, 'MODE') == 'MASTER': CONFIG['SYSTEMS'].update({section: { 'MODE': config.get(section, 'MODE'), - 'ENABLED': config.getboolean(section, 'ENABLED'), - 'REPEAT': config.getboolean(section, 'REPEAT'), - 'MAX_PEERS': config.getint(section, 'MAX_PEERS'), - 'IP': config.get(section, 'IP'), - 'PORT': config.getint(section, 'PORT'), - 'PASSPHRASE': bytes(config.get(section, 'PASSPHRASE'), 'utf-8'), - 'GROUP_HANGTIME': config.getint(section, 'GROUP_HANGTIME'), - 'USE_ACL': config.getboolean(section, 'USE_ACL'), - 'REG_ACL': config.get(section, 'REG_ACL'), - 'SUB_ACL': config.get(section, 'SUB_ACL'), - 'TG1_ACL': config.get(section, 'TGID_TS1_ACL'), - 'TG2_ACL': config.get(section, 'TGID_TS2_ACL'), - 'DEFAULT_UA_TIMER': config.getint(section, 'DEFAULT_UA_TIMER'), - 'SINGLE_MODE': config.getboolean(section, 'SINGLE_MODE'), - 'VOICE_IDENT': config.getboolean(section, 'VOICE_IDENT'), - 'TS1_STATIC': config.get(section,'TS1_STATIC'), - 'TS2_STATIC': config.get(section,'TS2_STATIC'), + 'ENABLED': config.getboolean(section, 'ENABLED', fallback=True ), + 'REPEAT': config.getboolean(section, 'REPEAT', fallback=True), + 'MAX_PEERS': config.getint(section, 'MAX_PEERS', fallback=1), + 'IP': config.get(section, 'IP', fallback='127.0.0.1'), + 'PORT': config.getint(section, 'PORT', fallback=54000), + 'PASSPHRASE': bytes(config.get(section, 'PASSPHRASE', fallback=''), 'utf-8'), + 'GROUP_HANGTIME': config.getint(section, 'GROUP_HANGTIME',fallback=5), + 'USE_ACL': config.getboolean(section, 'USE_ACL', fallback=False), + 'REG_ACL': config.get(section, 'REG_ACL', fallback=''), + 'SUB_ACL': config.get(section, 'SUB_ACL', fallback=''), + 'TG1_ACL': config.get(section, 'TGID_TS1_ACL', fallback=''), + 'TG2_ACL': config.get(section, 'TGID_TS2_ACL', fallback=''), + 'DEFAULT_UA_TIMER': config.getint(section, 'DEFAULT_UA_TIMER', fallback=10), + 'SINGLE_MODE': config.getboolean(section, 'SINGLE_MODE', fallback=True), + 'VOICE_IDENT': config.getboolean(section, 'VOICE_IDENT', fallback=True), + 'TS1_STATIC': config.get(section,'TS1_STATIC', fallback=''), + 'TS2_STATIC': config.get(section,'TS2_STATIC', fallback=''), 'DEFAULT_REFLECTOR': config.getint(section, 'DEFAULT_REFLECTOR'), - 'GENERATOR': config.getint(section, 'GENERATOR'), - 'ANNOUNCEMENT_LANGUAGE': config.get(section, 'ANNOUNCEMENT_LANGUAGE'), - 'ALLOW_UNREG_ID': config.getboolean(section,'ALLOW_UNREG_ID'), - 'PROXY_CONTROL' : config.getboolean(section,'PROXY_CONTROL'), - 'OVERRIDE_IDENT_TG': config.get(section, 'OVERRIDE_IDENT_TG') + 'GENERATOR': config.getint(section, 'GENERATOR', fallback=100), + 'ANNOUNCEMENT_LANGUAGE': config.get(section, 'ANNOUNCEMENT_LANGUAGE', fallback='en_GB'), + 'ALLOW_UNREG_ID': config.getboolean(section,'ALLOW_UNREG_ID', fallback=False), + 'PROXY_CONTROL' : config.getboolean(section,'PROXY_CONTROL', fallback=True), + 'OVERRIDE_IDENT_TG': config.get(section, 'OVERRIDE_IDENT_TG', fallback=False) }}) CONFIG['SYSTEMS'][section].update({'PEERS': {}}) elif config.get(section, 'MODE') == 'OPENBRIDGE': CONFIG['SYSTEMS'].update({section: { 'MODE': config.get(section, 'MODE'), - 'ENABLED': config.getboolean(section, 'ENABLED'), + 'ENABLED': config.getboolean(section, 'ENABLED', fallback=True), 'NETWORK_ID': config.getint(section, 'NETWORK_ID').to_bytes(4, 'big'), #'OVERRIDE_SERVER_ID': config.getint(section, 'OVERRIDE_SERVER_ID').to_bytes(4, 'big'), - 'IP': config.get(section, 'IP'), + 'IP': config.get(section, 'IP', fallback=''), 'PORT': config.getint(section, 'PORT'), 'PASSPHRASE': bytes(config.get(section, 'PASSPHRASE').ljust(20,'\x00')[:20], 'utf-8'), #'TARGET_SOCK': (gethostbyname(config.get(section, 'TARGET_IP')), config.getint(section, 'TARGET_PORT')), 'TARGET_IP': config.get(section, 'TARGET_IP'), 'TARGET_PORT': config.getint(section, 'TARGET_PORT'), - 'USE_ACL': config.getboolean(section, 'USE_ACL'), - 'SUB_ACL': config.get(section, 'SUB_ACL'), - 'TG1_ACL': config.get(section, 'TGID_ACL'), + 'USE_ACL': config.getboolean(section, 'USE_ACL', fallback=False), + 'SUB_ACL': config.get(section, 'SUB_ACL', fallback=''), + 'TG1_ACL': config.get(section, 'TGID_ACL', fallback=''), 'TG2_ACL': 'PERMIT:ALL', - 'RELAX_CHECKS': config.getboolean(section, 'RELAX_CHECKS'), - 'ENHANCED_OBP': config.getboolean(section, 'ENHANCED_OBP'), - 'VER' : config.getint(section, 'PROTO_VER') + 'RELAX_CHECKS': config.getboolean(section, 'RELAX_CHECKS', fallback=True), + 'ENHANCED_OBP': config.getboolean(section, 'ENHANCED_OBP',fallback=True), + 'VER' : config.getint(section, 'PROTO_VER', fallback=5) }}) + + if CONFIG['SYSTEMS'][section]['VER'] in (0,2,3) or CONFIG['SYSTEMS'][section]['VER'] > 5: + sys.exit('(%s) PROTO_VER not valid',section) try: diff --git a/docker-configs/docker-compose_install.sh b/docker-configs/docker-compose_install.sh index 1e23fcf..525408c 100644 --- a/docker-configs/docker-compose_install.sh +++ b/docker-configs/docker-compose_install.sh @@ -70,66 +70,32 @@ chown 54000:54000 /etc/freedmr/json && echo Install /etc/freedmr/freedmr.cfg ... cat << EOF > /etc/freedmr/freedmr.cfg +#This empty config file will use defaults for everything apart from OBP and HBP config +#This is usually a sensible choice. + +#I have moved to a config like this to encourage servers to use the accepted defaults +#unless you really know what you are doing. + [GLOBAL] -PATH: ./ -PING_TIME: 10 -MAX_MISSED: 3 -USE_ACL: True -REG_ACL: DENY:0-100000 -SUB_ACL: DENY:0-100000 -TGID_TS1_ACL: PERMIT:ALL -TGID_TS2_ACL: PERMIT:ALL -GEN_STAT_BRIDGES: True -ALLOW_NULL_PASSPHRASE: True -ANNOUNCEMENT_LANGUAGES: +#If you join the FreeDMR network, you need to add your ServerID Here. SERVER_ID: 0 -DATA_GATEWAY: False -VALIDATE_SERVER_IDS: True - [REPORTS] -REPORT: True -REPORT_INTERVAL: 60 -REPORT_PORT: 4321 -REPORT_CLIENTS: * [LOGGER] -LOG_FILE: /dev/null -LOG_HANDLERS: console-timed -LOG_LEVEL: INFO -LOG_NAME: FreeDMR [ALIASES] -TRY_DOWNLOAD: True -PATH: ./json/ -PEER_FILE: peer_ids.json -SUBSCRIBER_FILE: subscriber_ids.json -TGID_FILE: talkgroup_ids.json -PEER_URL: https://freedmr-lh.gb7fr.org.uk/json/peer_ids.json -SUBSCRIBER_URL: https://freedmr-lh.gb7fr.org.uk/json/subscriber_ids.json -TGID_URL: https://freedmr-lh.gb7fr.org.uk/json/talkgroup_ids.json -LOCAL_SUBSCRIBER_FILE: local_subcriber_ids.json -STALE_DAYS: 1 -SUB_MAP_FILE: sub_map.pkl -SERVER_ID_URL: https://freedmr-lh.gb7fr.org.uk/json/server_ids.tsv -SERVER_ID_FILE: server_ids.tsv -CHECKSUM_URL: https://freedmr-lh.gb7fr.org.uk/file_checksums.json -CHECKSUM_FILE: file_checksums.json - -#Control server shared allstar instance via dial / AMI + [ALLSTAR] -ENABLED: false -USER:admin -PASS: password -SERVER: asl.example.com -PORT: 5038 -NODE: 11111 +#This is an example OpenBridgeProtocol (OBP) or FreeBridgeProtocol (FBP) configuration +#If you joing FreeDMR, you will be given a config like this to paste in [OBP-TEST] MODE: OPENBRIDGE ENABLED: False IP: PORT: 62044 +#The ID which you expect to see sent from the other end of the link. NETWORK_ID: 1 PASSPHRASE: mypass TARGET_IP: @@ -137,11 +103,17 @@ TARGET_PORT: 62044 USE_ACL: True SUB_ACL: DENY:1 TGID_ACL: PERMIT:ALL +#Should always be true if using docker. RELAX_CHECKS: True +#True for FBP, False for OBP ENHANCED_OBP: True -PROTO_VER: 2 - +#PROTO_VER should be 5 for FreeDMR servers using FBP +#1 for other servers using OBP +PROTO_VER: 5 +#This defines parameters for repeater/hotspot connections +#via HomeBrewProtocol (HBP) +#I don't recommend changing most of this unless you know what you are doing [SYSTEM] MODE: MASTER ENABLED: True @@ -169,6 +141,7 @@ ALLOW_UNREG_ID: False PROXY_CONTROL: True OVERRIDE_IDENT_TG: +#Echo (Loro / Parrot) server [ECHO] MODE: PEER ENABLED: True diff --git a/hblink.py b/hblink.py index 06164c3..dea9462 100755 --- a/hblink.py +++ b/hblink.py @@ -201,20 +201,10 @@ class OPENBRIDGE(DatagramProtocol): self.transport.write(_packet, (self._config['TARGET_IP'], self._config['TARGET_PORT'])) elif 'VER' in self._config and self._config['VER'] == 3: - _packet = b''.join([DMRF,_packet[4:11], self._CONFIG['GLOBAL']['SERVER_ID'],_packet[15:]]) - _h = blake2b(key=self._config['PASSPHRASE'], digest_size=16) - _h.update(_packet) - _hash = _h.digest() - _packet = b''.join([_packet,time_ns().to_bytes(8,'big'), _hops, _hash]) - self.transport.write(_packet, (self._config['TARGET_IP'], self._config['TARGET_PORT'])) + logger.error('(%s) protocol version 3 no longer supported',self._system) elif 'VER' in self._config and self._config['VER'] == 2: - _packet = b''.join([DMRF,_packet[4:11], self._CONFIG['GLOBAL']['SERVER_ID'],_packet[15:], time_ns().to_bytes(8,'big')]) - _h = blake2b(key=self._config['PASSPHRASE'], digest_size=16) - _h.update(_packet) - _hash = _h.digest() - _packet = b''.join([_packet,_hops, _hash]) - self.transport.write(_packet, (self._config['TARGET_IP'], self._config['TARGET_PORT'])) + logger.error('(%s) protocol version 2 no longer supported',self._system) # KEEP THE FOLLOWING COMMENTED OUT UNLESS YOU'RE DEBUGGING DEEPLY!!!! #logger.debug('(%s) TX Packet to OpenBridge %s:%s -- %s %s', self._system, self._config['TARGET_IP'], self._config['TARGET_PORT'], _packet, _hash) else: @@ -486,122 +476,39 @@ class OPENBRIDGE(DatagramProtocol): self.send_bcsq(_dst_id,_stream_id) return - + #Low-level TG filtering if _call_type != 'unit': _int_dst_id = int_id(_dst_id) - if _int_dst_id <= 79 or (_int_dst_id >= 9990 and _int_dst_id <= 9999) or _int_dst_id == 900999: - if _stream_id not in self._laststrid: - logger.info('(%s) CALL DROPPED WITH STREAM ID %s FROM SUBSCRIBER %s BY GLOBAL TG FILTER', self._system, int_id(_stream_id), _int_dst_id) - self.send_bcsq(_dst_id,_stream_id) - self._laststrid.append(_stream_id) - return - - # ACL Processing - if self._CONFIG['GLOBAL']['USE_ACL']: - if not acl_check(_rf_src, self._CONFIG['GLOBAL']['SUB_ACL']): - if _stream_id not in self._laststrid: - logger.info('(%s) CALL DROPPED WITH STREAM ID %s ON TGID %s BY GLOBAL TS1 ACL', self._system, int_id(_stream_id), int_id(_rf_src)) - self.send_bcsq(_dst_id,_stream_id) - self._laststrid.append(_stream_id) - return - if _slot == 1 and not acl_check(_dst_id, self._CONFIG['GLOBAL']['TG1_ACL']): + + if _int_dst_id <= 79: if _stream_id not in self._laststrid: - logger.info('(%s) CALL DROPPED WITH STREAM ID %s ON TGID %s BY GLOBAL TS1 ACL', self._system, int_id(_stream_id), int_id(_dst_id)) + logger.info('(%s) CALL DROPPED WITH STREAM ID %s FROM SUBSCRIBER %s BY GLOBAL TG FILTER (local to repeater)', self._system, int_id(_stream_id), _int_dst_id) self.send_bcsq(_dst_id,_stream_id) self._laststrid.append(_stream_id) return - if self._config['USE_ACL']: - if not acl_check(_rf_src, self._config['SUB_ACL']): + + if (_int_dst_id >= 9990 and _int_dst_id <= 9999) or _int_dst_id == 900999: if _stream_id not in self._laststrid: - logger.info('(%s) CALL DROPPED WITH STREAM ID %s FROM SUBSCRIBER %s BY SYSTEM ACL', self._system, int_id(_stream_id), int_id(_rf_src)) + logger.info('(%s) CALL DROPPED WITH STREAM ID %s FROM SUBSCRIBER %s BY GLOBAL TG FILTER (local to server)', self._system, int_id(_stream_id), _int_dst_id) self.send_bcsq(_dst_id,_stream_id) self._laststrid.append(_stream_id) return - if not acl_check(_dst_id, self._config['TG1_ACL']): + + if (_int_dst_id >= 92 and _int_dst_id <= 199) and int(str(int.from_bytes(_source_server,'big'))[:4]) != int(str(int.from_bytes(self._CONFIG['GLOBAL']['SERVER_ID'],'big'))[:4]): if _stream_id not in self._laststrid: - logger.info('(%s) CALL DROPPED WITH STREAM ID %s ON TGID %s BY SYSTEM ACL', self._system, int_id(_stream_id), int_id(_dst_id)) + logger.info('(%s) CALL DROPPED WITH STREAM ID %s FROM SUBSCRIBER %s BY GLOBAL TG FILTER (local to server main ID)', self._system, int_id(_stream_id), _int_dst_id) self.send_bcsq(_dst_id,_stream_id) self._laststrid.append(_stream_id) return - _data = b''.join([DMRD,_data[4:]]) - - _hops = _inthops.to_bytes(1,'big') - # Userland actions -- typically this is the function you subclass for an application - self.dmrd_received(_peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data,_hash,_hops,_source_server,_ber,_rssi,_source_rptr) - #Silently treat a DMRD packet like a keepalive - this is because it's traffic and the - #Other end may not have enabled ENAHNCED_OBP - self._config['_bcka'] = time() - else: - h,p = _sockaddr - logger.warning('(%s) FreeBridge HMAC failed, packet discarded - OPCODE: %s DATA: %s HMAC LENGTH: %s HMAC: %s SRC IP: %s SRC PORT: %s', self._system, _packet[:4], repr(_packet[:69]), len(_packet[69:]), repr(_packet[61:]),h,p) - - - elif _packet[:4] == DMRF: - _data = _packet[:53] - _timestamp = _packet[53:60] - _hops = _packet[61] - _hash = _packet[62:] - #_ckhs = hmac_new(self._config['PASSPHRASE'],_data,sha1).digest() - _h = blake2b(key=self._config['PASSPHRASE'], digest_size=16) - if 'VER' in self._config and self._config['VER'] > 2: - _h.update(_packet[:53]) - elif 'VER' in self._config and self._config['VER'] == 2: - _h.update(_packet[:61]) - - _ckhs = _h.digest() - - if compare_digest(_hash, _ckhs) and (_sockaddr == self._config['TARGET_SOCK'] or self._config['RELAX_CHECKS']): - _peer_id = _data[11:15] - if self._config['NETWORK_ID'] != _peer_id: - if _stream_id not in self._laststrid: - logger.error('(%s) OpenBridge packet discarded because NETWORK_ID: %s Does not match sent Peer ID: %s', self._system, int_id(self._config['NETWORK_ID']), int_id(_peer_id)) - self._laststrid.append(_stream_id) - return - _seq = _data[4] - _rf_src = _data[5:8] - _dst_id = _data[8:11] - _int_dst_id = int_id(_dst_id) - _bits = _data[15] - _slot = 2 if (_bits & 0x80) else 1 - #_call_type = 'unit' if (_bits & 0x40) else 'group' - if _bits & 0x40: - _call_type = 'unit' - elif (_bits & 0x23) == 0x23: - _call_type = 'vcsbk' - else: - _call_type = 'group' - _frame_type = (_bits & 0x30) >> 4 - _dtype_vseq = (_bits & 0xF) # data, 1=voice header, 2=voice terminator; voice, 0=burst A ... 5=burst F - _stream_id = _data[16:20] - #logger.debug('(%s) DMRD - Seqence: %s, RF Source: %s, Destination ID: %s', self._system, int_id(_seq), int_id(_rf_src), int_id(_dst_id)) - - #Don't do anything if we are STUNned - if 'STUN' in self._CONFIG: + if (_int_dst_id >= 80 and _int_dst_id <= 89) or (_int_dst_id >= 800 and _int_dst_id <= 899) and int(str(int.from_bytes(_source_server,'big'))[:3]) != int(str(int.from_bytes(self._CONFIG['GLOBAL']['SERVER_ID'],'big'))[:3]): if _stream_id not in self._laststrid: - logger.warning('(%s) Bridge STUNned, discarding', self._system) - self._laststrid.append(_stream_id) - return - - #Increment max hops - _inthops = _hops +1 - - if _inthops > 10: - logger.warning('(%s) MAX HOPS exceed, dropping. Hops: %s, DST: %s', self._system, _inthops, _int_dst_id) - self.send_bcsq(_dst_id,_stream_id) - return - - - #Low-level TG filtering - if _call_type != 'unit': - _int_dst_id = int_id(_dst_id) - if _int_dst_id <= 79 or (_int_dst_id >= 9990 and _int_dst_id <= 9999) or _int_dst_id == 900999: - if _stream_id not in self._laststrid: - logger.info('(%s) CALL DROPPED WITH STREAM ID %s FROM SUBSCRIBER %s BY GLOBAL TG FILTER', self._system, int_id(_stream_id), _int_dst_id) + logger.info('(%s) CALL DROPPED WITH STREAM ID %s FROM SUBSCRIBER %s BY GLOBAL TG FILTER (local to MCC)', self._system, int_id(_stream_id), _int_dst_id) self.send_bcsq(_dst_id,_stream_id) self._laststrid.append(_stream_id) return + # ACL Processing if self._CONFIG['GLOBAL']['USE_ACL']: @@ -630,23 +537,22 @@ class OPENBRIDGE(DatagramProtocol): self.send_bcsq(_dst_id,_stream_id) self._laststrid.append(_stream_id) return - - - #Remove timestamp from data. For now dmrd_received does not expect it - #Leaving it in screws up the AMBE data - #_data = b''.join([_data[:5],_data[12:]]) _data = b''.join([DMRD,_data[4:]]) _hops = _inthops.to_bytes(1,'big') # Userland actions -- typically this is the function you subclass for an application - self.dmrd_received(_peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data,_hash,_hops) + self.dmrd_received(_peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data,_hash,_hops,_source_server,_ber,_rssi,_source_rptr) #Silently treat a DMRD packet like a keepalive - this is because it's traffic and the #Other end may not have enabled ENAHNCED_OBP self._config['_bcka'] = time() else: h,p = _sockaddr - logger.warning('(%s) FreeBridge HMAC failed, packet discarded - OPCODE: %s DATA: %s HMAC LENGTH: %s HMAC: %s SRC IP: %s SRC PORT: %s', self._system, _packet[:4], repr(_packet[:61]), len(_packet[61:]), repr(_packet[61:]),h,p) + logger.warning('(%s) FreeBridge HMAC failed, packet discarded - OPCODE: %s DATA: %s HMAC LENGTH: %s HMAC: %s SRC IP: %s SRC PORT: %s', self._system, _packet[:4], repr(_packet[:69]), len(_packet[69:]), repr(_packet[61:]),h,p) + + + elif _packet[:4] == DMRF: + logger.error('(%s) Protocol versions 2 and 3 no longer supported',self._system) if self._config['ENHANCED_OBP']: if _packet[:2] == BC: # Bridge Control packet (Extended OBP) @@ -703,7 +609,9 @@ class OPENBRIDGE(DatagramProtocol): if compare_digest(_hash, _ckhs): logger.trace('(%s) *ProtoControl* BCVE Version received, Ver: %s',self._system,_ver) - if _ver > self._config['VER']: + if _ver == 2 or _ver == 3 or _ver > 5: + logger.info('(%s) *ProtoControl* BCVE Version not supported, Ver: %s',self._system,_ver) + elif _ver > self._config['VER']: logger.info('(%s) *ProtoControl* BCVE Version upgrade, Ver: %s',self._system,_ver) self._config['VER'] = _ver elif _ver == self._config['VER']: @@ -927,7 +835,6 @@ class HBSYSTEM(DatagramProtocol): # Extract the command, which is various length, all but one 4 significant characters -- RPTCL _command = _data[:4] - if _command == DMRD: # DMRData -- encapsulated DMR data frame _peer_id = _data[11:15] if _peer_id in self._peers \