From dfe744ef13dd4191e9b3bfd62d129f1354ec99cb Mon Sep 17 00:00:00 2001 From: lwvmobile Date: Sat, 22 Feb 2025 09:04:07 -0500 Subject: [PATCH] DMR: Rework PDUs; --- include/dsd.h | 6 ++ src/dmr_block.c | 172 +++++++++++++++++++++++---------- src/dmr_pdu.c | 249 ++++++++++++++++++++++++++++++++++++++++++++++++ src/dsd_main.c | 4 + 4 files changed, 379 insertions(+), 52 deletions(-) diff --git a/include/dsd.h b/include/dsd.h index 3309f7f..b07be1d 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -661,6 +661,7 @@ typedef struct //new stuff below here uint8_t data_conf_data[2]; //flag for confirmed data blocks per slot + uint8_t data_block_poc[2]; //padding octets in the header (needed for Data PDU Decryption) uint8_t dmr_pdu_sf[2][24*128]; //unified pdu 'superframe' //[slot][byte] -- increased capacity to 127(+1) full rate blocks uint8_t cap_plus_csbk_bits[2][12*8*8]; //CSBK Cap+ FL initial and appended block bit storage, by slot uint8_t cap_plus_block_num[2]; //received block number storage -- per timeslot @@ -1285,7 +1286,12 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state); //dmr data header and multi block types (header, 1/2, 3/4, 1, Unified) void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t dheader_bits[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors); void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_bytes[], uint8_t block_len, uint8_t databurst, uint8_t type); + +//dmr pdu handling void dmr_pdu (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[]); +void dmr_ip_pdu (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t * DMR_PDU); +void dmr_sd_pdu (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t * DMR_PDU); +void dmr_udp_comp_pdu (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t * DMR_PDU); void dmr_reset_blocks (dsd_opts * opts, dsd_state * state); void dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[]); void dmr_locn (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[]); diff --git a/src/dmr_block.c b/src/dmr_block.c index c35f656..6a831a7 100644 --- a/src/dmr_block.c +++ b/src/dmr_block.c @@ -11,8 +11,7 @@ //hopefully a more simplified (or logical) version...once you get past all the variables void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t dheader_bits[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors) { - - int i; + uint8_t slot = state->currentslot; //clear out unified pdu 'superframe' slot @@ -68,6 +67,9 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t //store source for dmr pdu packet handling (lrrp) when not available in completed message if (dpf != 15) state->dmr_lrrp_source[slot] = source; + //store number of padding octets in a header to be used + if (dpf != 15) state->data_block_poc[slot] = poc; + //set dpf to storage for later use (UDT, SD, etc) state->data_header_format[slot] = dpf; @@ -132,8 +134,6 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t //p_head uint8_t p_sap = (uint8_t)ConvertBitIntoBytes(&dheader_bits[0], 4); uint8_t p_mfid = (uint8_t)ConvertBitIntoBytes(&dheader_bits[8], 8); - uint8_t p_pot = (uint8_t)ConvertBitIntoBytes(&dheader_bits[3], 5); //looking for LRRP pot_report - UNUSED(p_pot); fprintf (stderr, "%s ", KGRN); fprintf (stderr, "\n"); @@ -148,7 +148,8 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t else if (dpf == 3) fprintf (stderr, "Confirmed Delivery "); else if (dpf == 13) fprintf (stderr, "Short Data: Defined "); else if (dpf == 14) fprintf (stderr, "Short Data: Raw or S/P "); - else if (dpf == 15) fprintf (stderr, "Proprietary Packet Data"); + // else if (dpf == 15) fprintf (stderr, "Proprietary Packet Data"); + else if (dpf == 15) fprintf (stderr, "Extended"); // else fprintf (stderr, "Reserved/Unknown DPF %X ", dpf); if (a == 1 && dpf != 15) fprintf(stderr, "- Response Requested "); @@ -165,14 +166,14 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t else if (sap == 3) sprintf (sap_string, "%s", "UDP Comp"); //UDP/IP header compression else if (sap == 4) sprintf (sap_string, "%s", "IP Based"); //IP based Packet Data else if (sap == 5) sprintf (sap_string, "%s", "ARP Prot"); //Address Resoution Protocol (ARP) - else if (sap == 9) sprintf (sap_string, "%s", "Prop PDU"); //Proprietary Packet Data + else if (sap == 9) sprintf (sap_string, "%s", "EXTD HDR"); //Extended Header (Proprietary) else if (sap == 10) sprintf (sap_string, "%s", "Short DT"); //Short Data else sprintf (sap_string, "%s", "Reserved"); //reserved, or err/unk //mfid string handling if (dpf == 15) { - if (p_mfid == 0x10) sprintf (mfid_string, "%s", "Motorola"); + if (p_mfid == 0x10) sprintf (mfid_string, "%s", "Moto"); //could just also be a generic catch all for DMRA else if (p_mfid == 0x58) sprintf (mfid_string, "%s", "Tait"); else if (p_mfid == 0x68) sprintf (mfid_string, "%s", "Hytera"); else if (p_mfid == 0x08) sprintf (mfid_string, "%s", "Hytera"); @@ -313,44 +314,85 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t //Proprietary Data Header if (dpf == 15) { - fprintf (stderr, " - P_SAP %02d [%s] - MFID %02X [%s]", p_sap, sap_string, p_mfid, mfid_string); + //The SAP found here is the actual SAP of the message (like a P25 ndary SAP, and can chain together according to ETSI) + fprintf (stderr, " - SAP %02d [%s] - MFID %02X [%s]", p_sap, sap_string, p_mfid, mfid_string); - //p_sap 1 on mfid 10 (moto) is a pain, and doesn't assemble correctly for some reason - //two extra duplicate blocks are transmitted at the end for some reason -- system unique error? - if (p_sap != 1) + //p_sap 1 on mfid 10 (moto) is unknown, and the messages don't pass the CRC32 + //two extra duplicate blocks observed only happens on one sample, could have been radio or repeater errors? + // if (p_sap != 1) { //sanity check to prevent segfault (this happened when the regular header was not received beforehand) if (state->data_header_blocks[slot] > 1) state->data_header_blocks[slot]--; } - else + // else + // { + // //this method will just include the prop_pdu header as a data block and assemble the data blocks as a message, excluding duplicates + // int blocks = state->data_header_blocks[slot]-1; + // if (blocks > 127) blocks = 127; + // if (blocks < 1) blocks = 4; + // for(i = 0; i < 12; i++) + // state->dmr_pdu_sf[slot][i+(blocks*12)] = dheader[i]; + // state->data_block_counter[slot]++; + // } + + //Start Setting DMR Data Packet Encryption Variables + if (p_sap != 1 && p_mfid == 0x10) //p_sap 1 is reserved and doesn't seem to contain ENC header (may be extended address, or other signalling) { - //this method will assemble with the duplicate blocks and include the header as well - // state->data_header_blocks[slot]++; - // state->data_header_blocks[slot]++; - // int blocks = state->data_header_blocks[slot]-1; - // if (blocks > 127) blocks = 127; - // if (blocks < 1) blocks = 4; //safety value - // for(i = 0; i < 12; i++) - // state->dmr_pdu_sf[slot][i+(blocks*12)] = dheader[i]; - // state->data_block_counter[slot]++; + //check ENC bit, assuming this is an ENC bit, or SVC OPT like thing + if ((uint8_t)ConvertBitIntoBytes(&dheader_bits[20], 4) == 1) + { + //set to 0x100 so it won't trigger any weird flags, but still has a non-zero value to be checked later + if (state->currentslot == 0) state->dmr_so = 0x100; + else state->dmr_soR = 0x100; + } - //this method will just include the prop_pdu header as a data block and assemble the data blocks as a message, excluding duplicates - int blocks = state->data_header_blocks[slot]-1; - if (blocks > 127) blocks = 127; - if (blocks < 1) blocks = 4; - for(i = 0; i < 12; i++) - state->dmr_pdu_sf[slot][i+(blocks*12)] = dheader[i]; - state->data_block_counter[slot]++; + fprintf (stderr, "\n PDU ENC Header:"); + fprintf (stderr, " MFID: %02X;", (uint8_t)ConvertBitIntoBytes(&dheader_bits[8], 8)); + fprintf (stderr, " ENC: %X;", (uint8_t)ConvertBitIntoBytes(&dheader_bits[20], 4)); - //this method will NOT include the prop_pdu header as a data block and assemble the data blocks as a message, excluding duplicates - // state->data_header_blocks[slot]--; UNUSED(i); + if (state->currentslot == 0) + state->payload_keyid = (uint8_t)ConvertBitIntoBytes(&dheader_bits[24], 8); + else state->payload_keyidR = (uint8_t)ConvertBitIntoBytes(&dheader_bits[24], 8); + fprintf (stderr, " Key ID: %02X;", (uint8_t)ConvertBitIntoBytes(&dheader_bits[24], 8)); + + //this uses the same 3 bit method found in the 'late entry' alg + if (state->currentslot == 0) //could be 17,3 + state->payload_algid = (uint8_t)ConvertBitIntoBytes(&dheader_bits[17], 3); + else state->payload_algidR = (uint8_t)ConvertBitIntoBytes(&dheader_bits[17], 3); + fprintf (stderr, " ALG: %02X;", (uint8_t)ConvertBitIntoBytes(&dheader_bits[17], 3)); + if ((uint8_t)ConvertBitIntoBytes(&dheader_bits[17], 3) == 0) fprintf (stderr, " BP;"); + if ((uint8_t)ConvertBitIntoBytes(&dheader_bits[17], 3) == 1) fprintf (stderr, " RC4;"); + if ((uint8_t)ConvertBitIntoBytes(&dheader_bits[17], 3) == 2) fprintf (stderr, " DES56;"); + if ((uint8_t)ConvertBitIntoBytes(&dheader_bits[17], 3) == 3) fprintf (stderr, " AES128;"); + if ((uint8_t)ConvertBitIntoBytes(&dheader_bits[17], 3) == 4) fprintf (stderr, " AES256;"); + + if (state->currentslot == 0) + state->payload_mi = (uint32_t)ConvertBitIntoBytes(&dheader_bits[48], 32); + else state->payload_miR = (uint32_t)ConvertBitIntoBytes(&dheader_bits[48], 32); + + //print MI only if this is not Moto BP (no MI on those) + if ((uint32_t)ConvertBitIntoBytes(&dheader_bits[48], 32) != 0) + fprintf (stderr, " MI(32): %08X", (uint32_t)ConvertBitIntoBytes(&dheader_bits[48], 32)); - //no matter how you assemble this, with or without the p_head block(s) or extra blocks, there is ALWAYS a CRC32 Failure - //even when it continues to pass on other SAP values, SAP 1 must have a different checksum? - //Users trying to get this will want to enable -F to bypass the CRC32 failure } - + else //if (p_mfid == 0x10) + { + //I wonder if this is like the extended addressing header used on P25p1 + //(either way, the CRC32 will still fail, maybe its RAS or a MAC?) + /*Unknown Extended Header: 1F1002011127E70D20232018 + Slot 2 - Multi Block PDU Message CRC32 ERR + Slot 2 - Multi Block PDU Message + 1F1002011127E70D20232018 <--fails CRC32 with or without this attached + 41341F9AAECDE6554616A43C + 0E2A6335040C872A0009006C + 007356B370000000458AB84D <--very clearly 32 bits (4 bytes) after padding + */ //End Example + fprintf (stderr, "\n Unknown Extended Header: "); + for (uint8_t i = 2; i < 10; i++) + fprintf (stderr, "%02X", (uint8_t)ConvertBitIntoBytes(&dheader_bits[0+(i*8)], 8)); + } + //End Setting DMR Data Packet Encryption Variables } //block storage sanity @@ -361,24 +403,12 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t //set data header validity unless its a p_head (should be set prior, if received) if (dpf != 15) state->data_header_valid[slot] = 1; - //REMUS! Uncomment these lines if desired - if (dpf != 15 && dpf != 1) + // if (dpf != 15 && dpf != 1) { sprintf (state->dmr_lrrp_gps[slot], "Data Call - %s TGT: %d SRC: %d ", sap_string, target, source); if (a == 1) strcat (state->dmr_lrrp_gps[slot], "- RSP REQ "); } - //REMUS! Uncomment these lines if desired -- if the data request data header is missing, though, this may keep accumulating - // if (dpf == 1) - // { - // strcat (state->dmr_lrrp_gps[slot], "- RSP "); - // if (r_class == 0) strcat (state->dmr_lrrp_gps[slot], "ACK - RX OK"); - // if (r_class == 1) strcat (state->dmr_lrrp_gps[slot], "NACK - RX ERR"); - // if (r_class == 2) strcat (state->dmr_lrrp_gps[slot], "SACK - RETRY"); - - // } - //End REMUS Data string - //store SAP value state->data_header_sap[slot] = sap; @@ -767,9 +797,46 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte //individual CRC9s are correct on confirmed data blocks (but we can confirm now that they are all good) if (CRCComputed == CRCExtracted) CRCCorrect = 1; - //only run on good CRC or CRC/RAS bypass (aggressive_framesync == 0) - if (CRCCorrect || opts->aggressive_framesync == 0) - dmr_pdu (opts, state, block_len, state->dmr_pdu_sf[slot]); + //check for encryption on PDU + uint8_t enc_check = 0; + uint8_t decrypted_pdu = 1; + if (slot == 0 && state->dmr_so == 0x100) + { + enc_check = 1; + decrypted_pdu = 0; + } + else if (slot == 1 && state->dmr_soR == 0x100) + { + enc_check = 1; + decrypted_pdu = 0; + } + + //decode PDU + if (enc_check == 1 && decrypted_pdu == 0) //check for encryption and if it was decrypted first or not + { + fprintf (stderr, "%s", KRED); + fprintf (stderr, "\n Slot %d - Encrypted Data Packet;", slot+1); + fprintf (stderr, "%s", KNRM); + } + else if (CRCCorrect || opts->aggressive_framesync == 0) + { + //may need to make adjustments for various compressed headers for starting point, etc? + if (state->data_header_sap[slot] == 4) //IP based + { + uint16_t len = ((blocks+1)*block_len)-4; //total number of bytes in PDU minus 4 CRC32 bytes + dmr_ip_pdu (opts, state, len, state->dmr_pdu_sf[slot]); + } + else if (state->data_header_sap[slot] == 10) //short data, may also need to check for SD:D [DD_HEAD] + { + uint16_t len = ((blocks+1)*block_len)-4; //total number of bytes in PDU minus 4 CRC32 bytes + dmr_sd_pdu (opts, state, len, state->dmr_pdu_sf[slot]); + } + else if (state->data_header_sap[slot] == 2 || state->data_header_sap[slot] == 3) //TCP and UDP Compression (may only be 3 UDP compression, unknown) + { + uint16_t len = ((blocks+1)*block_len)-4; //total number of bytes in PDU minus 4 CRC32 bytes + dmr_udp_comp_pdu (opts, state, len, state->dmr_pdu_sf[slot]); + } + } if (CRCCorrect) ; //print nothing else @@ -792,7 +859,7 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte for (i = 0; i < ((blocks+1)*block_len); i++) { if ( (i != 0) && (i % 12 == 0) ) fprintf (stderr, "\n "); - fprintf (stderr, "[%02X]", state->dmr_pdu_sf[slot][i]); + fprintf (stderr, "%02X", state->dmr_pdu_sf[slot][i]); } //debug print @@ -973,7 +1040,7 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte fprintf (stderr, "\n Slot %d - Multi Block Control Message\n ", slot+1); for (i = 0; i < ((blocks+1)*block_len); i++) { - fprintf (stderr, "[%02X]", state->dmr_pdu_sf[slot][i]); + fprintf (stderr, "%02X", state->dmr_pdu_sf[slot][i]); if (i == 11 || i == 23 || i == 35 || i == 47 || i == 59 || i == 71 || i == 83 || i == 95) { fprintf (stderr, "\n "); @@ -1054,6 +1121,7 @@ void dmr_reset_blocks (dsd_opts * opts, dsd_state * state) memset (state->data_conf_data, 0, sizeof(state->data_conf_data)); memset (state->dmr_pdu_sf, 0, sizeof(state->dmr_pdu_sf)); memset (state->data_block_counter, 1, sizeof(state->data_block_counter)); + memset (state->data_block_poc, 0, sizeof(state->data_block_poc)); memset (state->data_header_blocks, 1, sizeof(state->data_header_blocks)); memset (state->data_block_crc_valid, 0, sizeof(state->data_block_crc_valid)); memset (state->dmr_lrrp_source, 0, sizeof(state->dmr_lrrp_source)); diff --git a/src/dmr_pdu.c b/src/dmr_pdu.c index f814027..31efcff 100644 --- a/src/dmr_pdu.c +++ b/src/dmr_pdu.c @@ -23,6 +23,255 @@ void dmr_pdu (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR } +void utf16_to_text (uint16_t len, uint8_t * input) +{ + len -= 36; //offset for starting point + 1 + fprintf (stderr, "\n UTF16 Text: "); + uint16_t ch16 = 0; + for (uint16_t i = 0; i < len; i += 2) + { + ch16 = (uint16_t)input[i+0]; + ch16 <<= 8; + ch16 |= (uint16_t)input[i+1]; + // fprintf (stderr, " %04X; ", ch16); //debug for raw values to check grouping for offset + + if (ch16 >= 0x20) //if not a linebreak or terminal commmands + fprintf (stderr, "%lc", ch16); + else if (ch16 == 0) //if padding (0 could also indicate end of text terminator?) + fprintf (stderr, "_"); + else fprintf (stderr, "-"); + } +} + +void utf8_to_text (uint16_t len, uint8_t * input) +{ + len -= 24; + fprintf (stderr, "\n UTF8 Text: "); + for (uint16_t i = 0; i < len; i++) + { + if (input[i] >= 0x20 && input[i] < 0x80) //if not a linebreak or terminal commmands + fprintf (stderr, "%c", input[i]); + else if (input[i] == 0) //if padding (0 could also indicate end of text terminator?) + fprintf (stderr, "_"); + else if (input[i] == 0x03) //ASCII end of text (observed on the NMEA LOCN ones anyways) + break; + else fprintf (stderr, "-"); + } +} + +void dmr_sd_pdu (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t * DMR_PDU) +{ + + // if (DMR_PDU[0] == 0x01) //may not be needed now, unknown + { + utf8_to_text(len, DMR_PDU+23); + dmr_locn(opts, state, len, DMR_PDU); //may need to figure out the actual len of each block? + } + +} + +//reading ETSI, seems like these aren't compressed, just that they are preset indexed values on the radio +void dmr_udp_comp_pdu (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t * DMR_PDU) +{ + UNUSED(opts); UNUSED(state); + uint16_t ipid = (DMR_PDU[0] << 8) | DMR_PDU[1]; + uint16_t said = (DMR_PDU[2] >> 4) & 0xF; + uint16_t daid = (DMR_PDU[2] >> 0) & 0xF; + + //the manual shows this is the lsb and msb of the header compression 'opcode', but only zero is defined + uint8_t op1 = (DMR_PDU[3] >> 7) & 1; + uint8_t op2 = (DMR_PDU[4] >> 7) & 1; + uint8_t opcode = (op1 << 1) | op2; + + uint8_t spid = (DMR_PDU[3] >> 0) & 0x7F; + uint8_t dpid = (DMR_PDU[4] >> 0) & 0x7F; + + //configure SAID / DAID string + char addrstring[2][35]; memset(addrstring, 0, sizeof(addrstring)); + + //said + if (said == 0) + sprintf (addrstring[0], "%s", "Radio Network"); + else if (said == 1) + sprintf (addrstring[0], "%s", "Ethernet"); + else if (said > 1 && said < 11) + sprintf (addrstring[0], "%s", "Reserved"); + else + sprintf (addrstring[0], "%s", "Manufacturer Specific"); + + //daid + if (daid == 0) + sprintf (addrstring[1], "%s", "Radio Network"); + else if (daid == 1) + sprintf (addrstring[1], "%s", "Ethernet"); + else if (daid == 1) + sprintf (addrstring[1], "%s", "Group Network"); + else if (daid > 2 && daid < 11) + sprintf (addrstring[1], "%s", "Reserved"); + else + sprintf (addrstring[1], "%s", "Manufacturer Specific"); + + //according to ETSI, if spid and/or dpid is zero, their respective port is defined in this header, otherwise, they are preset indexed values + + //look for and set optional port values and the ptr value to start of data + uint16_t ptr = 5; + + if (spid == 0 && dpid == 0) + { + spid = (DMR_PDU[5] << 8) | DMR_PDU[6]; + dpid = (DMR_PDU[7] << 8) | DMR_PDU[8]; + ptr = 9; + } + else if (spid == 0) + { + spid = (DMR_PDU[5] << 8) | DMR_PDU[6]; + ptr = 7; + } + else if (dpid == 0) + { + dpid = (DMR_PDU[5] << 8) | DMR_PDU[6]; + ptr = 7; + } + else ptr = 5; + + char portstring[2][35]; memset(portstring, 0, sizeof(portstring)); + + //spid + if (spid == 1) + { + // spid = 5016; + sprintf (portstring[0], "%s", "UTF-16BE Text Message"); + } + else if (spid == 2) + { + // spid = 5017; + sprintf (portstring[0], "%s", "Location Interface Protocol"); + } + else if (spid > 2 && spid < 191) + { + // spid = spid; + sprintf (portstring[0], "%s", "Reserved"); + } + else + { + // spid = spid; + sprintf (portstring[0], "%s", "Manufacturer Specific"); + } + + //dpid + if (dpid == 1) + { + // dpid = 5016; + sprintf (portstring[1], "%s", "UTF-16BE Text Message"); + } + else if (dpid == 2) + { + // dpid = 5017; + sprintf (portstring[1], "%s", "Location Interface Protocol"); + } + else if (dpid > 2 && dpid < 191) + { + // dpid = dpid; + sprintf (portstring[1], "%s", "Reserved"); + } + else + { + // dpid = dpid; + sprintf (portstring[1], "%s", "Manufacturer Specific"); + } + + fprintf (stderr, "\n Compressed IP Idx: %d; Opcode: %d; Src Idx: %d (%s); Dst Idx: %d (%s); ", ipid, opcode, said, addrstring[0], daid, addrstring[1]); + fprintf (stderr, "\n Src Port Idx: %d (%s); Dst Port Idx: %d (%s); ", spid, portstring[0], dpid, portstring[1]); + + //decode known types + if (spid == 1 || dpid == 1) + utf16_to_text(len, DMR_PDU+ptr); //assumming text starts right at the ptr value + else if (spid == 2 || dpid == 2) + { + //untested + uint8_t DMR_PDU_bits[127*8]; memset(DMR_PDU_bits, 0, sizeof(DMR_PDU_bits)); + unpack_byte_array_into_bit_array(DMR_PDU+ptr, DMR_PDU_bits, (len-4-ptr)*sizeof(uint8_t)); + lip_protocol_decoder(opts, state, DMR_PDU_bits); + } + else fprintf (stderr, "Unknown Decode Format;"); + +} + +void dmr_ip_pdu (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t * DMR_PDU) +{ + + UNUSED(opts); UNUSED(state); + // uint8_t slot = state->currentslot; + + //may need to look at sap value and determine the len of these addressing headers, etc + //and make a ptr to the start of actual PDU content data + // if (state->data_header_sap[slot] == 4) + // { + //adjust ptr, addressing type, etc + // } + + //take a look at the src, dst, and port indicated (assuming both ports will match) + uint32_t add1 = (DMR_PDU[13] << 16) | (DMR_PDU[14] << 8) | DMR_PDU[15]; //The 0C or 0D indicator will usually tell if this is src or dst + uint32_t add2 = (DMR_PDU[17] << 16) | (DMR_PDU[18] << 8) | DMR_PDU[19]; + uint16_t port1 = (DMR_PDU[20] << 8) | DMR_PDU[21]; + uint16_t port2 = (DMR_PDU[22] << 8) | DMR_PDU[23]; + fprintf (stderr, "\n %02X ADD1: %d; Port: %d; %02X ADD2: %d; Port: %d; Len: %d; ", DMR_PDU[12], add1, port1, DMR_PDU[16], add2, port2, len); + + //Are DMR PDU types only dictated by Port Number? Or is this just the defaults when programmed? + if (port1 == 231 && port2 == 231) + { + fprintf (stderr, "Cellocator;"); + } + else if (port1 == 4001 && port2 == 4001) + { + fprintf (stderr, "LRRP;"); + dmr_lrrp (opts, state, len, DMR_PDU); //will len just work here? (make adjustments if needed) + } + else if (port1 == 4004 && port2 == 4004) + { + fprintf (stderr, "XCMP;"); //may choose to use || instead of &&, saw a mismatch port but one was for XCMP + } + else if (port1 == 4005 && port2 == 4005) + { + fprintf (stderr, "ARS;"); + } + else if (port1 == 4007 && port2 == 4007) + { + fprintf (stderr, "TMS;"); + utf16_to_text(len, DMR_PDU+35); + } + else if (port1 == 4008 && port2 == 4008) + { + fprintf (stderr, "Telemetry;"); + } + else if (port1 == 4009 && port2 == 4009) + { + fprintf (stderr, "OTAP;"); + } + else if (port1 == 4012 && port2 == 4012) + { + fprintf (stderr, "Battery Management;"); + } + else if (port1 == 4013 && port2 == 4013) + { + fprintf (stderr, "Job Ticket Server;"); + } + //ETSI specific + else if (port1 == 5016 && port2 == 5016) + { + fprintf (stderr, "TMS;"); + utf16_to_text(len, DMR_PDU+35); + } + else if (port1 == 5017 && port2 == 5017) + { + uint8_t DMR_PDU_bits[127*8]; memset(DMR_PDU_bits, 0, sizeof(DMR_PDU_bits)); + unpack_byte_array_into_bit_array(DMR_PDU+35, DMR_PDU_bits, (len-4-35)*sizeof(uint8_t)); + lip_protocol_decoder(opts, state, DMR_PDU_bits); + } + else fprintf (stderr, "Unknown PDU Contents;"); + +} + //The contents of this function are mostly my reversed engineered efforts by observing DSDPlus output and matching data bytes //combined with a few external sources such as OK-DMR for some token values and extra data values (rad and alt) //this is by no means an extensive LRRP list and is prone to error (unless somebody has the manual or something) diff --git a/src/dsd_main.c b/src/dsd_main.c index a44cd92..6c9665c 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -365,6 +365,8 @@ noCarrier (dsd_opts * opts, dsd_state * state) state->data_block_counter[1] = 1; state->data_p_head[0] = 0; state->data_p_head[1] = 0; + state->data_block_poc[0] = 0; + state->data_block_poc[1] = 0; state->dmr_encL = 0; state->dmr_encR = 0; @@ -1034,6 +1036,8 @@ initState (dsd_state * state) state->data_block_counter[1] = 1; state->data_p_head[0] = 0; state->data_p_head[1] = 0; + state->data_block_poc[0] = 0; + state->data_block_poc[1] = 0; state->menuopen = 0; //is the ncurses menu open, if so, don't process frame sync