mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-13 09:07:27 -05:00
Some radios set the encryption flag in the service options of the LDU1 Group Voice Channel User link control while transmitting clear voice; the HDU and LDU2 encryption sync parameters report ALGID 0x80 (unencrypted) for the same call. Example (CoMIRS Boston, TG 2217, valid LCs from several radios): HDU TALKGROUP:2217 UNENCRYPTED LDU1 GROUP VOICE CHANNEL USER FM:64008 TO:2217 SERVICE OPTIONS:PRI4 ENCRYPTED CIRCUIT LDU2 UNENCRYPTED P25P1DecoderState broadcast State.ENCRYPTED for each such LDU1 and State.CALL for each LDU2, so the channel state flapped between CALL and ENCRYPTED (and on upstream, where ENCRYPTED cannot change back to CALL, the call stays muted). Track the per-call encryption state from the HDU header and LDU2 algorithm ID (reset at TDU/TDULC). When it is known to be unencrypted, clear the encryption flag on the LC service options before using them for the channel state and traffic channel call event. Genuinely encrypted calls are unaffected, and when the algorithm ID is not yet known (late entry before the first LDU2) the LC service options are used as before. Adds VoiceServiceOptions.createUnencrypted(ServiceOptions) to copy service options with only the encryption flag cleared. Verified by driving P25P1DecoderState with HDU/LDU1/LDU2/TDU sequences reproducing the field logs: state events go from C C C E C E C to all CALL; encrypted calls (ALGID 0x84) still report ENCRYPTED throughout. Claude-Session: https://claude.ai/code/session_01FRdfTvgcdBvwkipdfP8qxy (cherry picked from commit 2ef3c9d02176871577d38f8afd0fa3c32fb92a58) Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -192,6 +192,14 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
private final P25TrafficChannelManager mTrafficChannelManager;
|
||||
private ServiceOptions mCurrentServiceOptions;
|
||||
|
||||
/**
|
||||
* Encryption state of the current call as signalled by the algorithm ID in the HDU header or LDU2 encryption sync
|
||||
* parameters (null when not yet known for this call). Some radios set the encryption flag in the service options of
|
||||
* the LDU1 voice channel user link control while transmitting clear voice (HDU and LDU2 report ALGID 0x80), so the
|
||||
* algorithm ID takes precedence over the link control service options when it is known.
|
||||
*/
|
||||
private Boolean mCallEncryptedByAlgorithm = null;
|
||||
|
||||
/**
|
||||
* Constructs an APCO-25 decoder state with an optional traffic channel manager.
|
||||
* @param channel with configuration details
|
||||
@@ -419,6 +427,12 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
if(lcw instanceof IServiceOptionsProvider sop)
|
||||
{
|
||||
serviceOptions = sop.getServiceOptions();
|
||||
|
||||
//Trust the HDU/LDU2 algorithm ID over the link control service options encryption flag when known.
|
||||
if(serviceOptions != null && serviceOptions.isEncrypted() && Boolean.FALSE.equals(mCallEncryptedByAlgorithm))
|
||||
{
|
||||
serviceOptions = VoiceServiceOptions.createUnencrypted(serviceOptions);
|
||||
}
|
||||
}
|
||||
else if(lcw.isEncrypted())
|
||||
{
|
||||
@@ -838,6 +852,7 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
|
||||
Identifier<?> radio = getIdentifierCollection().getFromIdentifier();
|
||||
|
||||
mCallEncryptedByAlgorithm = headerData.isEncryptedAudio();
|
||||
mTrafficChannelManager.processP1TrafficCallStart(getCurrentFrequency(), talkgroup, radio,
|
||||
headerData.getEncryptionKey(), mCurrentServiceOptions, getCurrentChannel(), message.getTimestamp());
|
||||
|
||||
@@ -880,6 +895,7 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
if(esp != null && esp.isValid())
|
||||
{
|
||||
getIdentifierCollection().update(esp.getIdentifiers());
|
||||
mCallEncryptedByAlgorithm = esp.isEncryptedAudio();
|
||||
|
||||
if(esp.isEncryptedAudio())
|
||||
{
|
||||
@@ -903,6 +919,7 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
*/
|
||||
private void processTDU(P25P1Message message)
|
||||
{
|
||||
mCallEncryptedByAlgorithm = null;
|
||||
mTrafficChannelManager.processP1TrafficCallEnd(getCurrentFrequency(), message.getTimestamp(), "TDU:" + message);
|
||||
broadcast(new DecoderStateEvent(this, Event.DECODE, State.ACTIVE));
|
||||
}
|
||||
@@ -921,6 +938,7 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList
|
||||
|
||||
if(lcw != null && lcw.isValid())
|
||||
{
|
||||
mCallEncryptedByAlgorithm = null;
|
||||
mTrafficChannelManager.processP1TrafficCallEnd(getCurrentFrequency(), message.getTimestamp(), "TDULC:" + message);
|
||||
broadcast(new DecoderStateEvent(this, Event.DECODE, State.ACTIVE));
|
||||
processLC(lcw, message.getTimestamp(), true);
|
||||
|
||||
@@ -80,4 +80,13 @@ public class VoiceServiceOptions extends ServiceOptions
|
||||
{
|
||||
return new VoiceServiceOptions(4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of the supplied service options with the encryption flag cleared and all other options unchanged.
|
||||
* @param serviceOptions to copy
|
||||
*/
|
||||
public static VoiceServiceOptions createUnencrypted(ServiceOptions serviceOptions)
|
||||
{
|
||||
return new VoiceServiceOptions(serviceOptions.mServiceOptions & ~ENCRYPTION_FLAG);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user