From 6adf6e456bf9efb8f3f8ff291874626bf1f20121 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 7 Feb 2022 00:53:34 +0000 Subject: [PATCH 01/41] Emergency fix - unique packets break hashing --- const.py | 2 +- hblink.py | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/const.py b/const.py index 1da03cb..69ae539 100755 --- a/const.py +++ b/const.py @@ -81,7 +81,7 @@ BCST = b'BCST' BCVE = b'BCVE' #Protocol version -VER = 2 +VER = 3 # Higheset peer ID permitted by HBP PEER_MAX = 4294967295 diff --git a/hblink.py b/hblink.py index 42ae6df..ec4e2d2 100755 --- a/hblink.py +++ b/hblink.py @@ -156,7 +156,15 @@ class OPENBRIDGE(DatagramProtocol): if _packet[:3] == DMR and self._config['TARGET_IP']: - if 'VER' in self._config and self._config['VER'] > 1: + if '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'])) + + if '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) @@ -327,7 +335,10 @@ class OPENBRIDGE(DatagramProtocol): _hash = _packet[62:] #_ckhs = hmac_new(self._config['PASSPHRASE'],_data,sha1).digest() _h = blake2b(key=self._config['PASSPHRASE'], digest_size=16) - _h.update(_packet[:61]) + if 'VER' in self._config and self._config['VER'] = 2: + _h.update(_packet[:61]) + elif 'VER' in self._config and self._config['VER'] >= 3: + _h.update(_packet[:53]) _ckhs = _h.digest() if compare_digest(_hash, _ckhs) and (_sockaddr == self._config['TARGET_SOCK'] or self._config['RELAX_CHECKS']): From 38430a8e86612b9f1aa06dcfe0f3b34a6884c8d0 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 7 Feb 2022 00:55:54 +0000 Subject: [PATCH 02/41] Emergency fix - unique packets break hashing --- hblink.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hblink.py b/hblink.py index ec4e2d2..204ef29 100755 --- a/hblink.py +++ b/hblink.py @@ -164,7 +164,7 @@ class OPENBRIDGE(DatagramProtocol): _packet = b''.join([_packet,time_ns().to_bytes(8,'big'), _hops, _hash]) self.transport.write(_packet, (self._config['TARGET_IP'], self._config['TARGET_PORT'])) - if 'VER' in self._config and self._config['VER'] = 2: + if '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) @@ -335,7 +335,7 @@ class OPENBRIDGE(DatagramProtocol): _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: + if 'VER' in self._config and self._config['VER'] == 2: _h.update(_packet[:61]) elif 'VER' in self._config and self._config['VER'] >= 3: _h.update(_packet[:53]) From ae5aa881999663afb58bc0cf339e1bffa767dd87 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 7 Feb 2022 01:04:35 +0000 Subject: [PATCH 03/41] Emergency fix - unique packets break hashing --- hblink.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hblink.py b/hblink.py index 204ef29..fccac4f 100755 --- a/hblink.py +++ b/hblink.py @@ -338,7 +338,7 @@ class OPENBRIDGE(DatagramProtocol): if 'VER' in self._config and self._config['VER'] == 2: _h.update(_packet[:61]) elif 'VER' in self._config and self._config['VER'] >= 3: - _h.update(_packet[:53]) + _h.update(_packet[:54]) _ckhs = _h.digest() if compare_digest(_hash, _ckhs) and (_sockaddr == self._config['TARGET_SOCK'] or self._config['RELAX_CHECKS']): From d16cb04784bb2ef933396ef450b3f50af1b45716 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 7 Feb 2022 01:24:07 +0000 Subject: [PATCH 04/41] Emergency fix - unique packets break hashing --- hblink.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hblink.py b/hblink.py index fccac4f..9de3b09 100755 --- a/hblink.py +++ b/hblink.py @@ -156,7 +156,7 @@ class OPENBRIDGE(DatagramProtocol): if _packet[:3] == DMR and self._config['TARGET_IP']: - if 'VER' in self._config and self._config['VER'] >= 3: + if '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) @@ -335,10 +335,11 @@ class OPENBRIDGE(DatagramProtocol): _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: + if 'VER' in self._config and self._config['VER'] == 3: + _h.update(_packet[:53]) + elif 'VER' in self._config and self._config['VER'] == 2: _h.update(_packet[:61]) - elif 'VER' in self._config and self._config['VER'] >= 3: - _h.update(_packet[:54]) + _ckhs = _h.digest() if compare_digest(_hash, _ckhs) and (_sockaddr == self._config['TARGET_SOCK'] or self._config['RELAX_CHECKS']): From 50b1a85cfbb9105300c9f696d1b33bd492b96f5c Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 7 Feb 2022 01:37:31 +0000 Subject: [PATCH 05/41] Emergency fix - unique packets break hashing --- hblink.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hblink.py b/hblink.py index 9de3b09..48ba151 100755 --- a/hblink.py +++ b/hblink.py @@ -164,7 +164,7 @@ class OPENBRIDGE(DatagramProtocol): _packet = b''.join([_packet,time_ns().to_bytes(8,'big'), _hops, _hash]) self.transport.write(_packet, (self._config['TARGET_IP'], self._config['TARGET_PORT'])) - if 'VER' in self._config and self._config['VER'] == 2: + 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) From 5312c8cc8e4c6f550505edc325f099fe709fc021 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 7 Feb 2022 02:08:03 +0000 Subject: [PATCH 06/41] Support furture version --- hblink.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hblink.py b/hblink.py index 48ba151..17d38c3 100755 --- a/hblink.py +++ b/hblink.py @@ -335,7 +335,7 @@ class OPENBRIDGE(DatagramProtocol): _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'] == 3: + 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]) From 12dafa3c40d4f827dc3b556504e18cfcab6b58dd Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 13 Feb 2022 01:47:51 +0000 Subject: [PATCH 07/41] first pass - protov4 --- const.py | 2 +- doc/FreeDMR FBP Proto v4.ods | Bin 0 -> 13983 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 doc/FreeDMR FBP Proto v4.ods diff --git a/const.py b/const.py index 69ae539..efa30e9 100755 --- a/const.py +++ b/const.py @@ -81,7 +81,7 @@ BCST = b'BCST' BCVE = b'BCVE' #Protocol version -VER = 3 +VER = 4 # Higheset peer ID permitted by HBP PEER_MAX = 4294967295 diff --git a/doc/FreeDMR FBP Proto v4.ods b/doc/FreeDMR FBP Proto v4.ods new file mode 100644 index 0000000000000000000000000000000000000000..cc0e88afe7131d0903f4aa5744f41a5bcf58f524 GIT binary patch literal 13983 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 N4Bs~$V#eRO{{sPc<< Date: Sun, 13 Feb 2022 02:47:49 +0000 Subject: [PATCH 08/41] Prepare for 4 --- hblink.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hblink.py b/hblink.py index 17d38c3..5494a93 100755 --- a/hblink.py +++ b/hblink.py @@ -156,7 +156,7 @@ class OPENBRIDGE(DatagramProtocol): if _packet[:3] == DMR and self._config['TARGET_IP']: - if 'VER' in self._config and self._config['VER'] == 3: + if 'VER' in self._config and self._config['VER'] > 2: _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) From 265519fe03a3248c91b63ba6988626fee34e7251 Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 13 Feb 2022 14:31:14 +0000 Subject: [PATCH 09/41] Don't send UNIT DATA to ver 1 bridges --- bridge_master.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bridge_master.py b/bridge_master.py index 5708ac7..498cf33 100644 --- a/bridge_master.py +++ b/bridge_master.py @@ -1568,7 +1568,8 @@ class routerOBP(OPENBRIDGE): if system == self._system: continue #We only want to send data calls to individual IDs via OpenBridge - if CONFIG['SYSTEMS'][system]['MODE'] == 'OPENBRIDGE' and (_int_dst_id >= 1000000): + #Only send if proto ver for bridge is > 1 + if CONFIG['SYSTEMS'][system]['MODE'] == 'OPENBRIDGE' and CONFIG['SYSTEMS'][system]['VER'] > 1 and (_int_dst_id >= 1000000): self.sendDataToOBP(system,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_hops) #If destination ID is in the Subscriber Map @@ -2152,7 +2153,7 @@ class routerHBP(HBSYSTEM): if system == self._system: continue #We only want to send data calls to individual IDs via OpenBridge - if CONFIG['SYSTEMS'][system]['MODE'] == 'OPENBRIDGE' and (_int_dst_id >= 1000000): + if CONFIG['SYSTEMS'][system]['MODE'] == 'OPENBRIDGE' and CONFIG['SYSTEMS'][system]['VER'] > 1 and (_int_dst_id >= 1000000): self.sendDataToOBP(system,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot) From a74919dd6116726e319bb5018e684e373dc0667b Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 13 Feb 2022 15:31:43 +0000 Subject: [PATCH 10/41] limit wrong ver logging --- hblink.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hblink.py b/hblink.py index 5494a93..2f13631 100755 --- a/hblink.py +++ b/hblink.py @@ -234,7 +234,9 @@ class OPENBRIDGE(DatagramProtocol): if _packet[:3] == DMR: # DMRData -- encapsulated DMR data frame if _packet[:4] == DMRD: if self._config['VER'] > 1: - logger.warning('(%s) *ProtoControl* Version 1 protocol prohibited by PROTO_VER, Ver: %s',self._system,self._config['VER']) + if _stream_id not in self._laststrid: + logger.warning('(%s) *ProtoControl* Version 1 protocol prohibited by PROTO_VER, Ver: %s',self._system,self._config['VER']) + self._laststrid.append(_stream_id) self.send_bcve() return _data = _packet[:53] From 7d03e65d1d47747368ab50d83a0222e0e62b73cd Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 13 Feb 2022 15:33:40 +0000 Subject: [PATCH 11/41] get streamid earlier --- hblink.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hblink.py b/hblink.py index 2f13631..4615a64 100755 --- a/hblink.py +++ b/hblink.py @@ -233,6 +233,7 @@ class OPENBRIDGE(DatagramProtocol): if _packet[:3] == DMR: # DMRData -- encapsulated DMR data frame if _packet[:4] == DMRD: + _stream_id = _data[16:20] if self._config['VER'] > 1: if _stream_id not in self._laststrid: logger.warning('(%s) *ProtoControl* Version 1 protocol prohibited by PROTO_VER, Ver: %s',self._system,self._config['VER']) @@ -262,7 +263,6 @@ class OPENBRIDGE(DatagramProtocol): _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)) From 323be20ecfe87e212db0259e93af7c2eec969e83 Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 13 Feb 2022 15:34:58 +0000 Subject: [PATCH 12/41] get data earlier --- hblink.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hblink.py b/hblink.py index 4615a64..612095d 100755 --- a/hblink.py +++ b/hblink.py @@ -233,6 +233,7 @@ class OPENBRIDGE(DatagramProtocol): if _packet[:3] == DMR: # DMRData -- encapsulated DMR data frame if _packet[:4] == DMRD: + _data = _packet[:53] _stream_id = _data[16:20] if self._config['VER'] > 1: if _stream_id not in self._laststrid: @@ -240,7 +241,6 @@ class OPENBRIDGE(DatagramProtocol): self._laststrid.append(_stream_id) self.send_bcve() return - _data = _packet[:53] _hash = _packet[53:] _ckhs = hmac_new(self._config['PASSPHRASE'],_data,sha1).digest() From 005fa88de90c5585d8cfffa849bc15b331a5d4f0 Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 13 Feb 2022 15:46:04 +0000 Subject: [PATCH 13/41] ff --- hblink.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hblink.py b/hblink.py index 17d38c3..3649c91 100755 --- a/hblink.py +++ b/hblink.py @@ -156,6 +156,15 @@ class OPENBRIDGE(DatagramProtocol): if _packet[:3] == DMR and self._config['TARGET_IP']: + + if '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'])) + if '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) From 91e234a64de359f66a598fdb5e8b69bcb28a12c6 Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 13 Feb 2022 19:35:57 +0000 Subject: [PATCH 14/41] protocol 4 communication working (low level) --- doc/FreeDMR FBP Proto v4.ods | Bin 13983 -> 15070 bytes hblink.py | 110 ++++++++++++++++++++++++++++++++++- 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/doc/FreeDMR FBP Proto v4.ods b/doc/FreeDMR FBP Proto v4.ods index cc0e88afe7131d0903f4aa5744f41a5bcf58f524..8fc2803f2a7de478752d669ee49fb54fac8dbd1a 100644 GIT binary patch delta 13056 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 delta 11953 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 diff --git a/hblink.py b/hblink.py index 7bd740e..a642692 100755 --- a/hblink.py +++ b/hblink.py @@ -159,7 +159,7 @@ class OPENBRIDGE(DatagramProtocol): if 'VER' in self._config and self._config['VER'] > 3: _ver = VER.to_bytes(1,'big') - _packet = b''.join([DMRE,_ver,_packet[4:11], self._CONFIG['GLOBAL']['SERVER_ID'],_packet[15:],time_ns().to_bytes(8,'big'), _source_server, _hops]) + _packet = b''.join([DMRE,_packet[4:11], self._CONFIG['GLOBAL']['SERVER_ID'],_packet[15:],_ver,time_ns().to_bytes(8,'big'), _source_server, _hops]) _h = blake2b(key=self._config['PASSPHRASE'], digest_size=16) _h.update(_packet) _hash = _h.digest() @@ -339,6 +339,114 @@ class OPENBRIDGE(DatagramProtocol): elif _packet[:4] == EOBP: logger.warning('(%s) *ProtoControl* KF7EEL EOBP protocol not supported',self._system) return + + elif _packet[:4] == DMRE: + _data = _packet[:53] + _embedded_version = _packet[53] + _timestamp = _packet[54:62] + _source_server = _packet[62:66] + _hops = _packet[66] + _hash = _packet[67:83] + #_ckhs = hmac_new(self._config['PASSPHRASE'],_data,sha1).digest() + _h = blake2b(key=self._config['PASSPHRASE'], digest_size=16) + _h.update(_packet[:67]) + + _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: + 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)) + 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 _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) + 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 _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)) + 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 _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)) + self.send_bcsq(_dst_id,_stream_id) + self._laststrid.append(_stream_id) + return + if not acl_check(_dst_id, self._config['TG1_ACL']): + 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)) + 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) + #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[:67]), len(_packet[67:]), repr(_packet[61:]),h,p) + elif _packet[:4] == DMRF: _data = _packet[:53] From f3f1663999acc56fe0cc6406a5351aac506d7913 Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 13 Feb 2022 19:41:05 +0000 Subject: [PATCH 15/41] use separate hash for previous packet detection --- bridge_master.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bridge_master.py b/bridge_master.py index 498cf33..3a25516 100644 --- a/bridge_master.py +++ b/bridge_master.py @@ -1470,7 +1470,13 @@ class routerOBP(OPENBRIDGE): #pkt_crc = Crc32.calc(_data[4:53]) #_pkt_crc = Crc32.calc(dmrpkt) - _pkt_crc = _hash + + #Use blake2b hash + _h = blake2b(digest_size=16) + _h.update(_data) + _pkt_crc = _h.digest() + + #_pkt_crc = _hash # Match UNIT data, SMS/GPS, and send it to the dst_id if it is in SUB_MAP if _call_type == 'unit' and (_dtype_vseq == 6 or _dtype_vseq == 7 or _dtype_vseq == 8 or ((_stream_id not in self.STATUS) and _dtype_vseq == 3)): From dbeb97e57820cb2cc4feabd393fe036296ffdb12 Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 13 Feb 2022 23:00:30 +0000 Subject: [PATCH 16/41] handle source_server, ber, rssi - in code --- bridge_master.py | 37 +++++++++++++++++++++-------------- doc/FreeDMR FBP Proto v4.ods | Bin 15070 -> 15138 bytes hblink.py | 31 ++++++++++++++++------------- 3 files changed, 39 insertions(+), 29 deletions(-) diff --git a/bridge_master.py b/bridge_master.py index 3a25516..74bf38d 100644 --- a/bridge_master.py +++ b/bridge_master.py @@ -1236,7 +1236,7 @@ class routerOBP(OPENBRIDGE): OPENBRIDGE.__init__(self, _name, _config, _report) self.STATUS = {} - def to_target(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data, pkt_time, dmrpkt, _bits,_bridge,_system,_noOBP,sysIgnore, _hops = b''): + def to_target(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data, pkt_time, dmrpkt, _bits,_bridge,_system,_noOBP,sysIgnore, _hops = b'', _source_server = b'\x00\x00\x00\x00', _ber = b'\x00', _rssi = b'\x00'): _sysIgnore = sysIgnore for _target in BRIDGES[_bridge]: if (_target['SYSTEM'] != self._system) and (_target['ACTIVE']): @@ -1405,10 +1405,11 @@ class routerOBP(OPENBRIDGE): elif _dtype_vseq in [1,2,3,4]: dmrbits = dmrbits[0:116] + _target_status[_target['TS']]['TX_EMB_LC'][_dtype_vseq] + dmrbits[148:264] dmrpkt = dmrbits.tobytes() - _tmp_data = b''.join([_tmp_data, dmrpkt, b'\x00\x00']) # Add two bytes of nothing since OBP doesn't include BER & RSSI bytes #_data[53:55] + #_tmp_data = b''.join([_tmp_data, dmrpkt, b'\x00\x00']) # Add two bytes of nothing since OBP doesn't include BER & RSSI bytes #_data[53:55] + _tmp_data = b''.join([_tmp_data, dmrpkt]) # Transmit the packet to the destination system - systems[_target['SYSTEM']].send_system(_tmp_data,_hops) + systems[_target['SYSTEM']].send_system(_tmp_data,_hops,_source_server, _ber, _rssi) #logger.debug('(%s) Packet routed by bridge: %s to system: %s TS: %s, TGID: %s', self._system, _bridge, _target['SYSTEM'], _target['TS'], int_id(_target['TGID'])) #Ignore this system and TS pair if it's called again on this packet return(_sysIgnore) @@ -1423,7 +1424,7 @@ class routerOBP(OPENBRIDGE): if CONFIG['REPORTS']['REPORT']: systems[_d_system]._report.send_bridgeEvent('UNIT DATA,START,TX,{},{},{},{},{},{}'.format(_d_system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), 1, _int_dst_id).encode(encoding='utf-8', errors='ignore')) - def sendDataToOBP(self,_target,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_hops = b''): + def sendDataToOBP(self,_target,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_hops = b'',_source_server = b'\x00\x00\x00\x00', _ber = b'\x00', _rssi = b'\x00'): _int_dst_id = int_id(_dst_id) _target_status = systems[_target].STATUS @@ -1457,13 +1458,13 @@ class routerOBP(OPENBRIDGE): #Assemble transmit HBP packet header _tmp_data = b''.join([_data[:15], _tmp_bits.to_bytes(1, 'big'), _data[16:20]]) _tmp_data = b''.join([_tmp_data, dmrpkt]) - systems[_target].send_system(_tmp_data,_hops) + systems[_target].send_system(_tmp_data,_hops, _source_server, _ber, _rssi) logger.info('(%s) UNIT Data Bridged to OBP System: %s DST_ID: %s', self._system, _target,_int_dst_id) if CONFIG['REPORTS']['REPORT']: systems[_target]._report.send_bridgeEvent('UNIT DATA,START,TX,{},{},{},{},{},{}'.format(_target, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), 1, _int_dst_id).encode(encoding='utf-8', errors='ignore')) - def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data,_hash, _hops = b''): + def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data,_hash, _hops = b'', _source_server = b'\x00\x00\x00\x00', _ber = b'\x00', _rssi = b'\x00'): pkt_time = time() dmrpkt = _data[20:53] _bits = _data[15] @@ -1576,7 +1577,7 @@ class routerOBP(OPENBRIDGE): #We only want to send data calls to individual IDs via OpenBridge #Only send if proto ver for bridge is > 1 if CONFIG['SYSTEMS'][system]['MODE'] == 'OPENBRIDGE' and CONFIG['SYSTEMS'][system]['VER'] > 1 and (_int_dst_id >= 1000000): - self.sendDataToOBP(system,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_hops) + self.sendDataToOBP(system,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_hops,_source_server,_ber,_rssi) #If destination ID is in the Subscriber Map if _dst_id in SUB_MAP: @@ -1655,8 +1656,8 @@ class routerOBP(OPENBRIDGE): _inthops = 0 if _hops: _inthops = int.from_bytes(_hops,'big') - logger.info('(%s) *CALL START* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, HOPS %s', \ - self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot,_inthops) + logger.info('(%s) *CALL START* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, SRC: %s, BER: %s, RSSI %s, HOPS %s', \ + self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot,int_id(_source_server),_ber,_rssi,_inthops) if CONFIG['REPORTS']['REPORT']: self._report.send_bridgeEvent('GROUP VOICE,START,RX,{},{},{},{},{},{}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id)).encode(encoding='utf-8', errors='ignore')) @@ -1775,7 +1776,7 @@ class routerOBP(OPENBRIDGE): for _system in BRIDGES[_bridge]: if _system['SYSTEM'] == self._system and _system['TGID'] == _dst_id and _system['TS'] == _slot and _system['ACTIVE'] == True: - _sysIgnore = self.to_target(_peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data, pkt_time, dmrpkt, _bits,_bridge,_system,False,_sysIgnore,_hops) + _sysIgnore = self.to_target(_peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data, pkt_time, dmrpkt, _bits,_bridge,_system,False,_sysIgnore,_hops, _source_server, _ber, _rssi) # Final actions - Is this a voice terminator? @@ -1862,7 +1863,7 @@ class routerHBP(HBSYSTEM): } } - def to_target(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data, pkt_time, dmrpkt, _bits,_bridge,_system,_noOBP,sysIgnore): + def to_target(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data, pkt_time, dmrpkt, _bits,_bridge,_system,_noOBP,sysIgnore,_source_server, _ber, _rssi): _sysIgnore = sysIgnore for _target in BRIDGES[_bridge]: #if _target['SYSTEM'] != self._system or (_target['SYSTEM'] == self._system and _target['TS'] != _slot): @@ -2029,7 +2030,7 @@ class routerHBP(HBSYSTEM): _tmp_data = b''.join([_tmp_data, dmrpkt, _data[53:55]]) # Transmit the packet to the destination system - systems[_target['SYSTEM']].send_system(_tmp_data,None) + systems[_target['SYSTEM']].send_system(_tmp_data,b'',_source_server,_ber,_rssi) return _sysIgnore @@ -2078,7 +2079,7 @@ class routerHBP(HBSYSTEM): #Assemble transmit HBP packet header _tmp_data = b''.join([_data[:15], _tmp_bits.to_bytes(1, 'big'), _data[16:20]]) _tmp_data = b''.join([_tmp_data, dmrpkt]) - systems[_target].send_system(_tmp_data,None) + systems[_target].send_system(_tmp_data,b'',_source_server,_ber,_rssi) logger.info('(%s) UNIT Data Bridged to OBP System: %s DST_ID: %s', self._system, _target,_int_dst_id) if CONFIG['REPORTS']['REPORT']: systems[system]._report.send_bridgeEvent('UNIT DATA,START,TX,{},{},{},{},{},{}'.format(_target, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), 1, _int_dst_id).encode(encoding='utf-8', errors='ignore')) @@ -2087,8 +2088,14 @@ class routerHBP(HBSYSTEM): def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data): pkt_time = time() dmrpkt = _data[20:53] + + _ber = _data[53] + _rssi = _data[54] + _bits = _data[15] + _source_server = self._CONFIG['GLOBAL']['SERVER_ID'] + #_pkt_crc = Crc32.calc(_data[4:53]) #_pkt_crc = hash(_data).digest() @@ -2504,7 +2511,7 @@ class routerHBP(HBSYSTEM): if True: for _system in BRIDGES[_bridge]: if _system['SYSTEM'] == self._system and _system['TGID'] == _dst_id and _system['TS'] == _slot and _system['ACTIVE'] == True: - _sysIgnore = self.to_target(_peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data, pkt_time, dmrpkt, _bits,_bridge,_system,False,_sysIgnore) + _sysIgnore = self.to_target(_peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data, pkt_time, dmrpkt, _bits,_bridge,_system,False,_sysIgnore,_source_server,_ber,_rssi) #Send to reflector or TG too, if it exists if _bridge[0:1] == '#': @@ -2512,7 +2519,7 @@ class routerHBP(HBSYSTEM): else: _bridge = '#'+_bridge if _bridge in BRIDGES: - _sysIgnore = self.to_target(_peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data, pkt_time, dmrpkt, _bits,_bridge,_system,False,_sysIgnore) + _sysIgnore = self.to_target(_peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data, pkt_time, dmrpkt, _bits,_bridge,_system,False,_sysIgnore,_source_server,_ber,_rssi) # Final actions - Is this a voice terminator? if (_frame_type == HBPF_DATA_SYNC) and (_dtype_vseq == HBPF_SLT_VTERM) and (self.STATUS[_slot]['RX_TYPE'] != HBPF_SLT_VTERM): diff --git a/doc/FreeDMR FBP Proto v4.ods b/doc/FreeDMR FBP Proto v4.ods index 8fc2803f2a7de478752d669ee49fb54fac8dbd1a..334ee9d58a5d7f2bf7d1394f6e60c19bdc2d9b11 100644 GIT binary patch delta 4554 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 delta 4490 zcmY*d1yqz>w;mXpkp}6O9%87OVUP|PrR$TDmTp99KvGIz5Re!oq@)z-7!Z|Iq#J4J z?!5AS_q+dp&pPWodq2;5&wAH7XRW=@ljl3@1JXtU@n`@5A^@NyBMGF7`)7S3@%PG^ zR8RH4!S-!{Ucuo+Z%KpDqBumiY1yCD6o>9#1qB6>{Aa5_D)b*k>K0gWW&S|539c;8 zZJGgOM)kT*iBdG52;%V=#gMCfRPG}AsWhMzLsv|CXxFu*YKcS>sHklJGSd33!{$Gf zVCU=W`)>a_P+~y*)KI2LMW~PuS1^09b|R0hNeilWG7>c?d*6{*5jMfnP7oNbtrj+1 zo42R&2JBBV&rP&;aeo^CC#}_&HHIk#0Tp z_=sY&`&WrkQ^DsS;6AetRW+zYMPnX+wo*0Ro_Kn3F=XBvjqv=~c zmsgOb*2s;jv9EN5F~$OnP#9^P5py!oeEBX44gw*Z$ptiFohjC-n|!ng+N^KuvQHDVDP$ePv9H^-t%GMn{A)2>P zd_}#2V4><-@~m-(!N)HxVT4--A2`*hD3g1)D}>f6c7954qPOt&2UmQ^d01{8Ejk(@ml{pKRSPw<_y_0b4RTF zP>L>?|ERtot+1^Q6+;n*8tL;Wt{^<=X;Y*f+bWsN=WUgSO~JTc>d@0UuV zA-)g2J{V_#;r4M_-;31r;u)w?2m4BjrVn124f{6Dh!qv8-IK%w88`RBQpFjzm#Tz? zh5KwIc(X-Wg~fxkL;DCybgSY*FErQ~p>Z5x?aeRe^Z$azW~1Um@?4SgMo((`uw*-G z+aSdlNO(aKDeUem>ErRaE?59hRJz9-y@2fuDCU5j}SNlnXL-t=z8x7(;wlnz1 z=-A2V-wtNx+$w3r)}~t?02L0_qS!`V8t}Pok{L|N%vZ%^$u_Pb05m0O##rxUyDShg zxh}9!UP2d8gnI1G#=^@>t}xi>#Xp(+3P1QTe-b;g`VG6G`H?16%#s!v-Lo|UZZX&6 zHS*#8VO6mt%2L_d;oY2E_tWD_Ee(3G7w*YKQ6;gnzs399_1MSqa$FdO$^^py`32o!F*FW;^4v#^JqJ^}d`B zOOP@Ap?QkZQxBs|xT`I4O;$R*iau)wH1 zfX!NP4@C^gqx=zJqN>Sw-o9RX6u>CH*9mSsw2Mtq7WB6!p%fP3@%ykF!Kd@3)!V}X z!+%1(BXy#5(Zh}8;bObFybC!ue(91~MOObhkwPkLn-1fkT-0R*oR6#*OR*biv_Dxh zg@8zYNm9X_qSWsr;SGI{wNmG`_9P&tRB%c1fQeD^zRYmwVZr^pkgt!dPl+UDzVa1K`f1Z&CEMvuo2^ zmzVO+S3{Oe%#L*jdX^iQi5Z}^r8~T7qNSZ<+|R&&(fI>DXop7UoznUW=yDD8>{4n4 zB|;m0fzyvqFO(Xr4$SWYpD~lQn>w`dyxtc37P#o_fu|O6H#G$``dV92O<^ipSK9MAMmij0Rfn>3MjrZMw2>9YWEj zV!GhDhLiv+J?Db3ZhO`A437c;>M_h~psjS5Z_gHgpKP$epuaT6dt$I=yar^Lu7&RX`Crh}x^kfxQE9e9~C_O&Ozr{5v%7UQi^zs`EnN#A3{wRglz<}MS6;$FW1p0w~M z68_*;y3_5I7EN!;#;dO7Ao4wKV{kgshH zEmmn!o({f&1N#qJ*z!6&W!=+Hkt~UqsjZBP+X@*L6^|B!$cYagnuWeRIoP+t^A$3A#uI|uCW%7K)^yL=ndMchydtW(UOJ6RC zVKyG)8c7ZhVFG|1y>w)4O^3ZkWbnFq}kOpTGW)?E5cwXzXR&`kJyTgJ#`W}M!;HwA` z!A1Zl!yda8)$l!(4!L_j2|4bdTebJ8;4FG+%npv{Z*CH|g4Q*uiErX)>zqP`8{s5= zfGfK-|AMj3HvV!bh?8X{SABJuf4DcCX0qQql=I22Ffo{v+GJGy>Y6GoSq?b%^(lQ< zDL?1U^=~W<@JE>U&P$^7KrQ)3c*rH|+3Hn6dtnJf$D1XT-RZpWl`YuNP|OTJPRiZe z8v)l*XPMaXS8seRwYzle=V#&Y1+QLcA5Wn;U6FfRl0y91D4=!G`k3jY=z&1HJMH%f zCtwg+?91MjB%UJo#gJ=&N#gwX&YO|#_aOW=jsBIX8HGxejv0=j+z9rRA3WcFK)bV~ zJAyFZi>Ma)T-mH4(y%N&G&Z;Ye(MH2cP@9^JH)8XToV3iD_!OPfA4_yq~$`XQv_qN zoXZ=p1s#)3%D;dmuGJ0Waj80{0QnD@?TX(h3}deehD}FbJJZ=ZZ8#oK;1y!G9sC=y z4)tdr_xHY1K@#{Hz$tS45v1zO>zoiQ_+gypp4U8bv62a%$w4@3wjO?;JFhF3!jlM_ zxDY{hcn2N>1K7 zZ_mm*&vHY-d(Tdk_}^6mtvAbUyXRu^OjB!rSLUOuUoqBZ+FFfopD>N-lg78O9S^xp zZ?1flrAZ12-pq`hSvH<>lNtAQ2B(NW|y{{n-NQBs;I&k;7w6I?_$TyRAy>zg=W~upr?ka#imDpX6s4uBLTdlej;a`btbCi zGD?=P3_w&=@zi0i%@Iy|2ehFzHaMHo^yKNV?W(BTREiamdaf7>nBEchJ`6gT`BQRE z1EFCh)*-Rp0dpT^NMUI>t%bgu(Jbv!yX&cIp-VDeo0yfg%B(6@i-WWUEju3N$WaD4 zDtD4(B*Va}pl`!mQL70f#)$)8f-!~iRl9hX9JJ3BuyrfdT%E<>7=9T>;ny3E?>v2i zB0Dp}^!!7Ry-KK@rxNQ5b3O6e!WzlSoZ^qjR!=U)Xgm*yj%wWW`h5J1=lb)wU!GzL z$f1Q45SiKsS46E3Gupc?$dn2ucEeM*F`J%o~9DgyW42j z7PElHWg zjQEdxE$>icxqYe?q}@(k*|T#SKnQvJiCMx78F6x4?2E_`*EGYf;?^64q7ArYXZ>U~ zht_92SzLo@rUK%Mne{t8IT>rH0y#C|YwTRlv!*nTMpF)0(pY6;5;yfL#f4}JW(PTp z+JMOX6*fj|S@V4Pqv=Cjqtw$wjPEydR1U5YS`hW3$22EwnYiVJGoP03zO9>nb6DUW zK;?sHIbU*{7~a`~NmcfcvW{YrMFE8KHpatHZ5}6TEbWnUNEyW)s-tUR{@HrDfhs*p zi}E#NkU1t_;eGRmLh?{amSXJCuX^VM-psk+L4msRwZyg7lEe6mo;gig&9A0myk6Bz z=LM)zpwC&(QxgMO+53(AIoo52qg#Cajg5{;g(*$CWoto?c8V1@GML`tjl1w~%*Qew z6)A0=(#z;n#l4amK-9&i9V4GR8?n)J?%-80Hjj_kZB|Y`5keUmUOq3KA3!fpv~akd z+4k?vv>nTk%J;=jfst7rEWgpel!ovYBLWumki%g_hIzT=nL|;_Z{$|+>(-0pl9c0kqeY9`DzHP~ z8utqy0Jz8VZxy(;8g9LSXr>y5Ta=UZ{@W9%k-D`V&|=ceXhLbee?sMd8T3EQJd_zd zAuVvr;zQMM;g)fN{>`NQ%c$N8{4nG#_`;xfN-`el|KCd%-2~&m6;@zUWVgb9$`o1v zE{M3L{`;Rnfd3wBv;csYt+%&>tG$=7pNq3L5(k$C@UMM>PJ%PzK+zR&UiRB 3: _ver = VER.to_bytes(1,'big') - _packet = b''.join([DMRE,_packet[4:11], self._CONFIG['GLOBAL']['SERVER_ID'],_packet[15:],_ver,time_ns().to_bytes(8,'big'), _source_server, _hops]) + _packet = b''.join([DMRE,_packet[4:11], self._CONFIG['GLOBAL']['SERVER_ID'],_packet[15:],_ber,_rssi,_ver,time_ns().to_bytes(8,'big'), _source_server, _hops]) _h = blake2b(key=self._config['PASSPHRASE'], digest_size=16) _h.update(_packet) _hash = _h.digest() @@ -233,7 +233,7 @@ class OPENBRIDGE(DatagramProtocol): - def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data,_hash,_hops = b''): + def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data,_hash,_hops = b'', _source_server = b'\x00\x00\x00\x00', _ber = b'\x00', _rssi = b'\x00'): pass #print(int_id(_peer_id), int_id(_rf_src), int_id(_dst_id), int_id(_seq), _slot, _call_type, _frame_type, repr(_dtype_vseq), int_id(_stream_id)) @@ -342,14 +342,16 @@ class OPENBRIDGE(DatagramProtocol): elif _packet[:4] == DMRE: _data = _packet[:53] - _embedded_version = _packet[53] - _timestamp = _packet[54:62] - _source_server = _packet[62:66] - _hops = _packet[66] - _hash = _packet[67:83] + _ber = _packet[53] + _rssi = _packet[54] + _embedded_version = _packet[55] + _timestamp = _packet[56:64] + _source_server = _packet[64:68] + _hops = _packet[68] + _hash = _packet[69:85] #_ckhs = hmac_new(self._config['PASSPHRASE'],_data,sha1).digest() _h = blake2b(key=self._config['PASSPHRASE'], digest_size=16) - _h.update(_packet[:67]) + _h.update(_packet[:69]) _ckhs = _h.digest() @@ -439,13 +441,13 @@ class OPENBRIDGE(DatagramProtocol): _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) #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[:67]), len(_packet[67:]), 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: @@ -730,8 +732,9 @@ class HBSYSTEM(DatagramProtocol): def updateSockaddr_errback(self,failure): logger.info('(%s) hostname resolution error: %s',self._system,failure) - def send_peers(self, _packet, _hops = b''): + def send_peers(self, _packet, _hops = b'',_source_server = b'\x00\x00\x00\x00', _ber = b'\x00', _rssi = b'\x00'): for _peer in self._peers: + _packet =b''.join([_packet,_ber,_rssi]) self.send_peer(_peer, _packet) #logger.debug('(%s) Packet sent to peer %s', self._system, self._peers[_peer]['RADIO_ID']) @@ -742,9 +745,9 @@ class HBSYSTEM(DatagramProtocol): # KEEP THE FOLLOWING COMMENTED OUT UNLESS YOU'RE DEBUGGING DEEPLY!!!! #logger.debug('(%s) TX Packet to %s on port %s: %s', self._peers[_peer]['RADIO_ID'], self._peers[_peer]['IP'], self._peers[_peer]['PORT'], ahex(_packet)) - def send_master(self, _packet, _hops = b''): + def send_master(self, _packet, _hops = b'',_source_server = b'\x00\x00\x00\x00', _ber = b'\x00', _rssi = b'\x00'): if _packet[:4] == DMRD: - _packet = b''.join([_packet[:11], self._config['RADIO_ID'], _packet[15:]]) + _packet = b''.join([_packet[:11], self._config['RADIO_ID'], _packet[15:],_ber,_rssi]) self.transport.write(_packet, self._config['MASTER_SOCKADDR']) # KEEP THE FOLLOWING COMMENTED OUT UNLESS YOU'RE DEBUGGING DEEPLY!!!! #logger.debug('(%s) TX Packet to %s:%s -- %s', self._system, self._config['MASTER_IP'], self._config['MASTER_PORT'], ahex(_packet)) From cca1f3e4833d376f9bef1d63a06d61ea9a3f7535 Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 13 Feb 2022 23:52:00 +0000 Subject: [PATCH 17/41] hmm --- bridge_master.py | 8 ++++---- doc/FreeDMR FBP Proto v4.ods | Bin 15138 -> 15718 bytes hblink.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bridge_master.py b/bridge_master.py index 74bf38d..2435306 100644 --- a/bridge_master.py +++ b/bridge_master.py @@ -1409,7 +1409,7 @@ class routerOBP(OPENBRIDGE): _tmp_data = b''.join([_tmp_data, dmrpkt]) # Transmit the packet to the destination system - systems[_target['SYSTEM']].send_system(_tmp_data,_hops,_source_server, _ber, _rssi) + systems[_target['SYSTEM']].send_system(_tmp_data,_hops,_ber,_rssi,_source_server) #logger.debug('(%s) Packet routed by bridge: %s to system: %s TS: %s, TGID: %s', self._system, _bridge, _target['SYSTEM'], _target['TS'], int_id(_target['TGID'])) #Ignore this system and TS pair if it's called again on this packet return(_sysIgnore) @@ -1458,7 +1458,7 @@ class routerOBP(OPENBRIDGE): #Assemble transmit HBP packet header _tmp_data = b''.join([_data[:15], _tmp_bits.to_bytes(1, 'big'), _data[16:20]]) _tmp_data = b''.join([_tmp_data, dmrpkt]) - systems[_target].send_system(_tmp_data,_hops, _source_server, _ber, _rssi) + systems[_target].send_system(_tmp_data,_hops,_ber,_rssi, _source_server) logger.info('(%s) UNIT Data Bridged to OBP System: %s DST_ID: %s', self._system, _target,_int_dst_id) if CONFIG['REPORTS']['REPORT']: systems[_target]._report.send_bridgeEvent('UNIT DATA,START,TX,{},{},{},{},{},{}'.format(_target, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), 1, _int_dst_id).encode(encoding='utf-8', errors='ignore')) @@ -2030,7 +2030,7 @@ class routerHBP(HBSYSTEM): _tmp_data = b''.join([_tmp_data, dmrpkt, _data[53:55]]) # Transmit the packet to the destination system - systems[_target['SYSTEM']].send_system(_tmp_data,b'',_source_server,_ber,_rssi) + systems[_target['SYSTEM']].send_system(_tmp_data,b'',ber,_rssi,_source_server) return _sysIgnore @@ -2079,7 +2079,7 @@ class routerHBP(HBSYSTEM): #Assemble transmit HBP packet header _tmp_data = b''.join([_data[:15], _tmp_bits.to_bytes(1, 'big'), _data[16:20]]) _tmp_data = b''.join([_tmp_data, dmrpkt]) - systems[_target].send_system(_tmp_data,b'',_source_server,_ber,_rssi) + systems[_target].send_system(_tmp_data,b'',ber,_rssi,_source_server) logger.info('(%s) UNIT Data Bridged to OBP System: %s DST_ID: %s', self._system, _target,_int_dst_id) if CONFIG['REPORTS']['REPORT']: systems[system]._report.send_bridgeEvent('UNIT DATA,START,TX,{},{},{},{},{},{}'.format(_target, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), 1, _int_dst_id).encode(encoding='utf-8', errors='ignore')) diff --git a/doc/FreeDMR FBP Proto v4.ods b/doc/FreeDMR FBP Proto v4.ods index 334ee9d58a5d7f2bf7d1394f6e60c19bdc2d9b11..f2f2a32e64c7b7259163d01e19b25ee98bf16924 100644 GIT binary patch delta 13715 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 Z@z>nHUGAKT3hda4$UL85Pr3e)|1Ta7@nHY} delta 13093 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 Date: Mon, 14 Feb 2022 01:28:51 +0000 Subject: [PATCH 18/41] BER --- bridge_master.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridge_master.py b/bridge_master.py index 2435306..0f3384c 100644 --- a/bridge_master.py +++ b/bridge_master.py @@ -2030,7 +2030,7 @@ class routerHBP(HBSYSTEM): _tmp_data = b''.join([_tmp_data, dmrpkt, _data[53:55]]) # Transmit the packet to the destination system - systems[_target['SYSTEM']].send_system(_tmp_data,b'',ber,_rssi,_source_server) + systems[_target['SYSTEM']].send_system(_tmp_data,b'',_ber,_rssi,_source_server) return _sysIgnore From 5bdfad300f5980889d6348713c4c1406407386d7 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 14 Feb 2022 01:42:45 +0000 Subject: [PATCH 19/41] bg --- hblink.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hblink.py b/hblink.py index 314ab7b..2bcd73f 100755 --- a/hblink.py +++ b/hblink.py @@ -342,8 +342,8 @@ class OPENBRIDGE(DatagramProtocol): elif _packet[:4] == DMRE: _data = _packet[:53] - _ber = _packet[53] - _rssi = _packet[54] + _ber = _packet[53:54] + _rssi = _packet[54:55] _embedded_version = _packet[55] _timestamp = _packet[56:64] _source_server = _packet[64:68] From a45e85c5048238b732e6f7e699baa78cdd5d8155 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 14 Feb 2022 18:52:12 +0000 Subject: [PATCH 20/41] f --- hblink.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hblink.py b/hblink.py index 2bcd73f..e58a5d4 100755 --- a/hblink.py +++ b/hblink.py @@ -159,7 +159,7 @@ class OPENBRIDGE(DatagramProtocol): if 'VER' in self._config and self._config['VER'] > 3: _ver = VER.to_bytes(1,'big') - _packet = b''.join([DMRE,_packet[4:11], self._CONFIG['GLOBAL']['SERVER_ID'],_packet[15:],_ber,_rssi,_ver,time_ns().to_bytes(8,'big'), _source_server, _hops]) + _packet = b''.join([DMRE,_packet[4:11], self._CONFIG['GLOBAL']['SERVER_ID'],_packet[15:],_ber.to_bytes(1,'big'),_rssi.to_bytes(1,'big'),_ver,time_ns().to_bytes(8,'big'), _source_server.to_bytes(4,'big'), _hops]) _h = blake2b(key=self._config['PASSPHRASE'], digest_size=16) _h.update(_packet) _hash = _h.digest() @@ -342,8 +342,8 @@ class OPENBRIDGE(DatagramProtocol): elif _packet[:4] == DMRE: _data = _packet[:53] - _ber = _packet[53:54] - _rssi = _packet[54:55] + _ber = _packet[53] + _rssi = _packet[54] _embedded_version = _packet[55] _timestamp = _packet[56:64] _source_server = _packet[64:68] @@ -732,9 +732,9 @@ class HBSYSTEM(DatagramProtocol): def updateSockaddr_errback(self,failure): logger.info('(%s) hostname resolution error: %s',self._system,failure) - def send_peers(self, _packet, _hops = b'', _ber = b'\x00', _rssi = b'\x00',_source_server = b'\x00\x00\x00\x00'): + def send_peers(self, _packet, _hops = b'', _ber = b'\x00', _rssi = b'\x00',_source_server = b'\x00\x00\x00\x00', _ber = b'\x00', _rssi = b'\x00'): for _peer in self._peers: - _packet =b''.join([_packet,_ber,_rssi]) + _packet =b''.join([_packet,_ber.to_bytes(1,'big'),_rssi.to_bytes(1,'big')]) self.send_peer(_peer, _packet) #logger.debug('(%s) Packet sent to peer %s', self._system, self._peers[_peer]['RADIO_ID']) @@ -747,7 +747,7 @@ class HBSYSTEM(DatagramProtocol): def send_master(self, _packet, _hops = b'', _ber = b'\x00', _rssi = b'\x00',_source_server = b'\x00\x00\x00\x00'): if _packet[:4] == DMRD: - _packet = b''.join([_packet[:11], self._config['RADIO_ID'], _packet[15:],_ber,_rssi]) + _packet = b''.join([_packet[:11], self._config['RADIO_ID'], _packet[15:],_ber.to_bytes(1,'big'),_rssi.to_bytes(1,'big')]) self.transport.write(_packet, self._config['MASTER_SOCKADDR']) # KEEP THE FOLLOWING COMMENTED OUT UNLESS YOU'RE DEBUGGING DEEPLY!!!! #logger.debug('(%s) TX Packet to %s:%s -- %s', self._system, self._config['MASTER_IP'], self._config['MASTER_PORT'], ahex(_packet)) From 89a51598368077a6082937a3a31ffa77ecb68f73 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 14 Feb 2022 18:55:24 +0000 Subject: [PATCH 21/41] ff --- hblink.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hblink.py b/hblink.py index e58a5d4..98e924b 100755 --- a/hblink.py +++ b/hblink.py @@ -732,7 +732,7 @@ class HBSYSTEM(DatagramProtocol): def updateSockaddr_errback(self,failure): logger.info('(%s) hostname resolution error: %s',self._system,failure) - def send_peers(self, _packet, _hops = b'', _ber = b'\x00', _rssi = b'\x00',_source_server = b'\x00\x00\x00\x00', _ber = b'\x00', _rssi = b'\x00'): + def send_peers(self, _packet, _hops = b'', _ber = b'\x00', _rssi = b'\x00',_source_server = b'\x00\x00\x00\x00'): for _peer in self._peers: _packet =b''.join([_packet,_ber.to_bytes(1,'big'),_rssi.to_bytes(1,'big')]) self.send_peer(_peer, _packet) From 3aaced2e6a2e2a51e1d2fed111cb316b176f9a05 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 14 Feb 2022 19:09:05 +0000 Subject: [PATCH 22/41] Keep ber and rssi as bytes --- hblink.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hblink.py b/hblink.py index 98e924b..84b5867 100755 --- a/hblink.py +++ b/hblink.py @@ -342,8 +342,8 @@ class OPENBRIDGE(DatagramProtocol): elif _packet[:4] == DMRE: _data = _packet[:53] - _ber = _packet[53] - _rssi = _packet[54] + _ber = _packet[53:54] + _rssi = _packet[54:55] _embedded_version = _packet[55] _timestamp = _packet[56:64] _source_server = _packet[64:68] @@ -734,7 +734,7 @@ class HBSYSTEM(DatagramProtocol): def send_peers(self, _packet, _hops = b'', _ber = b'\x00', _rssi = b'\x00',_source_server = b'\x00\x00\x00\x00'): for _peer in self._peers: - _packet =b''.join([_packet,_ber.to_bytes(1,'big'),_rssi.to_bytes(1,'big')]) + _packet =b''.join([_packet,_ber,_rssi]) self.send_peer(_peer, _packet) #logger.debug('(%s) Packet sent to peer %s', self._system, self._peers[_peer]['RADIO_ID']) @@ -747,7 +747,7 @@ class HBSYSTEM(DatagramProtocol): def send_master(self, _packet, _hops = b'', _ber = b'\x00', _rssi = b'\x00',_source_server = b'\x00\x00\x00\x00'): if _packet[:4] == DMRD: - _packet = b''.join([_packet[:11], self._config['RADIO_ID'], _packet[15:],_ber.to_bytes(1,'big'),_rssi.to_bytes(1,'big')]) + _packet = b''.join([_packet[:11], self._config['RADIO_ID'], _packet[15:],_ber,_rssi]) self.transport.write(_packet, self._config['MASTER_SOCKADDR']) # KEEP THE FOLLOWING COMMENTED OUT UNLESS YOU'RE DEBUGGING DEEPLY!!!! #logger.debug('(%s) TX Packet to %s:%s -- %s', self._system, self._config['MASTER_IP'], self._config['MASTER_PORT'], ahex(_packet)) From 0d568e4ba17aba2e42e0fadc84aed4d8f4bcc28b Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 14 Feb 2022 19:13:17 +0000 Subject: [PATCH 23/41] dd --- bridge_master.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bridge_master.py b/bridge_master.py index 0f3384c..480b0e9 100644 --- a/bridge_master.py +++ b/bridge_master.py @@ -2089,8 +2089,8 @@ class routerHBP(HBSYSTEM): pkt_time = time() dmrpkt = _data[20:53] - _ber = _data[53] - _rssi = _data[54] + _ber = _data[53:54] + _rssi = _data[54:55] _bits = _data[15] From 41805929a7369ff5d1904468e740d9e8fd784e04 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 14 Feb 2022 19:18:30 +0000 Subject: [PATCH 24/41] Log rssi and ber integer values, not bytes --- bridge_master.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridge_master.py b/bridge_master.py index 480b0e9..96077c8 100644 --- a/bridge_master.py +++ b/bridge_master.py @@ -1657,7 +1657,7 @@ class routerOBP(OPENBRIDGE): if _hops: _inthops = int.from_bytes(_hops,'big') logger.info('(%s) *CALL START* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, SRC: %s, BER: %s, RSSI %s, HOPS %s', \ - self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot,int_id(_source_server),_ber,_rssi,_inthops) + self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot,int_id(_source_server),int.from_bytes(_ber,'big'),int.from_bytes(_rssi,'big'),_inthops) if CONFIG['REPORTS']['REPORT']: self._report.send_bridgeEvent('GROUP VOICE,START,RX,{},{},{},{},{},{}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id)).encode(encoding='utf-8', errors='ignore')) From 118e99dc2060005406f8299e435633ce38ff25f8 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 14 Feb 2022 19:29:42 +0000 Subject: [PATCH 25/41] dlkdlk --- hblink.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hblink.py b/hblink.py index 84b5867..2bcd73f 100755 --- a/hblink.py +++ b/hblink.py @@ -159,7 +159,7 @@ class OPENBRIDGE(DatagramProtocol): if 'VER' in self._config and self._config['VER'] > 3: _ver = VER.to_bytes(1,'big') - _packet = b''.join([DMRE,_packet[4:11], self._CONFIG['GLOBAL']['SERVER_ID'],_packet[15:],_ber.to_bytes(1,'big'),_rssi.to_bytes(1,'big'),_ver,time_ns().to_bytes(8,'big'), _source_server.to_bytes(4,'big'), _hops]) + _packet = b''.join([DMRE,_packet[4:11], self._CONFIG['GLOBAL']['SERVER_ID'],_packet[15:],_ber,_rssi,_ver,time_ns().to_bytes(8,'big'), _source_server, _hops]) _h = blake2b(key=self._config['PASSPHRASE'], digest_size=16) _h.update(_packet) _hash = _h.digest() From 36e9b8057c5c7bd3ac505adeabc01e221783a426 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 14 Feb 2022 23:07:18 +0000 Subject: [PATCH 26/41] Server should take responsibility for the the source of V1 (OBP) bridge traffic --- bridge_master.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bridge_master.py b/bridge_master.py index 96077c8..9918ee7 100644 --- a/bridge_master.py +++ b/bridge_master.py @@ -1468,7 +1468,11 @@ class routerOBP(OPENBRIDGE): pkt_time = time() dmrpkt = _data[20:53] _bits = _data[15] - + + #If this is a v1 bridge, this server takes responsibility for traffic. + if CONFIG['SYSTEMS'][system]['VER'] == 1: + _source_server = self._CONFIG['GLOBAL']['SERVER_ID'] + #pkt_crc = Crc32.calc(_data[4:53]) #_pkt_crc = Crc32.calc(dmrpkt) From b61ea48e5d39900950c299a0768a35720d436b7a Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 14 Feb 2022 23:11:50 +0000 Subject: [PATCH 27/41] Revert "Server should take responsibility for the the source of V1 (OBP) bridge traffic" This reverts commit 36e9b8057c5c7bd3ac505adeabc01e221783a426. --- bridge_master.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/bridge_master.py b/bridge_master.py index 9918ee7..96077c8 100644 --- a/bridge_master.py +++ b/bridge_master.py @@ -1468,11 +1468,7 @@ class routerOBP(OPENBRIDGE): pkt_time = time() dmrpkt = _data[20:53] _bits = _data[15] - - #If this is a v1 bridge, this server takes responsibility for traffic. - if CONFIG['SYSTEMS'][system]['VER'] == 1: - _source_server = self._CONFIG['GLOBAL']['SERVER_ID'] - + #pkt_crc = Crc32.calc(_data[4:53]) #_pkt_crc = Crc32.calc(dmrpkt) From cd57beebe35485b2579adf51773d91315708b27c Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 14 Feb 2022 23:39:01 +0000 Subject: [PATCH 28/41] Discard packets with old timestamp (low level) --- hblink.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hblink.py b/hblink.py index 2bcd73f..8bc7789 100755 --- a/hblink.py +++ b/hblink.py @@ -385,6 +385,11 @@ class OPENBRIDGE(DatagramProtocol): self._laststrid.append(_stream_id) return + #Discard old packets + if (_timestamp/1000000000) < (time() - 30): + logger.warning('(%s) Packet more than 30s old!, discarding', self._system) + return + #Increment max hops _inthops = _hops +1 From 441551c01b7b162ab10908a3dc7ae10c13556af4 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 14 Feb 2022 23:45:03 +0000 Subject: [PATCH 29/41] Need to convert bytes to int when comparing timestamp for out-of-time packets --- hblink.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hblink.py b/hblink.py index 8bc7789..4084003 100755 --- a/hblink.py +++ b/hblink.py @@ -386,7 +386,7 @@ class OPENBRIDGE(DatagramProtocol): return #Discard old packets - if (_timestamp/1000000000) < (time() - 30): + if (int.from_bytes(_timestamp,'big')/1000000000) < (time() - 30): logger.warning('(%s) Packet more than 30s old!, discarding', self._system) return From f4f97dfa0f083758d6b2fdecd6c7ae0149794d26 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 14 Feb 2022 23:59:09 +0000 Subject: [PATCH 30/41] Get proto version from the embedded value in proto v4 --- hblink.py | 1 + 1 file changed, 1 insertion(+) diff --git a/hblink.py b/hblink.py index 4084003..0630a0e 100755 --- a/hblink.py +++ b/hblink.py @@ -345,6 +345,7 @@ class OPENBRIDGE(DatagramProtocol): _ber = _packet[53:54] _rssi = _packet[54:55] _embedded_version = _packet[55] + self._config['VER'] = _embedded_version _timestamp = _packet[56:64] _source_server = _packet[64:68] _hops = _packet[68] From 415f3d77324954047c4cf69b298df2114b993c81 Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 15 Feb 2022 00:21:13 +0000 Subject: [PATCH 31/41] Fix text to OBP --- bridge_master.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bridge_master.py b/bridge_master.py index 96077c8..7bca09b 100644 --- a/bridge_master.py +++ b/bridge_master.py @@ -1729,7 +1729,6 @@ class routerOBP(OPENBRIDGE): logger.warning("(%s) *PacketControl* RATE DROP! Stream ID:, %s TGID: %s",self._system,int_id(_stream_id),int_id(_dst_id)) return - #Duplicate handling# #Handle inbound duplicates #Duplicate complete packet @@ -2079,7 +2078,7 @@ class routerHBP(HBSYSTEM): #Assemble transmit HBP packet header _tmp_data = b''.join([_data[:15], _tmp_bits.to_bytes(1, 'big'), _data[16:20]]) _tmp_data = b''.join([_tmp_data, dmrpkt]) - systems[_target].send_system(_tmp_data,b'',ber,_rssi,_source_server) + systems[_target].send_system(_tmp_data,b'',_ber,_rssi,_source_server) logger.info('(%s) UNIT Data Bridged to OBP System: %s DST_ID: %s', self._system, _target,_int_dst_id) if CONFIG['REPORTS']['REPORT']: systems[system]._report.send_bridgeEvent('UNIT DATA,START,TX,{},{},{},{},{},{}'.format(_target, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), 1, _int_dst_id).encode(encoding='utf-8', errors='ignore')) From c9d8a4512d22a9ce2b95fce5aa3677e925d37cc6 Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 15 Feb 2022 00:23:39 +0000 Subject: [PATCH 32/41] ddd --- bridge_master.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridge_master.py b/bridge_master.py index 7bca09b..74c1b88 100644 --- a/bridge_master.py +++ b/bridge_master.py @@ -2043,7 +2043,7 @@ class routerHBP(HBSYSTEM): if CONFIG['REPORTS']['REPORT']: systems[_d_system]._report.send_bridgeEvent('UNIT DATA,START,TX,{},{},{},{},{},{}'.format(_d_system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), 1, _int_dst_id).encode(encoding='utf-8', errors='ignore')) - def sendDataToOBP(self,_target,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_hops = b''): + def sendDataToOBP(self,_target,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_hops = b'',_ber = b'\x00', _rssi = b'\x00',_source_server = b'\x00\x00\x00\x00'): # _sysIgnore = sysIgnore _int_dst_id = int_id(_dst_id) _target_status = systems[_target].STATUS From 3cb6da9ec46cf98cebc63d0af6a215230099e61d Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 15 Feb 2022 15:27:17 +0000 Subject: [PATCH 34/41] S --- bridge_master.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridge_master.py b/bridge_master.py index 74c1b88..ec7bc6a 100644 --- a/bridge_master.py +++ b/bridge_master.py @@ -2052,7 +2052,7 @@ class routerHBP(HBSYSTEM): #We want to ignore this system and TS combination if it's called again for this packet # _sysIgnore.append((_target,_target['TS'])) - #If target has missed 6 (on 1 min) of keepalives, don't send + #If target has missed 6 (in 1 min) of keepalives, don't send if _target_system['ENHANCED_OBP'] and '_bcka' in _target_system and _target_system['_bcka'] < pkt_time - 60: return From e9e60c5ed150b4ec0d85021f666414678091b123 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 16 Feb 2022 02:31:45 +0000 Subject: [PATCH 35/41] Log source and hops for unit data Only allow 2s packet validity --- bridge_master.py | 28 +++++++++++++++------------- hblink.py | 4 ++-- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/bridge_master.py b/bridge_master.py index ec7bc6a..fb50797 100644 --- a/bridge_master.py +++ b/bridge_master.py @@ -1477,6 +1477,10 @@ class routerOBP(OPENBRIDGE): _h.update(_data) _pkt_crc = _h.digest() + _inthops = 0 + if _hops: + _inthops = int.from_bytes(_hops,'big') + #_pkt_crc = _hash # Match UNIT data, SMS/GPS, and send it to the dst_id if it is in SUB_MAP @@ -1547,28 +1551,28 @@ class routerOBP(OPENBRIDGE): if _dtype_vseq == 3: - logger.info('(%s) *UNIT CSBK* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) DST_ID %s (%s), TS %s', \ - self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot) + logger.info('(%s) *UNIT CSBK* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) DST_ID %s (%s), TS %s, SRC %s, HOPS %s', \ + self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot,int_id(_source_server),_inthops) if CONFIG['REPORTS']['REPORT']: self._report.send_bridgeEvent('UNIT CSBK,START,RX,{},{},{},{},{},{}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id)).encode(encoding='utf-8', errors='ignore')) elif _dtype_vseq == 6: - logger.info('(%s) *UNIT DATA HEADER* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) DST_ID %s (%s), TS %s', \ - self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot) + logger.info('(%s) *UNIT DATA HEADER* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) DST_ID %s (%s), TS %s, SRC %s, HOPS %s', \ + self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot,int_id(_source_server),_inthops) if CONFIG['REPORTS']['REPORT']: self._report.send_bridgeEvent('UNIT DATA HEADER,START,RX,{},{},{},{},{},{}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id)).encode(encoding='utf-8', errors='ignore')) elif _dtype_vseq == 7: - logger.info('(%s) *UNIT VCSBK 1/2 DATA BLOCK * STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s', \ - self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot) + logger.info('(%s) *UNIT VCSBK 1/2 DATA BLOCK * STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, SRC %s, HOPS %s', \ + self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot,int_id(_source_server),_inthops) if CONFIG['REPORTS']['REPORT']: self._report.send_bridgeEvent('UNIT VCSBK 1/2 DATA BLOCK,START,RX,{},{},{},{},{},{}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id)).encode(encoding='utf-8', errors='ignore')) elif _dtype_vseq == 8: - logger.info('(%s) *UNIT VCSBK 3/4 DATA BLOCK * STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s', \ - self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot) + logger.info('(%s) *UNIT VCSBK 3/4 DATA BLOCK * STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, SRC %s, HOPS %s', \ + self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot,int_id(_source_server),_inthops) if CONFIG['REPORTS']['REPORT']: self._report.send_bridgeEvent('UNIT VCSBK 3/4 DATA BLOCK,START,RX,{},{},{},{},{},{}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id)).encode(encoding='utf-8', errors='ignore')) else: - logger.info('(%s) *UNKNOWN DATA TYPE* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s', \ - self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot) + logger.info('(%s) *UNKNOWN DATA TYPE* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, SRC %s, HOPS %s', \ + self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot,int_id(_source_server),_inthops) #Send other openbridges for system in systems: @@ -1653,9 +1657,7 @@ class routerOBP(OPENBRIDGE): else: self.STATUS[_stream_id]['LC'] = LC_OPT + _dst_id + _rf_src - _inthops = 0 - if _hops: - _inthops = int.from_bytes(_hops,'big') + logger.info('(%s) *CALL START* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, SRC: %s, BER: %s, RSSI %s, HOPS %s', \ self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot,int_id(_source_server),int.from_bytes(_ber,'big'),int.from_bytes(_rssi,'big'),_inthops) if CONFIG['REPORTS']['REPORT']: diff --git a/hblink.py b/hblink.py index 0630a0e..46be260 100755 --- a/hblink.py +++ b/hblink.py @@ -387,8 +387,8 @@ class OPENBRIDGE(DatagramProtocol): return #Discard old packets - if (int.from_bytes(_timestamp,'big')/1000000000) < (time() - 30): - logger.warning('(%s) Packet more than 30s old!, discarding', self._system) + if (int.from_bytes(_timestamp,'big')/1000000000) < (time() - 2): + logger.warning('(%s) Packet more than 2s old!, discarding', self._system) return #Increment max hops From ae76dd7c4fa7c71dfec84b7259d73883debcf6ff Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 16 Feb 2022 02:39:08 +0000 Subject: [PATCH 36/41] Source data for unit data packets --- bridge_master.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridge_master.py b/bridge_master.py index fb50797..85f23cb 100644 --- a/bridge_master.py +++ b/bridge_master.py @@ -2168,7 +2168,7 @@ class routerHBP(HBSYSTEM): continue #We only want to send data calls to individual IDs via OpenBridge if CONFIG['SYSTEMS'][system]['MODE'] == 'OPENBRIDGE' and CONFIG['SYSTEMS'][system]['VER'] > 1 and (_int_dst_id >= 1000000): - self.sendDataToOBP(system,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot) + self.sendDataToOBP(system,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_ber,_rssi,_source_server) #If destination ID is in the Subscriber Map From c59812f417c8351897d50c436150c5ad51e5c8d1 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 16 Feb 2022 02:47:40 +0000 Subject: [PATCH 37/41] 53 --- bridge_master.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridge_master.py b/bridge_master.py index 85f23cb..34795cd 100644 --- a/bridge_master.py +++ b/bridge_master.py @@ -2079,7 +2079,7 @@ class routerHBP(HBSYSTEM): _tmp_bits = _bits #Assemble transmit HBP packet header _tmp_data = b''.join([_data[:15], _tmp_bits.to_bytes(1, 'big'), _data[16:20]]) - _tmp_data = b''.join([_tmp_data, dmrpkt]) + _tmp_data = b''.join([_tmp_data, dmrpkt[:53]]) systems[_target].send_system(_tmp_data,b'',_ber,_rssi,_source_server) logger.info('(%s) UNIT Data Bridged to OBP System: %s DST_ID: %s', self._system, _target,_int_dst_id) if CONFIG['REPORTS']['REPORT']: From 741965351186458a142c70147b17c57aa9a0cc7a Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 16 Feb 2022 02:50:12 +0000 Subject: [PATCH 38/41] Revert "53" This reverts commit c59812f417c8351897d50c436150c5ad51e5c8d1. --- bridge_master.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridge_master.py b/bridge_master.py index 34795cd..85f23cb 100644 --- a/bridge_master.py +++ b/bridge_master.py @@ -2079,7 +2079,7 @@ class routerHBP(HBSYSTEM): _tmp_bits = _bits #Assemble transmit HBP packet header _tmp_data = b''.join([_data[:15], _tmp_bits.to_bytes(1, 'big'), _data[16:20]]) - _tmp_data = b''.join([_tmp_data, dmrpkt[:53]]) + _tmp_data = b''.join([_tmp_data, dmrpkt]) systems[_target].send_system(_tmp_data,b'',_ber,_rssi,_source_server) logger.info('(%s) UNIT Data Bridged to OBP System: %s DST_ID: %s', self._system, _target,_int_dst_id) if CONFIG['REPORTS']['REPORT']: From 301d22123fe2d1997b56de69c78d44c0e053b430 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 16 Feb 2022 02:50:27 +0000 Subject: [PATCH 39/41] Revert "Source data for unit data packets" This reverts commit ae76dd7c4fa7c71dfec84b7259d73883debcf6ff. --- bridge_master.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridge_master.py b/bridge_master.py index 85f23cb..fb50797 100644 --- a/bridge_master.py +++ b/bridge_master.py @@ -2168,7 +2168,7 @@ class routerHBP(HBSYSTEM): continue #We only want to send data calls to individual IDs via OpenBridge if CONFIG['SYSTEMS'][system]['MODE'] == 'OPENBRIDGE' and CONFIG['SYSTEMS'][system]['VER'] > 1 and (_int_dst_id >= 1000000): - self.sendDataToOBP(system,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_ber,_rssi,_source_server) + self.sendDataToOBP(system,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot) #If destination ID is in the Subscriber Map From 0fa45829cc93ab38f0b9c559752c07d1ea66bd07 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 16 Feb 2022 02:50:43 +0000 Subject: [PATCH 40/41] Revert "Log source and hops for unit data" This reverts commit e9e60c5ed150b4ec0d85021f666414678091b123. --- bridge_master.py | 28 +++++++++++++--------------- hblink.py | 4 ++-- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/bridge_master.py b/bridge_master.py index fb50797..ec7bc6a 100644 --- a/bridge_master.py +++ b/bridge_master.py @@ -1477,10 +1477,6 @@ class routerOBP(OPENBRIDGE): _h.update(_data) _pkt_crc = _h.digest() - _inthops = 0 - if _hops: - _inthops = int.from_bytes(_hops,'big') - #_pkt_crc = _hash # Match UNIT data, SMS/GPS, and send it to the dst_id if it is in SUB_MAP @@ -1551,28 +1547,28 @@ class routerOBP(OPENBRIDGE): if _dtype_vseq == 3: - logger.info('(%s) *UNIT CSBK* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) DST_ID %s (%s), TS %s, SRC %s, HOPS %s', \ - self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot,int_id(_source_server),_inthops) + logger.info('(%s) *UNIT CSBK* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) DST_ID %s (%s), TS %s', \ + self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot) if CONFIG['REPORTS']['REPORT']: self._report.send_bridgeEvent('UNIT CSBK,START,RX,{},{},{},{},{},{}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id)).encode(encoding='utf-8', errors='ignore')) elif _dtype_vseq == 6: - logger.info('(%s) *UNIT DATA HEADER* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) DST_ID %s (%s), TS %s, SRC %s, HOPS %s', \ - self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot,int_id(_source_server),_inthops) + logger.info('(%s) *UNIT DATA HEADER* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) DST_ID %s (%s), TS %s', \ + self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot) if CONFIG['REPORTS']['REPORT']: self._report.send_bridgeEvent('UNIT DATA HEADER,START,RX,{},{},{},{},{},{}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id)).encode(encoding='utf-8', errors='ignore')) elif _dtype_vseq == 7: - logger.info('(%s) *UNIT VCSBK 1/2 DATA BLOCK * STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, SRC %s, HOPS %s', \ - self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot,int_id(_source_server),_inthops) + logger.info('(%s) *UNIT VCSBK 1/2 DATA BLOCK * STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s', \ + self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot) if CONFIG['REPORTS']['REPORT']: self._report.send_bridgeEvent('UNIT VCSBK 1/2 DATA BLOCK,START,RX,{},{},{},{},{},{}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id)).encode(encoding='utf-8', errors='ignore')) elif _dtype_vseq == 8: - logger.info('(%s) *UNIT VCSBK 3/4 DATA BLOCK * STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, SRC %s, HOPS %s', \ - self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot,int_id(_source_server),_inthops) + logger.info('(%s) *UNIT VCSBK 3/4 DATA BLOCK * STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s', \ + self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot) if CONFIG['REPORTS']['REPORT']: self._report.send_bridgeEvent('UNIT VCSBK 3/4 DATA BLOCK,START,RX,{},{},{},{},{},{}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id)).encode(encoding='utf-8', errors='ignore')) else: - logger.info('(%s) *UNKNOWN DATA TYPE* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, SRC %s, HOPS %s', \ - self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot,int_id(_source_server),_inthops) + logger.info('(%s) *UNKNOWN DATA TYPE* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s', \ + self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot) #Send other openbridges for system in systems: @@ -1657,7 +1653,9 @@ class routerOBP(OPENBRIDGE): else: self.STATUS[_stream_id]['LC'] = LC_OPT + _dst_id + _rf_src - + _inthops = 0 + if _hops: + _inthops = int.from_bytes(_hops,'big') logger.info('(%s) *CALL START* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, SRC: %s, BER: %s, RSSI %s, HOPS %s', \ self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot,int_id(_source_server),int.from_bytes(_ber,'big'),int.from_bytes(_rssi,'big'),_inthops) if CONFIG['REPORTS']['REPORT']: diff --git a/hblink.py b/hblink.py index 46be260..0630a0e 100755 --- a/hblink.py +++ b/hblink.py @@ -387,8 +387,8 @@ class OPENBRIDGE(DatagramProtocol): return #Discard old packets - if (int.from_bytes(_timestamp,'big')/1000000000) < (time() - 2): - logger.warning('(%s) Packet more than 2s old!, discarding', self._system) + if (int.from_bytes(_timestamp,'big')/1000000000) < (time() - 30): + logger.warning('(%s) Packet more than 30s old!, discarding', self._system) return #Increment max hops From 2448469a11fecc6aff083a8456bf27b28dbe6c84 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 16 Feb 2022 02:53:01 +0000 Subject: [PATCH 41/41] Only 2s old packets --- hblink.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hblink.py b/hblink.py index 0630a0e..46be260 100755 --- a/hblink.py +++ b/hblink.py @@ -387,8 +387,8 @@ class OPENBRIDGE(DatagramProtocol): return #Discard old packets - if (int.from_bytes(_timestamp,'big')/1000000000) < (time() - 30): - logger.warning('(%s) Packet more than 30s old!, discarding', self._system) + if (int.from_bytes(_timestamp,'big')/1000000000) < (time() - 2): + logger.warning('(%s) Packet more than 2s old!, discarding', self._system) return #Increment max hops