Ejemplo n.º 1
0
def add_hb_peer(_peer_conf, _ctable_loc, _peer):
    _ctable_loc[int_id(_peer)] = {}
    _ctable_peer = _ctable_loc[int_id(_peer)]

    # if the Frequency is 000.xxx assume it's not an RF peer, otherwise format the text fields
    # (9 char, but we are just software)  see https://wiki.brandmeister.network/index.php/Homebrew/example/php2

    if _peer_conf['TX_FREQ'].isalnum() and _peer_conf['RX_FREQ'].isalnum():
        if _peer_conf['TX_FREQ'][:3] == b'000' or _peer_conf[
                'RX_FREQ'][:3] == b'000':
            _ctable_peer['TX_FREQ'] = 'N/A'
            _ctable_peer['RX_FREQ'] = 'N/A'
        else:
            _ctable_peer['TX_FREQ'] = _peer_conf['TX_FREQ'][:3].decode(
                'utf-8') + '.' + _peer_conf['TX_FREQ'][3:7].decode(
                    'utf-8') + ' MHz'
            _ctable_peer['RX_FREQ'] = _peer_conf['RX_FREQ'][:3].decode(
                'utf-8') + '.' + _peer_conf['RX_FREQ'][3:7].decode(
                    'utf-8') + ' MHz'
    else:
        _ctable_peer['TX_FREQ'] = 'N/A'
        _ctable_peer['RX_FREQ'] = 'N/A'
    # timeslots are kinda complicated too. 0 = none, 1 or 2 mean that one slot, 3 is both, and anything else it considered DMO
    # Slots (0, 1=1, 2=2, 1&2=3 Duplex, 4=Simplex) see https://wiki.brandmeister.network/index.php/Homebrew/example/php2

    if (_peer_conf['SLOTS'] == b'0'):
        _ctable_peer['SLOTS'] = 'NONE'
    elif (_peer_conf['SLOTS'] == b'1' or _peer_conf['SLOTS'] == b'2'):
        _ctable_peer['SLOTS'] = _peer_conf['SLOTS'].decode('utf-8')
    elif (_peer_conf['SLOTS'] == b'3'):
        _ctable_peer['SLOTS'] = 'Duplex'
    else:
        _ctable_peer['SLOTS'] = 'Simplex'

    # Simple translation items
    _ctable_peer['SOFTWARE_ID'] = _peer_conf['SOFTWARE_ID'].decode(
        'utf-8').strip()
    _ctable_peer['PACKAGE_ID'] = _peer_conf['PACKAGE_ID'].decode(
        'utf-8').strip()
    _ctable_peer['COLORCODE'] = _peer_conf['COLORCODE'].decode('utf-8')
    _ctable_peer['CALLSIGN'] = _peer_conf['CALLSIGN'].decode('utf-8')
    _ctable_peer['LOCATION'] = _peer_conf['LOCATION'].decode('utf-8')
    _ctable_peer['CONNECTION'] = _peer_conf['CONNECTION']
    _ctable_peer['CONNECTED'] = since(_peer_conf['CONNECTED'])
    _ctable_peer['IP'] = _peer_conf['IP']
    _ctable_peer['PORT'] = _peer_conf['PORT']
    #_ctable_peer['LAST_PING'] = _peer_conf['LAST_PING']

    # SLOT 1&2 - for real-time montior: make the structure for later use
    for ts in range(1, 3):
        _ctable_peer[ts] = {}
        _ctable_peer[ts]['COLOR'] = ''
        _ctable_peer[ts]['BGCOLOR'] = ''
        _ctable_peer[ts]['TS'] = ''
        _ctable_peer[ts]['TYPE'] = ''
        _ctable_peer[ts]['SUB'] = ''
        _ctable_peer[ts]['SRC'] = ''
        _ctable_peer[ts]['DEST'] = ''
Ejemplo n.º 2
0
def build_bridge_table(_bridges):
    _stats_table = {}
    _now = time()
    _cnow = strftime('%Y-%m-%d %H:%M:%S', localtime(_now))

    for _bridge, _bridge_data in list(_bridges.items()):
        _stats_table[_bridge] = {}

        for system in _bridges[_bridge]:
            _stats_table[_bridge][system['SYSTEM']] = {}
            _stats_table[_bridge][system['SYSTEM']]['TS'] = system['TS']
            _stats_table[_bridge][system['SYSTEM']]['TGID'] = int_id(
                system['TGID'])

            if system['TO_TYPE'] == 'ON' or system['TO_TYPE'] == 'OFF':
                if system['TIMER'] - _now > 0:
                    _stats_table[_bridge][system['SYSTEM']]['EXP_TIME'] = int(
                        system['TIMER'] - _now)
                else:
                    _stats_table[_bridge][
                        system['SYSTEM']]['EXP_TIME'] = 'Expired'
                if system['TO_TYPE'] == 'ON':
                    _stats_table[_bridge][
                        system['SYSTEM']]['TO_ACTION'] = 'Disconnect'
                else:
                    _stats_table[_bridge][
                        system['SYSTEM']]['TO_ACTION'] = 'Connect'
            else:
                _stats_table[_bridge][system['SYSTEM']]['EXP_TIME'] = 'N/A'
                _stats_table[_bridge][system['SYSTEM']]['TO_ACTION'] = 'None'

            if system['ACTIVE'] == True:
                _stats_table[_bridge][system['SYSTEM']]['ACTIVE'] = 'Connected'
                _stats_table[_bridge][system['SYSTEM']]['COLOR'] = BLACK
                _stats_table[_bridge][system['SYSTEM']]['BGCOLOR'] = GREEN
            elif system['ACTIVE'] == False:
                _stats_table[_bridge][
                    system['SYSTEM']]['ACTIVE'] = 'Disconnected'
                _stats_table[_bridge][system['SYSTEM']]['COLOR'] = WHITE
                _stats_table[_bridge][system['SYSTEM']]['BGCOLOR'] = RED

            for i in range(len(system['ON'])):
                system['ON'][i] = str(int_id(system['ON'][i]))

            _stats_table[_bridge][system['SYSTEM']]['TRIG_ON'] = ', '.join(
                system['ON'])

            for i in range(len(system['OFF'])):
                system['OFF'][i] = str(int_id(system['OFF'][i]))

            _stats_table[_bridge][system['SYSTEM']]['TRIG_OFF'] = ', '.join(
                system['OFF'])
    return _stats_table
Ejemplo n.º 3
0
def update_hblink_table(_config, _stats_table):
    # Is there a system in HBlink's config monitor doesn't know about?
    for _hbp in _config:
        if _config[_hbp]['MODE'] == 'MASTER':
            for _peer in _config[_hbp]['PEERS']:
                if int_id(_peer) not in _stats_table['MASTERS'][_hbp]['PEERS'] and _config[_hbp]['PEERS'][_peer]['CONNECTION'] == 'YES':
                    logger.info('Adding peer to CTABLE that has registerred: %s', int_id(_peer))
                    add_hb_peer(_config[_hbp]['PEERS'][_peer], _stats_table['MASTERS'][_hbp]['PEERS'], _peer)

    # Is there a system in monitor that's been removed from HBlink's config?
    for _hbp in _stats_table['MASTERS']:
        remove_list = []
        if _config[_hbp]['MODE'] == 'MASTER':
            for _peer in _stats_table['MASTERS'][_hbp]['PEERS']:
                if bytes_4(_peer) not in _config[_hbp]['PEERS']:
                    remove_list.append(_peer)

            for _peer in remove_list:
                logger.info('Deleting stats peer not in hblink config: %s', _peer)
                del (_stats_table['MASTERS'][_hbp]['PEERS'][_peer])

    # Update connection time
    for _hbp in _stats_table['MASTERS']:
        for _peer in _stats_table['MASTERS'][_hbp]['PEERS']:
            if bytes_4(_peer) in _config[_hbp]['PEERS']:
                _stats_table['MASTERS'][_hbp]['PEERS'][_peer]['CONNECTED'] = since(_config[_hbp]['PEERS'][bytes_4(_peer)]['CONNECTED'])

    for _hbp in _stats_table['PEERS']:
        if _stats_table['PEERS'][_hbp]['MODE'] == 'XLXPEER':
            if _config[_hbp]['XLXSTATS']['CONNECTION'] == "YES":
                _stats_table['PEERS'][_hbp]['STATS']['CONNECTED'] = since(_config[_hbp]['XLXSTATS']['CONNECTED'])
                _stats_table['PEERS'][_hbp]['STATS']['CONNECTION'] = _config[_hbp]['XLXSTATS']['CONNECTION']
                _stats_table['PEERS'][_hbp]['STATS']['PINGS_SENT'] = _config[_hbp]['XLXSTATS']['PINGS_SENT']
                _stats_table['PEERS'][_hbp]['STATS']['PINGS_ACKD'] = _config[_hbp]['XLXSTATS']['PINGS_ACKD']
            else:
                _stats_table['PEERS'][_hbp]['STATS']['CONNECTED'] = "--   --"
                _stats_table['PEERS'][_hbp]['STATS']['CONNECTION'] = _config[_hbp]['XLXSTATS']['CONNECTION']
                _stats_table['PEERS'][_hbp]['STATS']['PINGS_SENT'] = 0
                _stats_table['PEERS'][_hbp]['STATS']['PINGS_ACKD'] = 0
        else:
            if _config[_hbp]['STATS']['CONNECTION'] == "YES":
                _stats_table['PEERS'][_hbp]['STATS']['CONNECTED'] = since(_config[_hbp]['STATS']['CONNECTED'])
                _stats_table['PEERS'][_hbp]['STATS']['CONNECTION'] = _config[_hbp]['STATS']['CONNECTION']
                _stats_table['PEERS'][_hbp]['STATS']['PINGS_SENT'] = _config[_hbp]['STATS']['PINGS_SENT']
                _stats_table['PEERS'][_hbp]['STATS']['PINGS_ACKD'] = _config[_hbp]['STATS']['PINGS_ACKD']
            else:
                _stats_table['PEERS'][_hbp]['STATS']['CONNECTED'] = "--   --"
                _stats_table['PEERS'][_hbp]['STATS']['CONNECTION'] = _config[_hbp]['STATS']['CONNECTION']
                _stats_table['PEERS'][_hbp]['STATS']['PINGS_SENT'] = 0
                _stats_table['PEERS'][_hbp]['STATS']['PINGS_ACKD'] = 0
    
    cleanTE()
    build_stats()
Ejemplo n.º 4
0
    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]
        _bits = _data[15]

        if _call_type == 'group':

            # Is this is a new call stream?
            if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']):
                self.STATUS['RX_START'] = pkt_time
                logger.info('(%s) *START RECORDING* STREAM ID: %s SUB: %s (%s) REPEATER: %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)
                self.CALL_DATA.append(_data)
                self.STATUS[_slot]['RX_STREAM_ID'] = _stream_id
                return

            # Final actions - Is this a voice terminator?
            if (_frame_type == const.HBPF_DATA_SYNC) and (
                    _dtype_vseq == const.HBPF_SLT_VTERM) and (
                        self.STATUS[_slot]['RX_TYPE'] !=
                        const.HBPF_SLT_VTERM) and (self.CALL_DATA):
                call_duration = pkt_time - self.STATUS['RX_START']
                #Change the stream ID
                self.CALL_DATA.append(_data)
                logger.info('(%s) *END   RECORDING* STREAM ID: %s',
                            self._system, int_id(_stream_id))
                sleep(2)
                _new_stream_id = bytes_4(randint(0x00, 0xFFFFFFFF))
                logger.info('(%s) *START  PLAYBACK* STREAM ID: %s SUB: %s (%s) REPEATER: %s (%s) TGID %s (%s), TS %s, Duration: %s', \
                                  self._system, int_id(_new_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, call_duration)

                for i in self.CALL_DATA:

                    i = i[:16] + _new_stream_id + i[20:]
                    self.send_system(i)
                    sleep(0.06)
                self.CALL_DATA = []
                logger.info('(%s) *END    PLAYBACK* STREAM ID: %s',
                            self._system, int_id(_new_stream_id))

            else:
                if self.CALL_DATA:
                    #Change the stream ID
                    self.CALL_DATA.append(_data)

            # Mark status variables for use later
            self.STATUS[_slot]['RX_RFS'] = _rf_src
            self.STATUS[_slot]['RX_TYPE'] = _dtype_vseq
            self.STATUS[_slot]['RX_TGID'] = _dst_id
            self.STATUS[_slot]['RX_TIME'] = pkt_time
            self.STATUS[_slot]['RX_STREAM_ID'] = _stream_id
Ejemplo n.º 5
0
    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]
        _bits = _data[15]
        if _call_type == 'group':

            # Is this is a new call stream?
            if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']):
                self.STATUS['RX_START'] = pkt_time
                logger.info('(%s) *START RECORDING* STREAM ID: %s SUB: %s (%s) REPEATER: %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)
                self.CALL_DATA.append(_data)
                self.STATUS[_slot]['RX_STREAM_ID'] = _stream_id
                return

            # Final actions - Is this a voice terminator?
            if (_frame_type == const.HBPF_DATA_SYNC) and (
                    _dtype_vseq == const.HBPF_SLT_VTERM) and (
                        self.STATUS[_slot]['RX_TYPE'] !=
                        const.HBPF_SLT_VTERM) and (self.CALL_DATA):
                call_duration = pkt_time - self.STATUS['RX_START']
                self.CALL_DATA.append(_data)
                logger.info('(%s) *END   RECORDING* STREAM ID: %s',
                            self._system, int_id(_stream_id))
                sleep(2)
                logger.info('(%s) *START  PLAYBACK* STREAM ID: %s SUB: %s (%s) REPEATER: %s (%s) TGID %s (%s), TS %s, Duration: %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, call_duration)
                if (int_id(_dst_id) == 9996):
                    fout = open(
                        '/home/mmdvm/' + str(int_id(_stream_id)) + '.ambe',
                        'w+b')
                for i in self.CALL_DATA:
                    if (int_id(_dst_id) == 9996):
                        fout.write(i)
#                   self.send_system(i)
                    self.send_system(i[:5] + bytes_3(int_id(_peer_id)) + i[8:])
                    #print(i)
                    sleep(0.06)
                if (int_id(_dst_id) == 9996):
                    fout.close()
                self.CALL_DATA = []
                logger.info('(%s) *END    PLAYBACK* STREAM ID: %s',
                            self._system, int_id(_stream_id))

            else:
                if self.CALL_DATA:
                    self.CALL_DATA.append(_data)

            # Mark status variables for use later
            self.STATUS[_slot]['RX_RFS'] = _rf_src
            self.STATUS[_slot]['RX_TYPE'] = _dtype_vseq
            self.STATUS[_slot]['RX_TGID'] = _dst_id
            self.STATUS[_slot]['RX_TIME'] = pkt_time
            self.STATUS[_slot]['RX_STREAM_ID'] = _stream_id
Ejemplo n.º 6
0
def add_hb_peer(_peer_conf, _ctable_loc, _peer):
    _ctable_loc[int_id(_peer)] = {}
    _ctable_peer = _ctable_loc[int_id(_peer)]

    # if the Frequency is 000.xxx assume it's not an RF peer, otherwise format the text fields
    if _peer_conf['TX_FREQ'][:3] == b'000' or _peer_conf[
            'RX_FREQ'][:3] == b'000':
        _ctable_peer['TX_FREQ'] = 'N/A'
        _ctable_peer['RX_FREQ'] = ''
    else:
        _ctable_peer['TX_FREQ'] = 'TX: ' + _peer_conf['TX_FREQ'][:3].decode(
            'utf-8') + '.' + _peer_conf['TX_FREQ'][3:7].decode('utf-8')
        _ctable_peer['RX_FREQ'] = 'RX: ' + _peer_conf['RX_FREQ'][:3].decode(
            'utf-8') + '.' + _peer_conf['RX_FREQ'][3:7].decode('utf-8')

    # timeslots are kinda complicated too. 0 = none, 1 or 2 mean that one slot, 3 is both, and anything else it considered DMO
    if (_peer_conf['SLOTS'] == b'0'):
        _ctable_peer['SLOTS'] = 'NONE'
    elif (_peer_conf['SLOTS'] == b'1' or _peer_conf['SLOTS'] == b'2'):
        _ctable_peer['SLOTS'] = _peer_conf['SLOTS']
    elif (_peer_conf['SLOTS'] == b'3'):
        _ctable_peer['SLOTS'] = 'BOTH'
    else:
        _ctable_peer['SLOTS'] = 'DMO'

    # Simple translation items
    _ctable_peer['COLORCODE'] = _peer_conf['COLORCODE'].decode('utf-8')
    _ctable_peer['CALLSIGN'] = _peer_conf['CALLSIGN'].decode('utf-8')
    _ctable_peer['LOCATION'] = _peer_conf['LOCATION'].decode('utf-8')
    _ctable_peer['CONNECTION'] = _peer_conf['CONNECTION']
    _ctable_peer['CONNECTED'] = since(_peer_conf['CONNECTED'])
    _ctable_peer['IP'] = _peer_conf['IP']
    _ctable_peer['PORT'] = _peer_conf['PORT']
    #_ctable_peer['LAST_PING'] = _peer_conf['LAST_PING']

    # SLOT 1&2 - for real-time montior: make the structure for later use
    for ts in range(1, 3):
        _ctable_peer[ts] = {}
        _ctable_peer[ts]['COLOR'] = ''
        _ctable_peer[ts]['BGCOLOR'] = ''
        _ctable_peer[ts]['TS'] = ''
        _ctable_peer[ts]['TYPE'] = ''
        _ctable_peer[ts]['SUB'] = ''
        _ctable_peer[ts]['SRC'] = ''
        _ctable_peer[ts]['DEST'] = ''
Ejemplo n.º 7
0
    def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot,
                      _call_type, _frame_type, _dtype_vseq, _stream_id, _data):
        if (_frame_type
                == HBPF_DATA_SYNC) and (_dtype_vseq == HBPF_SLT_VTERM) and (
                    _stream_id != self.last_stream):
            print(int_id(_stream_id), int_id(self.last_stream))
            self.last_stream = _stream_id
            print('start speech')
            speech = pkt_gen(bytes_3(3120101), bytes_3(2), bytes_4(3120119), 0,
                             [words['all_circuits'], words['all_circuits']])

            sleep(1)
            while True:
                try:
                    pkt = next(speech)
                except StopIteration:
                    break
                sleep(.058)
                self.send_system(pkt)
                print(bhex(pkt))
            print('end speech')
Ejemplo n.º 8
0
def get_alias(_id, _dict, *args):
    if type(_id) == bytes:
        _id = int_id(_id)
    if _id in _dict:
        if args:
            retValue = []
            for _item in args:
                try:
                    retValue.append(_dict[_id][_item])
                except TypeError:
                    return _dict[_id]
            return retValue
        else:
            return _dict[_id]
    return _id
Ejemplo n.º 9
0
def build_hblink_table(_config, _stats_table):
    for _hbp, _hbp_data in list(_config.items()):
        if _hbp_data['ENABLED'] == True:

            # Process Master Systems
            if _hbp_data['MODE'] == 'MASTER':
                _stats_table['MASTERS'][_hbp] = {}
                if _hbp_data['REPEAT']:
                    _stats_table['MASTERS'][_hbp]['REPEAT'] = "repeat"
                else:
                    _stats_table['MASTERS'][_hbp]['REPEAT'] = "isolate"
                _stats_table['MASTERS'][_hbp]['PEERS'] = {}
                for _peer in _hbp_data['PEERS']:
                    add_hb_peer(_hbp_data['PEERS'][_peer],
                                _stats_table['MASTERS'][_hbp]['PEERS'], _peer)

            # Proccess Peer Systems
            elif (_hbp_data['MODE'] == 'XLXPEER'
                  or _hbp_data['MODE'] == 'PEER') and HOMEBREW_INC:
                _stats_table['PEERS'][_hbp] = {}
                _stats_table['PEERS'][_hbp]['MODE'] = _hbp_data['MODE']

                if str(type(_hbp_data['LOCATION'])).find("bytes") != -1:
                    _stats_table['PEERS'][_hbp]['LOCATION'] = _hbp_data[
                        'LOCATION'].decode('utf-8').strip()
                else:
                    _stats_table['PEERS'][_hbp]['LOCATION'] = _hbp_data[
                        'LOCATION']

                if str(type(_hbp_data['CALLSIGN'])).find("bytes") != -1:
                    _stats_table['PEERS'][_hbp]['CALLSIGN'] = _hbp_data[
                        'CALLSIGN'].decode('utf-8').strip()
                else:
                    _stats_table['PEERS'][_hbp]['CALLSIGN'] = _hbp_data[
                        'CALLSIGN']

                _stats_table['PEERS'][_hbp]['RADIO_ID'] = int_id(
                    _hbp_data['RADIO_ID'])
                _stats_table['PEERS'][_hbp]['MASTER_IP'] = _hbp_data[
                    'MASTER_IP']
                _stats_table['PEERS'][_hbp]['MASTER_PORT'] = _hbp_data[
                    'MASTER_PORT']
                _stats_table['PEERS'][_hbp]['STATS'] = {}
                if _stats_table['PEERS'][_hbp]['MODE'] == 'XLXPEER':
                    _stats_table['PEERS'][_hbp]['STATS'][
                        'CONNECTION'] = _hbp_data['XLXSTATS']['CONNECTION']
                    if _hbp_data['XLXSTATS']['CONNECTION'] == "YES":
                        _stats_table['PEERS'][_hbp]['STATS'][
                            'CONNECTED'] = since(
                                _hbp_data['XLXSTATS']['CONNECTED'])
                        _stats_table['PEERS'][_hbp]['STATS'][
                            'PINGS_SENT'] = _hbp_data['XLXSTATS']['PINGS_SENT']
                        _stats_table['PEERS'][_hbp]['STATS'][
                            'PINGS_ACKD'] = _hbp_data['XLXSTATS']['PINGS_ACKD']
                    else:
                        _stats_table['PEERS'][_hbp]['STATS'][
                            'CONNECTED'] = "--   --"
                        _stats_table['PEERS'][_hbp]['STATS']['PINGS_SENT'] = 0
                        _stats_table['PEERS'][_hbp]['STATS']['PINGS_ACKD'] = 0
                else:
                    _stats_table['PEERS'][_hbp]['STATS'][
                        'CONNECTION'] = _hbp_data['STATS']['CONNECTION']
                    if _hbp_data['STATS']['CONNECTION'] == "YES":
                        _stats_table['PEERS'][_hbp]['STATS'][
                            'CONNECTED'] = since(
                                _hbp_data['STATS']['CONNECTED'])
                        _stats_table['PEERS'][_hbp]['STATS'][
                            'PINGS_SENT'] = _hbp_data['STATS']['PINGS_SENT']
                        _stats_table['PEERS'][_hbp]['STATS'][
                            'PINGS_ACKD'] = _hbp_data['STATS']['PINGS_ACKD']
                    else:
                        _stats_table['PEERS'][_hbp]['STATS'][
                            'CONNECTED'] = "--   --"
                        _stats_table['PEERS'][_hbp]['STATS']['PINGS_SENT'] = 0
                        _stats_table['PEERS'][_hbp]['STATS']['PINGS_ACKD'] = 0
                if _hbp_data['SLOTS'] == b'0':
                    _stats_table['PEERS'][_hbp]['SLOTS'] = 'NONE'
                elif _hbp_data['SLOTS'] == b'1' or _hbp_data['SLOTS'] == b'2':
                    _stats_table['PEERS'][_hbp]['SLOTS'] = _hbp_data[
                        'SLOTS'].decode('utf-8')
                elif _hbp_data['SLOTS'] == b'3':
                    _stats_table['PEERS'][_hbp]['SLOTS'] = '1&2'
                else:
                    _stats_table['PEERS'][_hbp]['SLOTS'] = 'DMO'
                # SLOT 1&2 - for real-time montior: make the structure for later use

                for ts in range(1, 3):
                    _stats_table['PEERS'][_hbp][ts] = {}
                    _stats_table['PEERS'][_hbp][ts]['COLOR'] = ''
                    _stats_table['PEERS'][_hbp][ts]['BGCOLOR'] = ''
                    _stats_table['PEERS'][_hbp][ts]['TS'] = ''
                    _stats_table['PEERS'][_hbp][ts]['TYPE'] = ''
                    _stats_table['PEERS'][_hbp][ts]['SUB'] = ''
                    _stats_table['PEERS'][_hbp][ts]['SRC'] = ''
                    _stats_table['PEERS'][_hbp][ts]['DEST'] = ''

            # Process OpenBridge systems
            elif _hbp_data['MODE'] == 'OPENBRIDGE':
                _stats_table['OPENBRIDGES'][_hbp] = {}
                _stats_table['OPENBRIDGES'][_hbp]['NETWORK_ID'] = int_id(
                    _hbp_data['NETWORK_ID'])
                _stats_table['OPENBRIDGES'][_hbp]['TARGET_IP'] = _hbp_data[
                    'TARGET_IP']
                _stats_table['OPENBRIDGES'][_hbp]['TARGET_PORT'] = _hbp_data[
                    'TARGET_PORT']
                _stats_table['OPENBRIDGES'][_hbp]['STREAMS'] = {}
Ejemplo n.º 10
0
    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]
        _bits = _data[15]

        if _call_type == 'group':

            # Is this is a new call stream?
            new_stream = (_stream_id != self.STATUS[_slot]['RX_STREAM_ID'])

            if new_stream:
                self.STATUS[_slot]['RX_START'] = pkt_time
                self.STATUS[_slot]['RX_LOSS'] = 0
                self.STATUS[_slot]['RX_SEQ'] = _seq
                logger.info('(%s) *CALL START* 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)
            else:
                # This could be much better, it will have errors during roll-over
                if _seq > (self.STATUS[_slot]['RX_SEQ'] + 1):
                    #print(_seq, self.STATUS[_slot]['RX_SEQ'])
                    self.STATUS[_slot]['RX_LOSS'] += _seq - (
                        self.STATUS[_slot]['RX_SEQ'] + 1)

            # Final actions - Is this a voice terminator?
            if (_frame_type == const.HBPF_DATA_SYNC) and (
                    _dtype_vseq == const.HBPF_SLT_VTERM) and (
                        self.STATUS[_slot]['RX_TYPE'] != const.HBPF_SLT_VTERM):
                call_duration = pkt_time - self.STATUS[_slot]['RX_START']
                logger.info('(%s) *CALL END*   STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, Loss: %s, Duration: %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, self.STATUS[_slot]['RX_LOSS'], call_duration)

            for _target in self._CONFIG['SYSTEMS']:
                if _target != self._system:

                    _target_status = systems[_target].STATUS
                    _target_system = self._CONFIG['SYSTEMS'][_target]

                    # BEGIN STANDARD CONTENTION HANDLING
                    #
                    # The rules for each of the 4 "ifs" below are listed here for readability. The Frame To Send is:
                    #   From a different group than last RX from this HBSystem, but it has been less than Group Hangtime
                    #   From a different group than last TX to this HBSystem, but it has been less than Group Hangtime
                    #   From the same group as the last RX from this HBSystem, but from a different subscriber, and it has been less than stream timeout
                    #   From the same group as the last TX to this HBSystem, but from a different subscriber, and it has been less than stream timeout
                    # The "continue" at the end of each means the next iteration of the for loop that tests for matching rules
                    #
                    if ((_dst_id != _target_status[_slot]['RX_TGID'])
                            and ((pkt_time - _target_status[_slot]['RX_TIME'])
                                 < _target_system['GROUP_HANGTIME'])):
                        if _frame_type == const.HBPF_DATA_SYNC and _dtype_vseq == const.HBPF_SLT_VHEAD and self.STATUS[
                                _slot]['RX_STREAM_ID'] != _stream_id:
                            logger.info(
                                '(%s) Call not routed to TGID %s, target active or in group hangtime: HBSystem: %s, TS: %s, TGID: %s',
                                self._system, int_id(_dst_id), _target, _slot,
                                int_id(_target_status[_slot]['RX_TGID']))
                        continue
                    if ((_dst_id != _target_status[_slot]['TX_TGID'])
                            and ((pkt_time - _target_status[_slot]['TX_TIME'])
                                 < _target_system['GROUP_HANGTIME'])):
                        if _frame_type == const.HBPF_DATA_SYNC and _dtype_vseq == const.HBPF_SLT_VHEAD and self.STATUS[
                                _slot]['RX_STREAM_ID'] != _stream_id:
                            logger.info(
                                '(%s) Call not routed to TGID%s, target in group hangtime: HBSystem: %s, TS: %s, TGID: %s',
                                self._system, int_id(_dst_id), _target, _slot,
                                int_id(_target_status[_slot]['TX_TGID']))
                        continue
                    if (_dst_id == _target_status[_slot]['RX_TGID']) and (
                        (pkt_time - _target_status[_slot]['RX_TIME']) <
                            const.STREAM_TO):
                        if _frame_type == const.HBPF_DATA_SYNC and _dtype_vseq == const.HBPF_SLT_VHEAD and self.STATUS[
                                _slot]['RX_STREAM_ID'] != _stream_id:
                            logger.info(
                                '(%s) Call not routed to TGID%s, matching call already active on target: HBSystem: %s, TS: %s, TGID: %s',
                                self._system, int_id(_dst_id), _target, _slot,
                                int_id(_target_status[_slot]['RX_TGID']))
                        continue
                    if (_dst_id == _target_status[_slot]['TX_TGID']) and (
                            _rf_src != _target_status[_slot]['TX_RFS']) and (
                                (pkt_time - _target_status[_slot]['TX_TIME']) <
                                const.STREAM_TO):
                        if _frame_type == const.HBPF_DATA_SYNC and _dtype_vseq == const.HBPF_SLT_VHEAD and self.STATUS[
                                _slot]['RX_STREAM_ID'] != _stream_id:
                            logger.info(
                                '(%s) Call not routed for subscriber %s, call route in progress on target: HBSystem: %s, TS: %s, TGID: %s, SUB: %s',
                                self._system, int_id(_rf_src), _target, _slot,
                                int_id(_target_status[_slot]['TX_TGID']),
                                int_id(_target_status[_slot]['TX_RFS']))
                        continue

                    # ACL Processing
                    if self._CONFIG['GLOBAL']['USE_ACL']:
                        if not acl_check(_rf_src,
                                         self._CONFIG['GLOBAL']['SUB_ACL']):
                            if _stream_id != _target_status[_slot][
                                    'TX_STREAM_ID']:
                                logger.info(
                                    '(%s) CALL DROPPED ON EGRESS WITH STREAM ID %s FROM SUBSCRIBER %s BY GLOBAL ACL',
                                    _target, int_id(_stream_id),
                                    int_id(_rf_src))
                                _target_status[_slot][
                                    'TX_STREAM_ID'] = _stream_id
                            continue
                        if _slot == 1 and not acl_check(
                                _dst_id, self._CONFIG['GLOBAL']['TG1_ACL']):
                            if _stream_id != _target_status[_slot][
                                    'TX_STREAM_ID']:
                                logger.info(
                                    '(%s) CALL DROPPED ON EGRESS WITH STREAM ID %s ON TGID %s BY GLOBAL TS1 ACL',
                                    _target, int_id(_stream_id),
                                    int_id(_dst_id))
                                _target_status[_slot][
                                    'TX_STREAM_ID'] = _stream_id
                            continue
                        if _slot == 2 and not acl_check(
                                _dst_id, self._CONFIG['GLOBAL']['TG2_ACL']):
                            if _stream_id != _target_status[_slot][
                                    'TX_STREAM_ID']:
                                logger.info(
                                    '(%s) CALL DROPPED ON EGRESS WITH STREAM ID %s ON TGID %s BY GLOBAL TS2 ACL',
                                    _target, int_id(_stream_id),
                                    int_id(_dst_id))
                                _target_status[_slot][
                                    'TX_STREAM_ID'] = _stream_id
                            continue
                    if _target_system['USE_ACL']:
                        if not acl_check(_rf_src, _target_system['SUB_ACL']):
                            if _stream_id != _target_status[_slot][
                                    'TX_STREAM_ID']:
                                logger.info(
                                    '(%s) CALL DROPPED ON EGRESS WITH STREAM ID %s FROM SUBSCRIBER %s BY SYSTEM ACL',
                                    _target, int_id(_stream_id),
                                    int_id(_rf_src))
                                _target_status[_slot][
                                    'TX_STREAM_ID'] = _stream_id
                            continue
                        if _slot == 1 and not acl_check(
                                _dst_id, _target_system['TG1_ACL']):
                            if _stream_id != _target_status[_slot][
                                    'TX_STREAM_ID']:
                                logger.info(
                                    '(%s) CALL DROPPED ON EGRESS WITH STREAM ID %s ON TGID %s BY SYSTEM TS1 ACL',
                                    _target, int_id(_stream_id),
                                    int_id(_dst_id))
                                _target_status[_slot][
                                    'TX_STREAM_ID'] = _stream_id
                            continue
                        if _slot == 2 and not acl_check(
                                _dst_id, _target_system['TG2_ACL']):
                            if _stream_id != _target_status[_slot][
                                    'TX_STREAM_ID']:
                                logger.info(
                                    '(%s) CALL DROPPED ON EGRESS WITH STREAM ID %s ON TGID %s BY SYSTEM TS2 ACL',
                                    _target, int_id(_stream_id),
                                    int_id(_dst_id))
                                _target_status[_slot][
                                    'TX_STREAM_ID'] = _stream_id
                            continue

                    # Record this stuff for later
                    # Is this a new call stream?
                    if new_stream:
                        # Record the DST TGID and Stream ID
                        _target_status[_slot]['TX_START'] = pkt_time
                        _target_status[_slot]['TX_TGID'] = _dst_id
                        _target_status[_slot]['TX_RFS'] = _rf_src
                        _target_status[_slot]['TX_PEER'] = _peer_id
                        _target_status[_slot]['TX_STREAM_ID'] = _stream_id

                    _target_status[_slot]['TX_TIME'] = pkt_time

                    systems[_target].send_system(_data)
                    #logger.debug('(%s) Packet routed to system: %s', self._system, _target)

            # Mark status variables for use later
            self.STATUS[_slot]['RX_RFS'] = _rf_src
            self.STATUS[_slot]['RX_SEQ'] = _seq
            self.STATUS[_slot]['RX_TYPE'] = _dtype_vseq
            self.STATUS[_slot]['RX_TGID'] = _dst_id
            self.STATUS[_slot]['RX_TIME'] = pkt_time
            self.STATUS[_slot]['RX_STREAM_ID'] = _stream_id
Ejemplo n.º 11
0
    def peer_datagramReceived(self, _data, _sockaddr):
        # Keep This Line Commented Unless HEAVILY Debugging!
        # logger.debug('(%s) RX packet from %s -- %s', self._system, _sockaddr, ahex(_data))

        # Validate that we receveived this packet from the master - security check!
        if self._config['MASTER_SOCKADDR'] == _sockaddr:
            # Extract the command, which is various length, but only 4 significant characters
            _command = _data[:4]
            if   _command == DMRD:    # DMRData -- encapsulated DMR data frame

                _peer_id = _data[11:15]
                if self._config['LOOSE'] or _peer_id == self._config['RADIO_ID']: # Validate the Radio_ID unless using loose validation
                    _seq = _data[4:5]
                    _rf_src = _data[5:8]
                    _dst_id = _data[8:11]
                    _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 - Sequence: %s, RF Source: %s, Destination ID: %s', self._system, int_id(_seq), int_id(_rf_src), int_id(_dst_id))

                    # ACL Processing
                    if self._CONFIG['GLOBAL']['USE_ACL']:
                        if not acl_check(_rf_src, self._CONFIG['GLOBAL']['SUB_ACL']):
                            if self._laststrid[_slot] != _stream_id:
                                logger.info('(%s) CALL DROPPED WITH STREAM ID %s FROM SUBSCRIBER %s BY GLOBAL ACL', self._system, int_id(_stream_id), int_id(_rf_src))
                                self._laststrid[_slot] = _stream_id
                            return
                        if _slot == 1 and not acl_check(_dst_id, self._CONFIG['GLOBAL']['TG1_ACL']):
                            if self._laststrid[_slot] != _stream_id:
                                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._laststrid[_slot] = _stream_id
                            return
                        if _slot == 2 and not acl_check(_dst_id, self._CONFIG['GLOBAL']['TG2_ACL']):
                            if self._laststrid[_slot] != _stream_id:
                                logger.info('(%s) CALL DROPPED WITH STREAM ID %s ON TGID %s BY GLOBAL TS2 ACL', self._system, int_id(_stream_id), int_id(_dst_id))
                                self._laststrid[_slot] = _stream_id
                            return
                    if self._config['USE_ACL']:
                        if not acl_check(_rf_src, self._config['SUB_ACL']):
                            if self._laststrid[_slot] != _stream_id:
                                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._laststrid[_slot] = _stream_id
                            return
                        if _slot == 1 and not acl_check(_dst_id, self._config['TG1_ACL']):
                            if self._laststrid[_slot] != _stream_id:
                                logger.info('(%s) CALL DROPPED WITH STREAM ID %s ON TGID %s BY SYSTEM TS1 ACL', self._system, int_id(_stream_id), int_id(_dst_id))
                                self._laststrid[_slot] = _stream_id
                            return
                        if _slot == 2 and not acl_check(_dst_id, self._config['TG2_ACL']):
                            if self._laststrid[_slot] != _stream_id:
                                logger.info('(%s) CALL DROPPED WITH STREAM ID %s ON TGID %s BY SYSTEM TS2 ACL', self._system, int_id(_stream_id), int_id(_dst_id))
                                self._laststrid[_slot] = _stream_id
                            return


                    # 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)

            elif _command == MSTN:    # Actually MSTNAK -- a NACK from the master
                _peer_id = _data[6:10]
                if self._config['LOOSE'] or _peer_id == self._config['RADIO_ID']: # Validate the Radio_ID unless using loose validation
                    logger.warning('(%s) MSTNAK Received. Resetting connection to the Master.', self._system)
                    self._stats['CONNECTION'] = 'NO' # Disconnect ourselves and re-register
                    self._stats['CONNECTED'] = time()

            elif _command == RPTA:    # Actually RPTACK -- an ACK from the master
                # Depending on the state, an RPTACK means different things, in each clause, we check and/or set the state
                if self._stats['CONNECTION'] == 'RPTL_SENT': # If we've sent a login request...
                    _login_int32 = _data[6:10]
                    logger.info('(%s) Repeater Login ACK Received with 32bit ID: %s', self._system, int_id(_login_int32))
                    _pass_hash = sha256(b''.join([_login_int32, self._config['PASSPHRASE']])).hexdigest()
                    _pass_hash = bhex(_pass_hash)
                    self.send_master(b''.join([RPTK, self._config['RADIO_ID'], _pass_hash]))
                    self._stats['CONNECTION'] = 'AUTHENTICATED'

                elif self._stats['CONNECTION'] == 'AUTHENTICATED': # If we've sent the login challenge...
                    _peer_id = _data[6:10]
                    if self._config['LOOSE'] or _peer_id == self._config['RADIO_ID']: # Validate the Radio_ID unless using loose validation
                        logger.info('(%s) Repeater Authentication Accepted', self._system)
                        _config_packet =  b''.join([\
                                              self._config['RADIO_ID'],\
                                              self._config['CALLSIGN'],\
                                              self._config['RX_FREQ'],\
                                              self._config['TX_FREQ'],\
                                              self._config['TX_POWER'],\
                                              self._config['COLORCODE'],\
                                              self._config['LATITUDE'],\
                                              self._config['LONGITUDE'],\
                                              self._config['HEIGHT'],\
                                              self._config['LOCATION'],\
                                              self._config['DESCRIPTION'],\
                                              self._config['SLOTS'],\
                                              self._config['URL'],\
                                              self._config['SOFTWARE_ID'],\
                                              self._config['PACKAGE_ID']\
                                          ])

                        self.send_master(b''.join([RPTC, _config_packet]))
                        self._stats['CONNECTION'] = 'CONFIG-SENT'
                        logger.info('(%s) Repeater Configuration Sent', self._system)
                    else:
                        self._stats['CONNECTION'] = 'NO'
                        logger.error('(%s) Master ACK Contained wrong ID - Connection Reset', self._system)

                elif self._stats['CONNECTION'] == 'CONFIG-SENT': # If we've sent out configuration to the master
                    _peer_id = _data[6:10]
                    if self._config['LOOSE'] or _peer_id == self._config['RADIO_ID']: # Validate the Radio_ID unless using loose validation
                        logger.info('(%s) Repeater Configuration Accepted', self._system)
                        if self._config['OPTIONS']:
                            self.send_master(b''.join([RPTO, self._config['RADIO_ID'], self._config['OPTIONS']]))
                            self._stats['CONNECTION'] = 'OPTIONS-SENT'
                            logger.info('(%s) Sent options: (%s)', self._system, self._config['OPTIONS'])
                        else:
                            self._stats['CONNECTION'] = 'YES'
                            self._stats['CONNECTED'] = time()
                            logger.info('(%s) Connection to Master Completed', self._system)

                            # If we are an XLX, send the XLX module request here.
                            if self._config['MODE'] == 'XLXPEER':
                                self.send_xlxmaster(self._config['RADIO_ID'], int(4000), self._config['MASTER_SOCKADDR'])
                                self.send_xlxmaster(self._config['RADIO_ID'], self._config['XLXMODULE'], self._config['MASTER_SOCKADDR'])
                                logger.info('(%s) Sending XLX Module request', self._system)
                    else:
                        self._stats['CONNECTION'] = 'NO'
                        logger.error('(%s) Master ACK Contained wrong ID - Connection Reset', self._system)

                elif self._stats['CONNECTION'] == 'OPTIONS-SENT': # If we've sent out options to the master
                    _peer_id = _data[6:10]
                    if self._config['LOOSE'] or _peer_id == self._config['RADIO_ID']: # Validate the Radio_ID unless using loose validation
                        logger.info('(%s) Repeater Options Accepted', self._system)
                        self._stats['CONNECTION'] = 'YES'
                        self._stats['CONNECTED'] = time()
                        logger.info('(%s) Connection to Master Completed with options', self._system)
                    else:
                        self._stats['CONNECTION'] = 'NO'
                        logger.error('(%s) Master ACK Contained wrong ID - Connection Reset', self._system)

            elif _command == MSTP:    # Actually MSTPONG -- a reply to RPTPING (send by peer)
                _peer_id = _data[7:11]
                if self._config['LOOSE'] or _peer_id == self._config['RADIO_ID']: # Validate the Radio_ID unless using loose validation
                    self._stats['PING_OUTSTANDING'] = False
                    self._stats['NUM_OUTSTANDING'] = 0
                    self._stats['PINGS_ACKD'] += 1
                    logger.debug('(%s) MSTPONG Received. Pongs Since Connected: %s', self._system, self._stats['PINGS_ACKD'])

            elif _command == MSTC:    # Actually MSTCL -- notify us the master is closing down
                _peer_id = _data[5:9]
                if self._config['LOOSE'] or _peer_id == self._config['RADIO_ID']: # Validate the Radio_ID unless using loose validation
                    self._stats['CONNECTION'] = 'NO'
                    logger.info('(%s) MSTCL Recieved', self._system)

            elif _command == RPTS:
              if _data[:7] == RPTSBKN:
                logger.info('(%s) Received Site Beacon with Repeater ID: %s', self._system, int_id(_data[7:]))

            else:
                logger.error('(%s) Received an invalid command in packet: %s', self._system, ahex(_data))
Ejemplo n.º 12
0
def process_message(_bmessage):
    global CTABLE, CONFIG, BRIDGES, CONFIG_RX, BRIDGES_RX
    _message = _bmessage.decode('utf-8', 'ignore')
    opcode = _message[:1]
    _now = strftime('%Y-%m-%d %H:%M:%S %Z', localtime(time()))

    if opcode == OPCODE['CONFIG_SND']:
        logging.debug('got CONFIG_SND opcode')
        CONFIG = load_dictionary(_bmessage)
        CONFIG_RX = strftime('%Y-%m-%d %H:%M:%S', localtime(time()))
        if CTABLE['MASTERS']:
            update_hblink_table(CONFIG, CTABLE)
        else:
            build_hblink_table(CONFIG, CTABLE)

    elif opcode == OPCODE['BRIDGE_SND']:
        logging.debug('got BRIDGE_SND opcode')
        BRIDGES = load_dictionary(_bmessage)
        BRIDGES_RX = strftime('%Y-%m-%d %H:%M:%S', localtime(time()))
        if BRIDGES_INC:
            BTABLE['BRIDGES'] = build_bridge_table(BRIDGES)

    elif opcode == OPCODE['LINK_EVENT']:
        logging.info('LINK_EVENT Received: {}'.format(repr(_message[1:])))

    elif opcode == OPCODE['BRDG_EVENT']:
        logging.info('BRIDGE EVENT: {}'.format(repr(_message[1:])))
        p = _message[1:].split(",")
        rts_update(p)
        opbfilter = get_opbf()
        if p[0] == 'GROUP VOICE' and p[2] != 'TX' and p[5] not in opbfilter:
            if p[1] == 'END':
                _matchsystem = False
                if (int(p[8]) == 9) and (int(p[7]) == 2) and BRIDGES:
                    for _bridge in BRIDGES:
                        for _bridgesystem in BRIDGES[_bridge]:
                            if p[3] == _bridgesystem[
                                    'SYSTEM'] and _bridgesystem[
                                        'ACTIVE'] == True and int_id(
                                            _bridgesystem['TGID']) == 9:
                                _refdest = str(_bridge[1:])
                                print(_refdest)
                                log_message = '{} {} {}   SYS: {:8.8s} SRC: {:9.9s}; {:9.9s} TS: {} TGID: {:7.7s} {:17.17s} SUB: {:9.9s}; {:18.18s} Time: {}s '.format(
                                    _now[10:19], p[0][6:], p[1], p[3], p[5],
                                    alias_call(int(p[5]),
                                               subscriber_ids), p[7], _refdest,
                                    alias_tgid(int(_refdest), talkgroup_ids) +
                                    " (9)", p[6],
                                    alias_short(int(p[6]), subscriber_ids),
                                    int(float(p[9])))
                                _matchsystem = True

                #If we didn't get a match, use default
                if _matchsystem == False:
                    log_message = '{} {} {}   SYS: {:8.8s} SRC: {:9.9s}; {:9.9s} TS: {} TGID: {:7.7s} {:17.17s} SUB: {:9.9s}; {:18.18s} Time: {}s '.format(
                        _now[10:19], p[0][6:], p[1], p[3], p[5],
                        alias_call(int(p[5]), subscriber_ids), p[7], p[8],
                        alias_tgid(int(p[8]), talkgroup_ids), p[6],
                        alias_short(int(p[6]), subscriber_ids),
                        int(float(p[9])))
                # log only to file if system is NOT OpenBridge event (not logging open bridge system, name depends on your OB definitions) AND transmit time is LONGER as 2sec (make sense for very short transmits)
                if LASTHEARD_INC:
                    if int(float(p[9])) > 2:
                        _matchsystem = False
                        if (int(p[8]) == 9) and (int(p[7]) == 2) and BRIDGES:
                            for _bridge in BRIDGES:
                                for _bridgesystem in BRIDGES[_bridge]:
                                    if p[3] == _bridgesystem[
                                            'SYSTEM'] and _bridgesystem[
                                                'ACTIVE'] == True and int_id(
                                                    _bridgesystem['TGID']
                                                ) == 9:
                                        _refdest = str(_bridge[1:])
                                        log_lh_message = '{},{},{},{},{},{},{},TS{},TG{},{},{},{}'.format(
                                            _now, p[9], p[0], p[1], p[3], p[5],
                                            alias_call(int(p[5]),
                                                       subscriber_ids), p[7],
                                            _refdest,
                                            alias_tgid(int(_refdest),
                                                       talkgroup_ids) + " (9)",
                                            p[6],
                                            alias_short(
                                                int(p[6]), subscriber_ids))
                                        _matchsystem = True

                        if _matchsystem == False:
                            log_lh_message = '{},{},{},{},{},{},{},TS{},TG{},{},{},{}'.format(
                                _now, p[9], p[0], p[1], p[3], p[5],
                                alias_call(int(p[5]),
                                           subscriber_ids), p[7], p[8],
                                alias_tgid(int(p[8]), talkgroup_ids), p[6],
                                alias_short(int(p[6]), subscriber_ids))

                        lh_logfile = open(LOG_PATH + "lastheard.log", "a")
                        lh_logfile.write(log_lh_message + '\n')
                        lh_logfile.close()
                        # Lastheard in Dashboard by SP2ONG
                        my_list = []
                        i = 0
                        f = open(PATH + "templates/lastheard.html", "w")
                        f.write(
                            "<br><fieldset style=\"border-radius: 8px; background-color:#e0e0e0e0; text-algin: lef; margin-left:15px;margin-right:15px;font-size:14px;border-top-left-radius: 10px; border-top-right-radius: 10px;border-bottom-left-radius: 10px; border-bottom-right-radius: 10px;\">\n"
                        )
                        #f.write("<legend><b><font color=\"#000\">&nbsp;.: Lastheard :.&nbsp;</font></b></legend>\n")
                        f.write(
                            "<table style=\"width:100%; font: 10pt arial, sans-serif\">\n"
                        )
                        f.write(
                            "<TR style=\" height: 32px;font: 10pt arial, sans-serif; background-color:#9dc209; color:black\"><TH>Date</TH><TH>Time</TH><TH>Callsign (DMR-Id)</TH><TH>Name</TH><TH>TG#</TH><TH>TG Name</TH><TH>TX (s)</TH></TR>\n"
                        )
                        with open(LOG_PATH + "lastheard.log", "r") as textfile:
                            for row in islice(
                                    reversed(list(csv.reader(textfile))), 100):
                                duration = row[1]
                                dur = str(int(float(duration.strip())))
                                if row[10] not in my_list:
                                    if len(row) < 13:
                                        hline = "<TR style=\"background-color:#f9f9f9f9;\"><TD>" + row[
                                            0][:10] + "</TD><TD>" + row[0][
                                                11:
                                                16] + "</TD><TD><font color=#0066ff><b><a target=\"_blank\" href=https://qrz.com/db/" + row[
                                                    11] + ">" + row[11] + "</a></b></font><span style=\"font: 7pt arial,sans-serif\"> (" + row[
                                                        10] + ")</span></TD><TD><font color=#002d62><b></b></font></TD><TD><font color=#b5651d><b>" + row[
                                                            8][2:] + "</b></font></TD><TD><font color=green><b>" + row[
                                                                9] + "</b></font></TD><TD>" + dur + "</TD><TR>"
                                        my_list.append(row[10])
                                        i += 1
                                    else:
                                        hline = "<TR style=\"background-color:#f9f9f9f9;\"><TD>" + row[
                                            0][:10] + "</TD><TD>" + row[0][
                                                11:
                                                16] + "</TD><TD><font color=#0066ff><b><a target=\"_blank\" href=https://qrz.com/db/" + row[
                                                    11] + ">" + row[11] + "</a></b></font><span style=\"font: 7pt arial,sans-serif\"> (" + row[
                                                        10] + ")</span></TD><TD><font color=#002d62><b>" + row[
                                                            12] + "</b></font></TD><TD><font color=#b5651d><b>" + row[
                                                                8][2:] + "</b></font></TD><TD><font color=green><b>" + row[
                                                                    9] + "</b></font></TD><TD>" + dur + "</TD><TR>"
                                        my_list.append(row[10])
                                        i += 1
                                    f.write(hline + "\n")
                                if i == 20:
                                    break
                        f.write("</table></fieldset><br>")
                        f.close()
                # End of Lastheard

            elif p[1] == 'START':
                log_message = '{} {} {} SYS: {:8.8s} SRC: {:9.9s}; {:9.9s} TS: {} TGID: {:7.7s} {:17.17s} SUB: {:9.9s}; {:18.18s}'.format(
                    _now[10:19], p[0][6:], p[1], p[3], p[5],
                    alias_call(int(p[5]), subscriber_ids), p[7], p[8],
                    alias_tgid(int(p[8]), talkgroup_ids), p[6],
                    alias_short(int(p[6]), subscriber_ids))
            elif p[1] == 'END WITHOUT MATCHING START':
                log_message = '{} {} {} on SYSTEM {:8.8s}: SRC: {:9.9s}; {:9.9s} TS: {} TGID: {:7.7s} {:17.17s} SUB: {:9.9s}; {:18.18s}'.format(
                    _now[10:19], p[0][6:], p[1], p[3], p[5],
                    alias_call(int(p[5]), subscriber_ids), p[7], p[8],
                    alias_tgid(int(p[8]), talkgroup_ids), p[6],
                    alias_short(int(p[6]), subscriber_ids))
            else:
                log_message = '{} UNKNOWN GROUP VOICE LOG MESSAGE'.format(_now)

            dashboard_server.broadcast('l' + log_message)
            LOGBUF.append(log_message)

        else:
            logging.debug('{}: UNKNOWN LOG MESSAGE'.format(_now))

    else:
        logging.debug('got unknown opcode: {}, message: {}'.format(
            repr(opcode), repr(_message[1:])))
Ejemplo n.º 13
0
def rts_update(p):
    callType = p[0]
    action = p[1]
    trx = p[2]
    system = p[3]
    streamId = p[4]
    sourcePeer = int(p[5])
    sourceSub = int(p[6])
    timeSlot = int(p[7])
    destination = int(p[8])
    timeout = datetime.datetime.now().timestamp()

    if system in CTABLE['MASTERS']:
        for peer in CTABLE['MASTERS'][system]['PEERS']:
            if sourcePeer == peer:
                bgcolor = RED
                color = WHITE
            else:
                bgcolor = GREEN
                color = BLACK

            if action == 'START':
                CTABLE['MASTERS'][system]['PEERS'][peer][timeSlot][
                    'TIMEOUT'] = timeout
                CTABLE['MASTERS'][system]['PEERS'][peer][timeSlot]['TS'] = True
                CTABLE['MASTERS'][system]['PEERS'][peer][timeSlot][
                    'COLOR'] = color
                CTABLE['MASTERS'][system]['PEERS'][peer][timeSlot][
                    'BGCOLOR'] = bgcolor
                CTABLE['MASTERS'][system]['PEERS'][peer][timeSlot][
                    'TYPE'] = callType
                CTABLE['MASTERS'][system]['PEERS'][peer][timeSlot][
                    'SUB'] = '{} ({})'.format(
                        alias_short(sourceSub, subscriber_ids), sourceSub)
                CTABLE['MASTERS'][system]['PEERS'][peer][timeSlot][
                    'SRC'] = peer
                _matchsystem = False
                if destination == 9 and timeSlot == 2:
                    for _bridge in BRIDGES:
                        for _bridgesystem in BRIDGES[_bridge]:
                            if system == _bridgesystem[
                                    'SYSTEM'] and _bridgesystem[
                                        'ACTIVE'] == True and int_id(
                                            _bridgesystem['TGID']) == 9:
                                _refdest = int(_bridge[1:])
                                CTABLE['MASTERS'][system]['PEERS'][peer][
                                    timeSlot]['DEST'] = '{} ({})'.format(
                                        alias_tgid(_refdest, talkgroup_ids),
                                        "" + str(destination))
                                _matchsystem = True
                if _matchsystem == False:
                    CTABLE['MASTERS'][system]['PEERS'][peer][timeSlot][
                        'DEST'] = '{} ({})'.format(
                            alias_tgid(destination, talkgroup_ids),
                            destination)
            if action == 'END':
                CTABLE['MASTERS'][system]['PEERS'][peer][timeSlot][
                    'TS'] = False
                CTABLE['MASTERS'][system]['PEERS'][peer][timeSlot][
                    'COLOR'] = BLACK
                CTABLE['MASTERS'][system]['PEERS'][peer][timeSlot][
                    'BGCOLOR'] = WHITE2
                CTABLE['MASTERS'][system]['PEERS'][peer][timeSlot]['TYPE'] = ''
                CTABLE['MASTERS'][system]['PEERS'][peer][timeSlot]['SUB'] = ''
                CTABLE['MASTERS'][system]['PEERS'][peer][timeSlot]['SRC'] = ''
                CTABLE['MASTERS'][system]['PEERS'][peer][timeSlot]['DEST'] = ''

    if system in CTABLE['OPENBRIDGES']:
        if action == 'START':
            CTABLE['OPENBRIDGES'][system]['STREAMS'][streamId] = (
                trx, alias_call(sourceSub, subscriber_ids),
                'TG{}'.format(destination), timeout)
        if action == 'END':
            if streamId in CTABLE['OPENBRIDGES'][system]['STREAMS']:
                del CTABLE['OPENBRIDGES'][system]['STREAMS'][streamId]

    if system in CTABLE['PEERS']:
        bgcolor = GREEN
        if trx == 'RX':
            bgcolor = RED
            color = WHITE
        else:
            bgcolor = GREEN
            color = BLACK

        if action == 'START':
            CTABLE['PEERS'][system][timeSlot]['TIMEOUT'] = timeout
            CTABLE['PEERS'][system][timeSlot]['TS'] = True
            CTABLE['PEERS'][system][timeSlot]['COLOR'] = color
            CTABLE['PEERS'][system][timeSlot]['BGCOLOR'] = bgcolor
            CTABLE['PEERS'][system][timeSlot]['SUB'] = '{} ({})'.format(
                alias_short(sourceSub, subscriber_ids), sourceSub)
            CTABLE['PEERS'][system][timeSlot]['SRC'] = sourcePeer
            CTABLE['PEERS'][system][timeSlot]['DEST'] = '{} ({})'.format(
                alias_tgid(destination, talkgroup_ids), destination)
        if action == 'END':
            CTABLE['PEERS'][system][timeSlot]['TS'] = False
            CTABLE['PEERS'][system][timeSlot]['COLOR'] = BLACK
            CTABLE['PEERS'][system][timeSlot]['BGCOLOR'] = WHITE2
            CTABLE['PEERS'][system][timeSlot]['TYPE'] = ''
            CTABLE['PEERS'][system][timeSlot]['SUB'] = ''
            CTABLE['PEERS'][system][timeSlot]['SRC'] = ''
            CTABLE['PEERS'][system][timeSlot]['DEST'] = ''

    build_stats()
Ejemplo n.º 14
0
def process(pkt):
    # we need to save ambe payload from MMDVM as global var
    global ambe_payload_mmdvm
    # we need to save the last packet Seq from Hytera IPSC UDP packet for later processing as global var
    global last_seq_HYT
    # get payload from packet is landed in netqueue - the payload is including(!) the IP header - the payload we use starts at p[28:]
    data = IP(pkt.get_payload())
    # process only UDP packets longer than 80, shorter packets will be pass-thru without any modification
    if len(data) > 80:
        # hexdump(data)
        # print("Length:", len(data),"\n\r")
        # extract payload from UDP packet
        mod_data = raw(data)
        # convert to bytearray
        p = bytearray(mod_data)
        # print(p[28:])
        # is the packet a MMDVM DMRD packet ?
        if p[28:32] == b"DMRD":
            # if p[28] == 68 and p[29] == 77 and p[30] == 82 and p[31] == 68 :
            print("------ packet processing MMDVM ------")
            p1 = bytearray(p[48:82])
            p1 = ahex(p1)
            print(p1, ":from DMRGateway(payload)    Seq.Nr:", hex(p[32]),
                  "Byte15-Flags:", format(p[43], '08b'),
                  check_FrameType_MMDVM(p[43]), "SrcId:", int_id(p[33:36]),
                  "T:", int_id(p[36:39]))
            # swap the ambe mmdvm payload HiByte<>LowByte needed for use in Hytera ambe payload
            p2 = byte_swap(p1)
            # save swapped ambe payload in ambe_paylaod_mmdvm for later insert in Hytera ambe payload
            ambe_payload_mmdvm = p2
            print(p2, ":modify MMDVM(Byte_swapping) Seq.Nr:", hex(p[32]),
                  "Byte15-Flags:", format(p[43], '08b'))
            # print(ahex(p[48:82]))
            # print(ahex(p[48:82]),":MMDVM Seq.Nr: ",hex(p[32]),"Status: ",format(p[43],'08b'))
        # is it a Hytera packet ?
        elif p[28:32] == b"ZZZZ" or p[28:32] == bytearray.fromhex(
                'ee ee 11 11'):
            print("------ packet processing IPSC HYTERA ------")
            # print(ambe_payload_mmdvm,":saved")
            # get the SrcId from Hytera payload
            SrcId = p[96:99]
            # get the destination Id from Hytera paylaod
            _DestId = bytearray(p[92:95])
            _DestId = ahex(_DestId)
            # change byteorder for correct calculating destination Id
            DestId = swap_DestId(_DestId)
            # print(ahex(p[44:46]))
            # get slot number from Hytera payload
            _slot = bytearray(p[44:46])
            _slot = ahex(_slot)
            Slot = check_Slot_HYT(_slot)
            print(ahex(p[28:32]), ":first 4 Bytes from HytGW Seq.Nr:",
                  hex(p[32]), "FrameType:", hex(p[36]), "Frametype:",
                  check_FrameType_HYT(p[36]))
            print(ahex(p[54:88]),
                  ":from HytGW unpatched                 SrcId:",
                  int.from_bytes(SrcId, byteorder='little'), " T:",
                  int.from_bytes(bhex(DestId), byteorder='big'), "(",
                  check_CallType_HYT(p[90]), ") TS:", Slot)
            # delete the UDP checksum and fill with 00 00 as No_CheckSum
            p[26:28] = bytearray.fromhex('00 00')
            if p[28:32] == b"ZZZZ":
                # if p[28] == 90 and p[29] == 90 and p[30] == 90 and p[31] == 90:
                # save the last HYT SeqNr (0x00 to 0xFF) of UDP payload for later use (format uint8)
                last_seq_HYT = p[32]
                # print(hex(last_seq_HYT))
                # replace the Offset_0-3 ZZZZ with 00 00 00 00 (not sure - stamped packet as packet from base station/master)
                p[28:32] = bytearray.fromhex('00 00 00 00')
                # check if the Hytera packet is START_OF_TRANSMISSION SeqNr.0x0/Offset_4 and 0x2/Offset_8
                if p[36] == 2 and p[32] == 0:
                    print(
                        "CALL_START_PAYLOAD possible not correct => need MODIFY...processing packet..."
                    )
                    # insert the MMDVM payload VOICE_START
                    p[54:88] = bhex(ambe_payload_mmdvm)
                    print(ahex(p[54:88]),
                          ":to RD985 replace with MMDVM(swapped) SrcId:",
                          int.from_bytes(SrcId, byteorder='little'), " T:",
                          int.from_bytes(bhex(DestId), byteorder='big'), "(",
                          check_CallType_HYT(p[90]), ") TS:", Slot)
                    print("CALL_START => now OK")
                # check if the Hytera packet is END_OF_TRANSMISSION 0x2222/Offset_18-19 and 0x3/Offset_8
                if p[46:48] == bytearray.fromhex('22 22') and p[36] == 3:
                    # if p[46] == 34 and p[47] == 34 and p[36]) == 3:
                    print(
                        "CALL_END_WITHOUT_PAYLOAD => need MODIFY...processing packet..."
                    )
                    # p[28:32] = bytearray.fromhex('00 00 00 00')
                    # correct some bytes in Hytera payload
                    p[48:50] = bytearray.fromhex('11 11')
                    p[51:53] = bytearray.fromhex('00 10')
                    # insert the MMDVM payload VOICE_TERMINATOR_WITH_LC because the Hytera_GW do it NOT and fill all with 00 !
                    try:
                        p[54:88] = bhex(ambe_payload_mmdvm)
                    except NameError:
                        print("No codec yet")
                    print(ahex(p[54:88]),
                          ":to RD985 replace with MMDVM(swapped) SrcId:",
                          int.from_bytes(SrcId, byteorder='little'), " T:",
                          int.from_bytes(bhex(DestId), byteorder='big'), "(",
                          check_CallType_HYT(p[90]), ") TS:", Slot)
                    print("CALL_END_WITH_Voiceterminator_LC => now OK")
        # write all changes to packet in netqueue
        p = modify_packet(p)
        pkt.set_payload(bytes(p))
    # we accept now the packet in netqueue with all changes and transmit it
    pkt.accept()
Ejemplo n.º 15
0
    def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot,
                      _call_type, _frame_type, _dtype_vseq, _stream_id, _data):
        # Capture data headers
        global n_packet_assembly
        #logger.info(_dtype_vseq)
        if int_id(_dst_id) == data_id:
            #logger.info(type(_seq))
            if type(_seq) is bytes:
                pckt_seq = int.from_bytes(_seq, 'big')
            else:
                pckt_seq = _seq
            if _call_type == call_type or (
                    _call_type == 'vcsbk'
                    and pckt_seq > 3):  #int.from_bytes(_seq, 'big') > 3 ):
                if _dtype_vseq == 6 or _dtype_vseq == 'group':
                    global btf
                    logger.info('Header from ' + str(int_id(_rf_src)))
                    logger.info(ahex(bptc_decode(_data)))
                    logger.info('Blocks to follow: ' +
                                str(ba2num(bptc_decode(_data)[65:72])))
                    btf = ba2num(bptc_decode(_data)[65:72])
                # Data blocks at 1/2 rate, see https://github.com/g4klx/MMDVM/blob/master/DMRDefines.h for data types. _dtype_seq defined here also
                if _dtype_vseq == 7:
                    btf = btf - 1
                    logger.info('Block #: ' + str(btf))
                    #logger.info(_seq)
                    global packet_assembly
                    logger.info('Data block from ' + str(int_id(_rf_src)))
                    logger.info(ahex(bptc_decode(_data)))
                    if _seq == 0:
                        n_packet_assembly = 0
                        packet_assembly = ''

                    if btf < btf + 1:
                        n_packet_assembly = n_packet_assembly + 1
                        packet_assembly = packet_assembly + str(
                            bptc_decode(_data)
                        )  #str((decode_full_lc(b_packet)).strip('bitarray('))
                    # Use block 0 as trigger. $GPRMC must also be in string to indicate NMEA.
                    # This triggers the APRS upload
                    if btf == 0:  #_seq == 12:
                        final_packet = bitarray(
                            re.sub("\)|\(|bitarray|'", '',
                                   packet_assembly)).tobytes().decode(
                                       'utf-8', 'ignore')
                        if '$GPRMC' in final_packet:
                            logger.info(final_packet + '\n')
                            logger.info('Latitude: ' +
                                        re.sub(',', '', final_packet[29:40]) +
                                        ' Longitude: ' +
                                        re.sub(',', '', final_packet[41:53]) +
                                        ' Direction: ' +
                                        re.sub(',', '', final_packet[58:62]) +
                                        ' Speed: ' +
                                        re.sub(',', '', final_packet[53:58]))
                            # Begin APRS format and upload
                            aprs_loc_packet = str(
                                get_alias(int_id(_rf_src), subscriber_ids)
                            ) + '-' + str(user_ssid) + '>APRS,TCPIP*:/' + str(
                                datetime.datetime.utcnow().strftime("%H%M%Sh")
                            ) + str(final_packet[29:36]) + str(
                                final_packet[39]) + '/' + str(
                                    re.sub(',', '', final_packet[41:49])
                                ) + str(
                                    final_packet[52]
                                ) + '[/' + aprs_comment + ' DMR ID: ' + str(
                                    int_id(_rf_src))
                            logger.info(aprs_loc_packet)
                            try:
                                # Try parse of APRS packet. If it fails, it will not upload to APRS-IS
                                aprslib.parse(aprs_loc_packet)
                                AIS = aprslib.IS(aprs_callsign,
                                                 passwd=aprs_passcode,
                                                 host=aprs_server,
                                                 port=aprs_port)
                                AIS.connect()
                                AIS.sendall(aprs_loc_packet)
                                AIS.close()
                            except:
                                logger.info(
                                    'Failed to parse packet. Packet may be deformed. Not uploaded.'
                                )
                            # Get callsign based on DMR ID
                            #logger.info(get_alias(int_id(_rf_src), subscriber_ids))
                            # End APRS-IS upload
                        else:
                            logger.info(final_packet)
                        packet_assembly = ''
                    logger.info(_seq)
                    #logger.info(_dtype_vseq)
                logger.info(ahex(bptc_decode(_data)).decode('utf-8', 'ignore'))
                #logger.info(bitarray(re.sub("\)|\(|bitarray|'", '', str(bptc_decode(_data)).tobytes().decode('utf-8', 'ignore'))))

        else:
            pass
Ejemplo n.º 16
0
    def datagramReceived(self, _packet, _sockaddr):
        # Keep This Line Commented Unless HEAVILY Debugging!
        #logger.debug('(%s) RX packet from %s -- %s', self._system, _sockaddr, ahex(_packet))

        if _packet[:4] == DMRD:    # DMRData -- encapsulated DMR data frame
            _data = _packet[:53]
            _hash = _packet[53:]
            _ckhs = hmac_new(self._config['PASSPHRASE'],_data,sha1).digest()

            if compare_digest(_hash, _ckhs) and _sockaddr == self._config['TARGET_SOCK']:
                _peer_id = _data[11:15]
                _seq = _data[4]
                _rf_src = _data[5:8]
                _dst_id = _data[8:11]
                _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))

                # Sanity check for OpenBridge -- all calls must be on Slot 1 for Brandmeister or DMR+. Other HBlinks can process timeslot on OPB if the flag is set
                if _slot != 1 and not self._config['BOTH_SLOTS'] and not _call_type == 'unit':
                    logger.error('(%s) OpenBridge packet discarded because it was not received on slot 1. SID: %s, TGID %s', self._system, int_id(_rf_src), int_id(_dst_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 FROM SUBSCRIBER %s BY GLOBAL ACL', self._system, int_id(_stream_id), int_id(_rf_src))
                            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._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._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._laststrid.append(_stream_id)
                        return

                # 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)
            else:
                logger.info('(%s) OpenBridge HMAC failed, packet discarded - OPCODE: %s DATA: %s HMAC LENGTH: %s HMAC: %s', self._system, _packet[:4], repr(_packet[:53]), len(_packet[53:]), repr(_packet[53:])) 
Ejemplo n.º 17
0
    def master_datagramReceived(self, _data, _sockaddr):
        # Keep This Line Commented Unless HEAVILY Debugging!
        # logger.debug('(%s) RX packet from %s -- %s', self._system, _sockaddr, ahex(_data))

        # 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 \
                        and self._peers[_peer_id]['CONNECTION'] == 'YES' \
                        and self._peers[_peer_id]['SOCKADDR'] == _sockaddr:
                _seq = _data[4]
                _rf_src = _data[5:8]
                _dst_id = _data[8:11]
                _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, _seq, int_id(_rf_src), int_id(_dst_id))
                # ACL Processing
                if self._CONFIG['GLOBAL']['USE_ACL']:
                    if not acl_check(_rf_src, self._CONFIG['GLOBAL']['SUB_ACL']):
                        if self._laststrid[_slot] != _stream_id:
                            logger.info('(%s) CALL DROPPED WITH STREAM ID %s FROM SUBSCRIBER %s BY GLOBAL ACL', self._system, int_id(_stream_id), int_id(_rf_src))
                            self._laststrid[_slot] = _stream_id
                        return
                    if _slot == 1 and not acl_check(_dst_id, self._CONFIG['GLOBAL']['TG1_ACL']):
                        if self._laststrid[_slot] != _stream_id:
                            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._laststrid[_slot] = _stream_id
                        return
                    if _slot == 2 and not acl_check(_dst_id, self._CONFIG['GLOBAL']['TG2_ACL']):
                        if self._laststrid[_slot] != _stream_id:
                            logger.info('(%s) CALL DROPPED WITH STREAM ID %s ON TGID %s BY GLOBAL TS2 ACL', self._system, int_id(_stream_id), int_id(_dst_id))
                            self._laststrid[_slot] = _stream_id
                        return
                if self._config['USE_ACL']:
                    if not acl_check(_rf_src, self._config['SUB_ACL']):
                        if self._laststrid[_slot] != _stream_id:
                            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._laststrid[_slot] = _stream_id
                        return
                    if _slot == 1 and not acl_check(_dst_id, self._config['TG1_ACL']):
                        if self._laststrid[_slot] != _stream_id:
                            logger.info('(%s) CALL DROPPED WITH STREAM ID %s ON TGID %s BY SYSTEM TS1 ACL', self._system, int_id(_stream_id), int_id(_dst_id))
                            self._laststrid[_slot] = _stream_id
                        return
                    if _slot == 2 and not acl_check(_dst_id, self._config['TG2_ACL']):
                        if self._laststrid[_slot]!= _stream_id:
                            logger.info('(%s) CALL DROPPED WITH STREAM ID %s ON TGID %s BY SYSTEM TS2 ACL', self._system, int_id(_stream_id), int_id(_dst_id))
                            self._laststrid[_slot] = _stream_id
                        return

                # The basic purpose of a master is to repeat to the peers
                if self._config['REPEAT'] == True:
                    pkt = [_data[:11], '', _data[15:]]
                    for _peer in self._peers:
                        if _peer != _peer_id:
                            pkt[1] = _peer
                            self.transport.write(b''.join(pkt), self._peers[_peer]['SOCKADDR'])
                            #logger.debug('(%s) Packet on TS%s from %s (%s) for destination ID %s repeated to peer: %s (%s) [Stream ID: %s]', self._system, _slot, self._peers[_peer_id]['CALLSIGN'], int_id(_peer_id), int_id(_dst_id), self._peers[_peer]['CALLSIGN'], int_id(_peer), int_id(_stream_id))


                # 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)

        elif _command == RPTL:    # RPTLogin -- a repeater wants to login
            _peer_id = _data[4:8]
            # Check to see if we've reached the maximum number of allowed peers
            if len(self._peers) < self._config['MAX_PEERS']:
                # Check for valid Radio ID
                if acl_check(_peer_id, self._CONFIG['GLOBAL']['REG_ACL']) and acl_check(_peer_id, self._config['REG_ACL']):
                    # Build the configuration data strcuture for the peer
                    self._peers.update({_peer_id: {
                        'CONNECTION': 'RPTL-RECEIVED',
                        'CONNECTED': time(),
                        'PINGS_RECEIVED': 0,
                        'LAST_PING': time(),
                        'SOCKADDR': _sockaddr,
                        'IP': _sockaddr[0],
                        'PORT': _sockaddr[1],
                        'SALT': randint(0,0xFFFFFFFF),
                        'RADIO_ID': str(int(ahex(_peer_id), 16)),
                        'CALLSIGN': '',
                        'RX_FREQ': '',
                        'TX_FREQ': '',
                        'TX_POWER': '',
                        'COLORCODE': '',
                        'LATITUDE': '',
                        'LONGITUDE': '',
                        'HEIGHT': '',
                        'LOCATION': '',
                        'DESCRIPTION': '',
                        'SLOTS': '',
                        'URL': '',
                        'SOFTWARE_ID': '',
                        'PACKAGE_ID': '',
                    }})
                    logger.info('(%s) Repeater Logging in with Radio ID: %s, %s:%s', self._system, int_id(_peer_id), _sockaddr[0], _sockaddr[1])
                    _salt_str = bytes_4(self._peers[_peer_id]['SALT'])
                    self.send_peer(_peer_id, b''.join([RPTACK, _salt_str]))
                    self._peers[_peer_id]['CONNECTION'] = 'CHALLENGE_SENT'
                    logger.info('(%s) Sent Challenge Response to %s for login: %s', self._system, int_id(_peer_id), self._peers[_peer_id]['SALT'])
                else:
                    self.transport.write(b''.join([MSTNAK, _peer_id]), _sockaddr)
                    logger.warning('(%s) Invalid Login from %s Radio ID: %s Denied by Registation ACL', self._system, _sockaddr[0], int_id(_peer_id))
            else:
                self.transport.write(b''.join([MSTNAK, _peer_id]), _sockaddr)
                logger.warning('(%s) Registration denied from Radio ID: %s Maximum number of peers exceeded', self._system, int_id(_peer_id))

        elif _command == RPTK:    # Repeater has answered our login challenge
            _peer_id = _data[4:8]
            if _peer_id in self._peers \
                        and self._peers[_peer_id]['CONNECTION'] == 'CHALLENGE_SENT' \
                        and self._peers[_peer_id]['SOCKADDR'] == _sockaddr:
                _this_peer = self._peers[_peer_id]
                _this_peer['LAST_PING'] = time()
                _sent_hash = _data[8:]
                _salt_str = bytes_4(_this_peer['SALT'])
                _calc_hash = bhex(sha256(_salt_str+self._config['PASSPHRASE']).hexdigest())
                if _sent_hash == _calc_hash:
                    _this_peer['CONNECTION'] = 'WAITING_CONFIG'
                    self.send_peer(_peer_id, b''.join([RPTACK, _peer_id]))
                    logger.info('(%s) Peer %s has completed the login exchange successfully', self._system, _this_peer['RADIO_ID'])
                else:
                    logger.info('(%s) Peer %s has FAILED the login exchange successfully', self._system, _this_peer['RADIO_ID'])
                    self.transport.write(b''.join([MSTNAK, _peer_id]), _sockaddr)
                    del self._peers[_peer_id]
            else:
                self.transport.write(b''.join([MSTNAK, _peer_id]), _sockaddr)
                logger.warning('(%s) Login challenge from Radio ID that has not logged in: %s', self._system, int_id(_peer_id))

        elif _command == RPTC:    # Repeater is sending it's configuraiton OR disconnecting
            if _data[:5] == RPTCL:    # Disconnect command
                _peer_id = _data[5:9]
                if _peer_id in self._peers \
                            and self._peers[_peer_id]['CONNECTION'] == 'YES' \
                            and self._peers[_peer_id]['SOCKADDR'] == _sockaddr:
                    logger.info('(%s) Peer is closing down: %s (%s)', self._system, self._peers[_peer_id]['CALLSIGN'], int_id(_peer_id))
                    self.transport.write(b''.join([MSTNAK, _peer_id]), _sockaddr)
                    del self._peers[_peer_id]

            else:
                _peer_id = _data[4:8]      # Configure Command
                if _peer_id in self._peers \
                            and self._peers[_peer_id]['CONNECTION'] == 'WAITING_CONFIG' \
                            and self._peers[_peer_id]['SOCKADDR'] == _sockaddr:
                    _this_peer = self._peers[_peer_id]
                    _this_peer['CONNECTION'] = 'YES'
                    _this_peer['CONNECTED'] = time()
                    _this_peer['LAST_PING'] = time()
                    _this_peer['CALLSIGN'] = _data[8:16]
                    _this_peer['RX_FREQ'] = _data[16:25]
                    _this_peer['TX_FREQ'] =  _data[25:34]
                    _this_peer['TX_POWER'] = _data[34:36]
                    _this_peer['COLORCODE'] = _data[36:38]
                    _this_peer['LATITUDE'] = _data[38:46]
                    _this_peer['LONGITUDE'] = _data[46:55]
                    _this_peer['HEIGHT'] = _data[55:58]
                    _this_peer['LOCATION'] = _data[58:78]
                    _this_peer['DESCRIPTION'] = _data[78:97]
                    _this_peer['SLOTS'] = _data[97:98]
                    _this_peer['URL'] = _data[98:222]
                    _this_peer['SOFTWARE_ID'] = _data[222:262]
                    _this_peer['PACKAGE_ID'] = _data[262:302]

                    self.send_peer(_peer_id, b''.join([RPTACK, _peer_id]))
                    logger.info('(%s) Peer %s (%s) has sent repeater configuration', self._system, _this_peer['CALLSIGN'], _this_peer['RADIO_ID'])
                else:
                    self.transport.write(b''.join([MSTNAK, _peer_id]), _sockaddr)
                    logger.warning('(%s) Peer info from Radio ID that has not logged in: %s', self._system, int_id(_peer_id))

        elif _command == RPTP:    # RPTPing -- peer is pinging us
                _peer_id = _data[7:11]
                if _peer_id in self._peers \
                            and self._peers[_peer_id]['CONNECTION'] == "YES" \
                            and self._peers[_peer_id]['SOCKADDR'] == _sockaddr:
                    self._peers[_peer_id]['PINGS_RECEIVED'] += 1
                    self._peers[_peer_id]['LAST_PING'] = time()
                    self.send_peer(_peer_id, b''.join([MSTPONG, _peer_id]))
                    logger.debug('(%s) Received and answered RPTPING from peer %s (%s)', self._system, self._peers[_peer_id]['CALLSIGN'], int_id(_peer_id))
                else:
                    self.transport.write(b''.join([MSTNAK, _peer_id]), _sockaddr)
                    logger.warning('(%s) Ping from Radio ID that is not logged in: %s', self._system, int_id(_peer_id))

        elif _command == RPTO:
            _peer_id = _data[4:8]
            if _peer_id in self._peers \
                        and self._peers[_peer_id]['CONNECTION'] == 'YES' \
                        and self._peers[_peer_id]['SOCKADDR'] == _sockaddr:
                logger.info('(%s) Peer %s (%s) has send options: %s', self._system, self._peers[_peer_id]['CALLSIGN'], int_id(_peer_id), _data[8:])
                self.transport.write(b''.join([RPTACK, _peer_id]), _sockaddr)

        elif _command == DMRA:
            _peer_id = _data[4:8]
            logger.info('(%s) Recieved DMR Talker Alias from peer %s, subscriber %s', self._system, self._peers[_peer_id]['CALLSIGN'], int_id(_rf_src))

        else:
            logger.error('(%s) Unrecognized command. Raw HBP PDU: %s', self._system, ahex(_data))
Ejemplo n.º 18
0
    def datagramReceived(self, data, addr):

        # HomeBrew Protocol Commands
        DMRD = b'DMRD'
        DMRA = b'DMRA'
        MSTCL = b'MSTCL'
        MSTNAK = b'MSTNAK'
        MSTPONG = b'MSTPONG'
        MSTN = b'MSTN'
        MSTP = b'MSTP'
        MSTC = b'MSTC'
        RPTL = b'RPTL'
        RPTPING = b'RPTPING'
        RPTCL = b'RPTCL'
        RPTL = b'RPTL'
        RPTACK = b'RPTACK'
        RPTK = b'RPTK'
        RPTC = b'RPTC'
        RPTP = b'RPTP'
        RPTA = b'RPTA'
        RPTO = b'RPTO'

        host, port = addr

        nowtime = time()

        Debug = self.debug

        #If the packet comes from the master
        if host == self.master:
            _command = data[:4]

            if _command == DMRD:
                _peer_id = data[11:15]
            elif _command == RPTA:
                if data[6:10] in self.peerTrack:
                    _peer_id = data[6:10]
                else:
                    _peer_id = self.connTrack[port]
            elif _command == MSTN:
                _peer_id = data[6:10]
                self.peerTrack[_peer_id]['timer'].cancel()
                self.reaper(_peer_id)
                return
            elif _command == MSTP:
                _peer_id = data[7:11]
            elif _command == MSTC:
                _peer_id = data[5:9]
                self.peerTrack[_peer_id]['timer'].cancel()
                self.reaper(_peer_id)
                return

        #  _peer_id = self.connTrack[port]
            if self.debug:
                print(data)
            if _peer_id and _peer_id in self.peerTrack:
                self.transport.write(data, (self.peerTrack[_peer_id]['shost'],
                                            self.peerTrack[_peer_id]['sport']))
                #self.peerTrack[_peer_id]['timer'].reset()
            return

        else:
            _command = data[:4]

            if _command == DMRD:  # DMRData -- encapsulated DMR data frame
                _peer_id = data[11:15]
            elif _command == DMRA:  # DMRAlias -- Talker Alias information
                _peer_id = _data[4:8]
            elif _command == RPTL:  # RPTLogin -- a repeater wants to login
                _peer_id = data[4:8]
            elif _command == RPTK:  # Repeater has answered our login challenge
                _peer_id = data[4:8]
            elif _command == RPTC:  # Repeater is sending it's configuraiton OR disconnecting
                if data[:5] == RPTCL:  # Disconnect command
                    _peer_id = data[5:9]
                else:
                    _peer_id = data[4:8]  # Configure Command
            elif _command == RPTO:  # options
                _peer_id = data[4:8]
            elif _command == RPTP:  # RPTPing -- peer is pinging us
                _peer_id = data[7:11]
            else:
                return

            if _peer_id in self.peerTrack:
                _dport = self.peerTrack[_peer_id]['dport']
                self.peerTrack[_peer_id]['sport'] = port
                self.peerTrack[_peer_id]['shost'] = host
                self.transport.write(data, ('127.0.0.1', _dport))
                self.peerTrack[_peer_id]['timer'].reset()
                if self.debug:
                    print(data)
                return
            else:

                if int_id(_peer_id) in self.blackList:
                    return
                #for _dport in self.connTrack:
                while True:
                    _dport = random.randint(1, (self.numPorts - 1))
                    _dport = _dport + self.destPortStart
                    if not self.connTrack[_dport]:
                        break
                self.connTrack[_dport] = _peer_id
                self.peerTrack[_peer_id] = {}
                self.peerTrack[_peer_id]['dport'] = _dport
                self.peerTrack[_peer_id]['sport'] = port
                self.peerTrack[_peer_id]['shost'] = host
                self.peerTrack[_peer_id]['timer'] = ResettableTimer(
                    self.timeout, self.reaper, [_peer_id])
                self.peerTrack[_peer_id]['timer'].start()
                self.transport.write(data, (self.master, _dport))
                if self.debug:
                    print(data)
                return
Ejemplo n.º 19
0
def acl_check(_id, _acl):
    id = int_id(_id)
    for entry in _acl[1]:
        if entry[0] <= id <= entry[1]:
            return _acl[0]
    return not _acl[0]
Ejemplo n.º 20
0
    def datagramReceived(self, data, addr):

        # HomeBrew Protocol Commands
        DMRD = b'DMRD'
        DMRA = b'DMRA'
        MSTCL = b'MSTCL'
        MSTNAK = b'MSTNAK'
        MSTPONG = b'MSTPONG'
        MSTN = b'MSTN'
        MSTP = b'MSTP'
        MSTC = b'MSTC'
        RPTL = b'RPTL'
        RPTPING = b'RPTPING'
        RPTCL = b'RPTCL'
        RPTL = b'RPTL'
        RPTACK = b'RPTACK'
        RPTK = b'RPTK'
        RPTC = b'RPTC'
        RPTP = b'RPTP'
        RPTA = b'RPTA'
        RPTO = b'RPTO'

        _peer_id = False

        host, port = addr

        nowtime = time()

        Debug = self.debug

        #If the packet comes from the master
        if host == self.master:
            _command = data[:4]

            if _command == DMRD:
                _peer_id = data[11:15]
            elif _command == RPTA:
                if data[6:10] in self.peerTrack:
                    _peer_id = data[6:10]
                else:
                    _peer_id = self.connTrack[port]
            elif _command == MSTN:
                _peer_id = data[6:10]
            elif _command == MSTP:
                _peer_id = data[7:11]
            elif _command == MSTC:
                _peer_id = data[5:9]

            if self.debug:
                print(data)
            if _peer_id in self.peerTrack:
                self.transport.write(data, (self.peerTrack[_peer_id]['shost'],
                                            self.peerTrack[_peer_id]['sport']))
                # Remove the client after send a MSTN or MSTC packet
                if _command in (MSTN, MSTC):
                    # Give time to the client for a reply to prevent port reassignment
                    self.peerTrack[_peer_id]['timer'].reset(15)

            return

        else:
            _command = data[:4]

            if _command == DMRD:  # DMRData -- encapsulated DMR data frame
                _peer_id = data[11:15]
            elif _command == DMRA:  # DMRAlias -- Talker Alias information
                _peer_id = data[4:8]
            elif _command == RPTL:  # RPTLogin -- a repeater wants to login
                _peer_id = data[4:8]
            elif _command == RPTK:  # Repeater has answered our login challenge
                _peer_id = data[4:8]
            elif _command == RPTC:  # Repeater is sending it's configuraiton OR disconnecting
                if data[:5] == RPTCL:  # Disconnect command
                    _peer_id = data[5:9]
                else:
                    _peer_id = data[4:8]  # Configure Command
            elif _command == RPTO:  # options
                _peer_id = data[4:8]
            elif _command == RPTP:  # RPTPing -- peer is pinging us
                _peer_id = data[7:11]
            else:
                return

            if _peer_id in self.peerTrack:
                _dport = self.peerTrack[_peer_id]['dport']
                self.peerTrack[_peer_id]['sport'] = port
                self.peerTrack[_peer_id]['shost'] = host
                self.transport.write(data, (self.master, _dport))
                self.peerTrack[_peer_id]['timer'].reset(self.timeout)
                if self.debug:
                    print(data)
                return

            else:
                if int_id(_peer_id) in self.blackList:
                    return
                # Make a list with the available ports
                _ports_avail = [
                    port for port in self.connTrack if not self.connTrack[port]
                ]
                if len(_ports_avail) > 0:
                    _dport = random.choice(_ports_avail)
                else:
                    return
                self.connTrack[_dport] = _peer_id
                self.peerTrack[_peer_id] = {}
                self.peerTrack[_peer_id]['dport'] = _dport
                self.peerTrack[_peer_id]['sport'] = port
                self.peerTrack[_peer_id]['shost'] = host
                self.peerTrack[_peer_id]['timer'] = reactor.callLater(
                    self.timeout, self.reaper, _peer_id)
                self.transport.write(data, (self.master, _dport))

                if self.clientinfo and _peer_id != b'\x00m@\xd7':
                    print(
                        f'New client: ID:{str(int_id(_peer_id)).rjust(9)} IP:{host.rjust(15)} Port:{port}, assigned to port:{_dport}.'
                    )
                if self.debug:
                    print(data)
                return