From 1532fdcc8e1cadd93f0818f2d8167393efdee605 Mon Sep 17 00:00:00 2001 From: lwvmobile Date: Tue, 6 May 2025 21:19:11 -0400 Subject: [PATCH] Event History Setup: #287 Include a simple sh file to startup dsd-fme with opts line, and open log files for multi linux terminal support; Fix bug with P25p1 MPDU Trunking Blocks setting address values to trigger event history watchdog; Add an internal string into event history to log internal events of note (ENC LO, errors, etc); Add a watchdog during any ENC LO event so the event_history will log the call with ENC LO; Disable AHOY and RSP PDU's from Event History (clogs up the event history with extra info); Fix DMR p_clear trigger to zero out src and tg values when tuning away; Fix Hytera Enhanced RC4 (verified working); Misc Tweaks Regarding; --- examples/start-dsd-fme-linux-terminal.sh | 112 +++++++++++++++++++++++ include/dsd.h | 1 + src/crypt-rc4.c | 7 +- src/dmr_block.c | 6 +- src/dmr_csbk.c | 60 +++++++----- src/dmr_flco.c | 29 +++++- src/dmr_pi.c | 8 +- src/dsd_mbe.c | 10 +- src/dsd_ncurses.c | 16 +++- src/nxdn_element.c | 7 ++ src/p25p1_ldu2.c | 7 ++ src/p25p1_pdu_data.c | 9 +- src/p25p2_frame.c | 9 ++ 13 files changed, 240 insertions(+), 41 deletions(-) create mode 100644 examples/start-dsd-fme-linux-terminal.sh diff --git a/examples/start-dsd-fme-linux-terminal.sh b/examples/start-dsd-fme-linux-terminal.sh new file mode 100644 index 0000000..5e0de6f --- /dev/null +++ b/examples/start-dsd-fme-linux-terminal.sh @@ -0,0 +1,112 @@ +#!/bin/bash +# Force bash for better compatibility (I think) +# +# Digital Speech Decoder: Florida Man Edition +# +# The source code of this software can be downloaded here: +# https://github.com/lwvmobile/dsd-fme +# +# If you paid for, or were otherwise fleeced for this software, DEMAND YOUR MONEY BACK! +# +# This software is designed to be used with an SDR receiver (like SDR++ or SDR#) with TCP input, +# RTL Input, media file playback over virtual cables or null-sinks, or a Discriminator Tap input +# +# The complete options list can be seen by viewing complete_usage_options.ans +# Many examples can be found in example_options.ans +# +# Enjoy! +### +#### IMPORTANT! Set your dsd-fme options here! #### +# Example : opts=' -ft -i rtl:0:460.350M:0:-1:8 -N -Z ' +#### +# set options to pass to dsd-fme +opts=' -N -Z ' +#### +# Initialize variables +xe="0" +gt="0" +xt="0" +ko="0" +# Functions to check for available terminals +chk_xe(){ +# Check if x-terminal-emulator is installed +xe=$(which x-terminal-emulator 2>/dev/null) +if [ -z $xe ];then xe="0";else xe="1";fi +} +chk_gt(){ +# Check if gnome-terminal is installed +gt=$(which gnome-terminal 2>/dev/null) +if [ -z $gt ];then gt="0";else gt="1";fi +} +chk_ko(){ +# Check if Konsole is installed +ko=$(which konsole 2>/dev/null) +if [ -z $ko ];then ko="0";else ko="1";fi +} +chk_xt(){ +# Check if xterm is installed +xt=$(which xterm 2>/dev/null) +if [ -z $xt ];then xt="0";else xt="1";fi +} +# Check for and set terminal +chk_xe +if [ $xe = "1" ];then + term=$(which x-terminal-emulator 2>/dev/null) + printf "Using X-Terminal-Emulator!\n" +else + chk_gt +fi +if [ $gt = "1" ];then + term=$(which gnome-terminal 2>/dev/null) + printf "Using Gnome-Terminal!\n" +elif [ $xe = "0" ]&&[ $gt = "0" ];then + chk_xt +fi +if [ $xt = "1" ];then + term=$(which xterm 2>/dev/null) + printf "Using XTerm!\n" +elif [ $xe = "0" ]&&[ $gt = "0" ]&&[ $xt = "0" ];then + chk_ko +fi +if [ $ko = "1" ];then + term=$(which konsole 2>/dev/null) + printf "Using Konsole!\n" +fi +# Bail if no terminal found +if [ "$ko" -eq "0" ]&&[ "$gt" -eq "0" ]&&[ "$xt" -eq "0" ]&&[ "$xe" -eq "0" ];then printf "No known terminals available!\n";exit 1;fi +# Get current directory +wd=$(pwd) +# Set date/time +# dt=$(date +%F_%H%M-%S-%N) #with hyphens +dt=$(date +%Y%m%d_%H%M%S) #just an underscore between date and time +if [ ! -d "logs" ]; then + mkdir logs +fi +# set log file relative filepath +clog="$wd/logs/console_log_$dt.txt" +elog="$wd/logs/event_log_$dt.txt" +# create the log file now with touch +touch $clog +touch $elog +# open new terminal windows to watch live log files +if [ "$term" == "$(which konsole)" ]||[ "$term" == "$(which xterm)" ];then + $term -e "tail -n 40 -f $clog" 2>/dev/null + $term -e "tail -n 40 -f $elog" 2>/dev/null +else + $term --window -e "tail -n 40 -f $clog" 2>/dev/null + $term --window -e "tail -n 40 -f $elog" 2>/dev/null +fi +# start dsd-fme with options and log files +dsd-fme $opts -J $elog 2> $clog +echo ------------------------------------------------------------------------------- +echo ------------------------------------------------------------------------------- +echo For any errors, see: $clog +echo Forward $clog and +echo Options: \" $opts \" +echo to developer on Github or Radio Reference for troubleshooting. +echo ------------------------------------------------------------------------------- +echo ------------------------------------------------------------------------------- + +# Set pause to diplay above message +read -p "Press ENTER to continue... " x + diff --git a/include/dsd.h b/include/dsd.h index b0be9ff..63f15dc 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -121,6 +121,7 @@ typedef struct { char gps_s[2000]; //gps, if returned, expressed as a string char text_message[2000]; //if this event is a decoded text message, then it goes here char event_string[2000]; //user legible and printable string for the event that happened + char internal_str[2000]; //string that relates to a DSD-FME generated event (ENC LO, error notices, etc) } Event_History; //event history for number of each items above diff --git a/src/crypt-rc4.c b/src/crypt-rc4.c index cea9486..7f28196 100644 --- a/src/crypt-rc4.c +++ b/src/crypt-rc4.c @@ -88,8 +88,8 @@ void rc4_block_output (int drop, int keylen, int meslen, uint8_t * key, uint8_t } -//NOTE: This has not been verified to work properly -//NOTE: This is for Hytera Enhanced RC4, if AES, this will not work +//This is now verified to work after changing the drop byte value from 256 to 0. +//also, had to change the application to not skip the additional 7 bits like DMRA or P25 does. void hytera_enhanced_rc4_setup(dsd_opts * opts, dsd_state * state, unsigned long long int key_value, unsigned long long int mi_value) { @@ -119,7 +119,8 @@ void hytera_enhanced_rc4_setup(dsd_opts * opts, dsd_state * state, unsigned long ks_octets = state->ks_octetL; else ks_octets = state->ks_octetR; - rc4_block_output(256, 5, 135, key, ks); + //NOTE: Drop Byte value is 0 + rc4_block_output(0, 5, 135, key, ks); for (int i = 0; i < 5; i++) kiv[i] = key[i] ^ mi[i]; diff --git a/src/dmr_block.c b/src/dmr_block.c index cbd4d7c..90d243e 100644 --- a/src/dmr_block.c +++ b/src/dmr_block.c @@ -284,9 +284,9 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t fprintf (stderr, "\n %s", rsp_string); - //REMUS, enable (or disable) next two lines is you want to - sprintf (state->dmr_lrrp_gps[slot], "%s; ", rsp_string); - watchdog_event_datacall (opts, state, source, target, state->dmr_lrrp_gps[slot], slot); + //REMUS, enable (or disable) next two lines is you want to // + // sprintf (state->dmr_lrrp_gps[slot], "%s; ", rsp_string); + // watchdog_event_datacall (opts, state, source, target, state->dmr_lrrp_gps[slot], slot); } diff --git a/src/dmr_csbk.c b/src/dmr_csbk.c index e62eb41..8c12232 100644 --- a/src/dmr_csbk.c +++ b/src/dmr_csbk.c @@ -502,6 +502,10 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8 if (opts->p25_trunk == 1 && state->p25_cc_freq != 0 && opts->p25_is_tuned == 1) { + //run a watchdog here so we can update this with the most recent info + watchdog_event_current(opts, state, 0); + watchdog_event_current(opts, state, 1); + //display/le/buzzer bug fix when p_clear activated (unsure why this was disabled) //clear only the current slot initially, then clear both if tuning to a different freq if (state->currentslot == 0 && csbk_fid != 253) //don't reset on Cap+ since we aren't testing based on the current TS @@ -529,11 +533,15 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8 //clear both if tuning away to another frequency if (GetCurrentFreq(opts->rigctl_sockfd) != state->p25_cc_freq) { + state->lastsrc = 0; + state->lasttg = 0; state->payload_mi = 0; state->payload_algid = 0; state->payload_keyid = 0; state->dmr_so = 0; + state->lastsrcR = 0; + state->lasttgR = 0; state->payload_miR = 0; state->payload_algidR = 0; state->payload_keyidR = 0; @@ -564,11 +572,15 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8 //clear both if tuning away to another frequency if (opts->rtlsdr_center_freq != tempf) { + state->lastsrc = 0; + state->lasttg = 0; state->payload_mi = 0; state->payload_algid = 0; state->payload_keyid = 0; state->dmr_so = 0; + state->lastsrcR = 0; + state->lasttgR = 0; state->payload_miR = 0; state->payload_algidR = 0; state->payload_keyidR = 0; @@ -1024,29 +1036,31 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8 //check the source and/or target for special gateway identifiers dmr_gateway_identifier (ahoy_source, ahoy_target); - if (state->currentslot == 0) - { - state->lastsrc = ahoy_source; - state->lasttg = ahoy_target; - } - else - { - state->lastsrcR = ahoy_source; - state->lasttgR = ahoy_target; - } - watchdog_event_datacall (opts, state, ahoy_source, ahoy_target, ahoy_str, state->currentslot); - if (state->currentslot == 0) - { - state->lastsrc = 0; - state->lasttg = 0; - } - else - { - state->lastsrcR = 0; - state->lasttgR = 0; - } - watchdog_event_history(opts, state, 0); - watchdog_event_current(opts, state, 0); + //log ahoy as a data call event //re-enable this if you want, but it can clog up the event history + // if (state->currentslot == 0) + // { + // state->lastsrc = ahoy_source; + // state->lasttg = ahoy_target; + // } + // else + // { + // state->lastsrcR = ahoy_source; + // state->lasttgR = ahoy_target; + // } + // watchdog_event_datacall (opts, state, ahoy_source, ahoy_target, ahoy_str, state->currentslot); + // if (state->currentslot == 0) + // { + // state->lastsrc = 0; + // state->lasttg = 0; + // } + // else + // { + // state->lastsrcR = 0; + // state->lasttgR = 0; + // } + // watchdog_event_history(opts, state, 0); + // watchdog_event_current(opts, state, 0); + //end ahoy logging } diff --git a/src/dmr_flco.c b/src/dmr_flco.c index 2eee74d..529405d 100644 --- a/src/dmr_flco.c +++ b/src/dmr_flco.c @@ -316,7 +316,13 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C unsigned long long int mi = (unsigned long long int)ConvertBitIntoBytes(&lc_bits[24], 40); fprintf (stderr, "%s", KYEL); fprintf (stderr, " Slot %d Alg: %02X; KEY ID: %02X; MI(40): %010llX;", slot+1, alg, key, mi); - fprintf (stderr, " Hytera Enhanced;"); + fprintf (stderr, " Hytera Enhanced; "); + + if (slot == 0 && state->R != 0) + fprintf (stderr, "Key: %010llX; ", state->R); + + if (slot == 1 && state->RR != 0) + fprintf (stderr, "Key: %010llX; ", state->RR); for (int i = 0; i < 8; i++) { @@ -555,6 +561,13 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C state->group_tally++; } + //run a watchdog here so we can update this with the crypto variables and ENC LO + if (target != 0 && lo == 0) + { + sprintf (state->event_history_s[slot].Event_History_Items[0].internal_str, "Target: %d; has been locked out; Encryption Lock Out Enabled.", target); + watchdog_event_current(opts, state, slot); + } + //Craft a fake CSBK pdu send it to run as a p_clear to return to CC if available uint8_t dummy[12]; uint8_t* dbits; memset (dummy, 0, sizeof(dummy)); dummy[0] = 46; dummy[1] = 255; if ( (strcmp(gm, "B") == 0) && (strcmp(gn, "ENC LO") == 0) ) //&& (opts->trunk_tune_data_calls == 0) @@ -716,6 +729,20 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C fprintf (stderr, "%s ", KNRM); } + if (slot == 0 && state->payload_algid == 0x02 && state->R != 0) + { + fprintf (stderr, "%s", KYEL); + fprintf (stderr, "Key: %010llX ", state->R); + fprintf (stderr, "%s ", KNRM); + } + + if (slot == 1 && state->payload_algidR == 0x02 && state->RR != 0) + { + fprintf (stderr, "%s", KYEL); + fprintf (stderr, "Key: %010llX ", state->RR); + fprintf (stderr, "%s ", KNRM); + } + if (slot == 0 && (state->payload_algid == 0x25 || state->payload_algid == 0x24) && state->aes_key_loaded[0] == 1) { fprintf (stderr, "\n "); diff --git a/src/dmr_pi.c b/src/dmr_pi.c index 257d0ce..1925289 100644 --- a/src/dmr_pi.c +++ b/src/dmr_pi.c @@ -65,7 +65,13 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC if (checksum == PI_BYTE[9]) { - fprintf (stderr, " Hytera Enhanced;"); + fprintf (stderr, " Hytera Enhanced; "); + + if (state->currentslot == 0 && state->R != 0) + fprintf (stderr, "Key: %010llX; ", state->R); + + if (state->currentslot == 1 && state->RR != 0) + fprintf (stderr, "Key: %010llX; ", state->RR); //disable late entry for DMRA (hopefully, there aren't any systems running both DMRA and Hytera Enhanced mixed together) opts->dmr_le = 2; diff --git a/src/dsd_mbe.c b/src/dsd_mbe.c index 735bebf..29e2431 100644 --- a/src/dsd_mbe.c +++ b/src/dsd_mbe.c @@ -802,8 +802,9 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a //last bit ambe_d[48] ^= state->ks_bitstreamL[state->bit_counterL++]; - //skip the next 7 bits of the array - state->bit_counterL += 7; + //skip the next 7 bits of the array (if not Hytera Enhanced) + if(state->payload_algid != 0x02) + state->bit_counterL += 7; //increment vc counter by one state->DMRvcL++; @@ -1179,8 +1180,9 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a //last bit ambe_d[48] ^= state->ks_bitstreamR[state->bit_counterR++]; - //skip the next 7 bits of the array - state->bit_counterR += 7; + //skip the next 7 bits of the array (if not Hytera Enhanced) + if(state->payload_algidR != 0x02) + state->bit_counterR += 7; //increment vc counter by one state->DMRvcR++; diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c index 0839b3e..22aaec1 100644 --- a/src/dsd_ncurses.c +++ b/src/dsd_ncurses.c @@ -3000,8 +3000,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) { attron(COLOR_PAIR(1)); printw("Hytera Enhanced"); - // if (state->R != 0) - // printw(" Key: %010X", state->R); + if (state->R != 0) + printw(" Key: %010llX", state->R); attron(COLOR_PAIR(3)); } @@ -3175,8 +3175,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) { attron(COLOR_PAIR(1)); printw("Hytera Enhanced"); - // if (state->RR != 0) - // printw(" Key: %010X", state->RR); + if (state->RR != 0) + printw(" Key: %010llX", state->RR); attron(COLOR_PAIR(3)); } @@ -3517,6 +3517,10 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) if (strncmp(text_string, state->event_history_s[slot].Event_History_Items[i%255].gps_s, 13) != 0) printw ("| GPS: %s \n", state->event_history_s[slot].Event_History_Items[i%255].gps_s); + sprintf (text_string, "%s", "BUMBLEBEETUNA"); + if (strncmp(text_string, state->event_history_s[slot].Event_History_Items[i%255].internal_str, 13) != 0) + printw ("| DSD-FME: %s \n", state->event_history_s[slot].Event_History_Items[i%255].internal_str); + } printw ("------------------------------------------------------------------------------\n"); attroff(COLOR_PAIR(4)); //cyan for history @@ -4427,6 +4431,7 @@ void init_event_history (Event_History_I * event_struct, uint8_t start, uint8_t sprintf (event_struct->Event_History_Items[i].gps_s, "%s", "BUMBLEBEETUNA"); sprintf (event_struct->Event_History_Items[i].text_message, "%s", "BUMBLEBEETUNA"); sprintf (event_struct->Event_History_Items[i].event_string, "%s", "BUMBLEBEETUNA"); + sprintf (event_struct->Event_History_Items[i].internal_str, "%s", "BUMBLEBEETUNA"); } } @@ -4467,6 +4472,7 @@ void push_event_history (Event_History_I * event_struct) sprintf (event_struct->Event_History_Items[i].gps_s, "%s", event_struct->Event_History_Items[i-1].gps_s); sprintf (event_struct->Event_History_Items[i].text_message, "%s", event_struct->Event_History_Items[i-1].text_message); sprintf (event_struct->Event_History_Items[i].event_string, "%s", event_struct->Event_History_Items[i-1].event_string); + sprintf (event_struct->Event_History_Items[i].internal_str, "%s", event_struct->Event_History_Items[i-1].internal_str); } } @@ -4489,6 +4495,8 @@ void write_event_to_log_file (dsd_opts * opts, dsd_state * state, uint8_t slot, fprintf (event_log_file, " Talker Alias: %s \n", state->event_history_s[slot].Event_History_Items[0].alias); if (strncmp(text_string, state->event_history_s[slot].Event_History_Items[0].gps_s, 13) != 0) fprintf (event_log_file, " GPS: %s \n", state->event_history_s[slot].Event_History_Items[0].gps_s); + if (strncmp(text_string, state->event_history_s[slot].Event_History_Items[0].internal_str, 13) != 0) + fprintf (event_log_file, " DSD-FME: %s \n", state->event_history_s[slot].Event_History_Items[0].internal_str); //flush and close log file fflush (event_log_file); diff --git a/src/nxdn_element.c b/src/nxdn_element.c index f06a1a8..4006460 100644 --- a/src/nxdn_element.c +++ b/src/nxdn_element.c @@ -1393,6 +1393,13 @@ void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message) state->group_tally++; } + //run a watchdog here so we can update this with the crypto variables and ENC LO + if (DestinationID != 0 && lo == 0) + { + sprintf (state->event_history_s[0].Event_History_Items[0].internal_str, "Target: %d; has been locked out; Encryption Lock Out Enabled.", DestinationID); + watchdog_event_current(opts, state, 0); + } + //Craft a fake DISC Message send it to return to CC uint8_t dbits[96]; memset (dbits, 0, sizeof(dbits)); dbits[3] = 1; dbits[7] = 1; //DISC = 0x11; if ( (strcmp(gm, "DE") == 0) && (strcmp(gn, "ENC LO") == 0) ) diff --git a/src/p25p1_ldu2.c b/src/p25p1_ldu2.c index 3e4fa8a..8ba2f16 100644 --- a/src/p25p1_ldu2.c +++ b/src/p25p1_ldu2.c @@ -702,6 +702,13 @@ processLDU2 (dsd_opts * opts, dsd_state * state) state->group_tally++; } + //run a watchdog here so we can update this with the crypto variables and ENC LO + if (ttg != 0 && enc_wr == 0) // + { + sprintf (state->event_history_s[0].Event_History_Items[0].internal_str, "Target: %d; has been locked out; Encryption Lock Out Enabled.", ttg); + watchdog_event_current(opts, state, 0); + } + //return to the control channel fprintf (stderr, " No Enc Following on P25p1 Trunking; Return to CC; \n"); return_to_cc (opts, state); diff --git a/src/p25p1_pdu_data.c b/src/p25p1_pdu_data.c index 16c2d0b..a3e8e5e 100644 --- a/src/p25p1_pdu_data.c +++ b/src/p25p1_pdu_data.c @@ -412,8 +412,13 @@ void p25_decode_pdu_header(dsd_opts * opts, dsd_state * state, uint8_t * input) watchdog_event_current(opts, state, 0); } - state->lasttg = address; - state->lastsrc = 0xFFFFFF; //none given, unless extended, so put any here for now + //following is for a continued PDU and not a response nor a trunking message + if (sap != 61 && sap != 63) //trunking blocks, don't set address (LID) + { + state->lasttg = address; + state->lastsrc = 0xFFFFFF; //none given, unless extended, so put any here for now + } + } //user or other data delivered via PDU format diff --git a/src/p25p2_frame.c b/src/p25p2_frame.c index 5a9c7f2..f16a912 100644 --- a/src/p25p2_frame.c +++ b/src/p25p2_frame.c @@ -729,6 +729,15 @@ void process_ESS (dsd_opts * opts, dsd_state * state) state->group_tally++; } + //run a watchdog here so we can update this with the crypto variables and ENC LO + //may need to disable this for same reason as below + if (ttg != 0 && enc_wr == 0) + { + uint8_t slot = state->currentslot; //need to make sure we can verify the slot accuracy on SACCH slots (inverted) + sprintf (state->event_history_s[slot].Event_History_Items[0].internal_str, "Target: %d; has been locked out; Encryption Lock Out Enabled.", ttg); + watchdog_event_current(opts, state, slot); + } + //return to the control channel -- NOTE: Disabled, just mark as lockout for now, return would require complex check of the other slot activity // fprintf (stderr, " No Enc Following on P25p2 Trunking; Return to CC; \n"); // return_to_cc (opts, state);