diff --git a/Constants.cs b/Constants.cs
index 35ea341..e7e5252 100644
--- a/Constants.cs
+++ b/Constants.cs
@@ -66,7 +66,58 @@ namespace fnecore
} // public enum ConnectionState
///
- ///
+ /// Peer Connection NAK Messages
+ ///
+ public enum ConnectionMSTNAK
+ {
+ ///
+ /// General Failure
+ ///
+ GENERAL_FAILURE,
+
+ ///
+ /// Mode Not Enabled
+ ///
+ MODE_NOT_ENABLED,
+ ///
+ /// Illegal Packet
+ ///
+ ILLEGAL_PACKET,
+
+ ///
+ /// FNE Unauthorized
+ ///
+ FNE_UNAUTHORIZED,
+ ///
+ /// Bad Connection State
+ ///
+ BAD_CONN_STATE,
+ ///
+ /// Invalid Configuration Data
+ ///
+ INVALID_CONFIG_DATA,
+ ///
+ /// Peer Reset
+ ///
+ PEER_RESET,
+ ///
+ /// Peer ACL
+ ///
+ PEER_ACL,
+
+ ///
+ /// FNE Maximum Connections
+ ///
+ FNE_MAX_CONN,
+
+ ///
+ /// Invalid
+ ///
+ INVALID = 0xFFFF
+ } // public enum ConnectionMSTNAK
+
+ ///
+ /// Call Type
///
public enum CallType : byte
{
@@ -81,7 +132,7 @@ namespace fnecore
} // public enum CallType : byte
///
- ///
+ /// Frame Type
///
public enum FrameType : byte
{
@@ -105,7 +156,7 @@ namespace fnecore
} // public enum FrameType : byte
///
- ///
+ /// DVM State
///
public enum DVMState : byte
{
diff --git a/FneBase.cs b/FneBase.cs
index df3af49..cbd2629 100644
--- a/FneBase.cs
+++ b/FneBase.cs
@@ -163,11 +163,6 @@ namespace fnecore
///
public ConnectionState State;
- ///
- /// Flag indicating peer is "connected".
- ///
- public bool Connection;
-
///
/// Number of pings received.
///
diff --git a/FnePeer.cs b/FnePeer.cs
index 549e5af..0a60b09 100644
--- a/FnePeer.cs
+++ b/FnePeer.cs
@@ -27,6 +27,7 @@ using fnecore.DMR;
using fnecore.P25;
using fnecore.NXDN;
using fnecore.P25.KMM;
+using System.Net.NetworkInformation;
namespace fnecore
{
@@ -142,7 +143,7 @@ namespace fnecore
info = new PeerInformation();
info.PeerID = peerId;
- info.Connection = false;
+ info.State = ConnectionState.WAITING_LOGIN;
PingsAcked = 0;
}
@@ -557,8 +558,67 @@ namespace fnecore
{
if (this.peerId == peerId)
{
- info.Connection = false;
- Log(LogLevel.DEBUG, $"({systemName}) PEER {this.peerId} MSTNAK received");
+ // DVM 3.6 adds support to respond with a NAK reason, as such we just check if the NAK response is greater
+ // then 10 bytes and process the reason value
+ ConnectionMSTNAK reason = ConnectionMSTNAK.INVALID;
+ if (message.Length > 10)
+ {
+ reason = (ConnectionMSTNAK)FneUtils.ToUInt16(message, 10);
+ switch (reason)
+ {
+ case ConnectionMSTNAK.MODE_NOT_ENABLED:
+ Log(LogLevel.WARNING, $"({systemName}) PEER {this.peerId} master NAK; digital mode not enabled on FNE");
+ break;
+ case ConnectionMSTNAK.ILLEGAL_PACKET:
+ Log(LogLevel.WARNING, $"({systemName}) PEER {this.peerId} master NAK; illegal/unknown packet");
+ break;
+ case ConnectionMSTNAK.FNE_UNAUTHORIZED:
+ Log(LogLevel.WARNING, $"({systemName}) PEER {this.peerId} master NAK; unauthorized");
+ break;
+ case ConnectionMSTNAK.BAD_CONN_STATE:
+ Log(LogLevel.WARNING, $"({systemName}) PEER {this.peerId} master NAK; bad connection state");
+ break;
+ case ConnectionMSTNAK.INVALID_CONFIG_DATA:
+ Log(LogLevel.WARNING, $"({systemName}) PEER {this.peerId} master NAK; invalid configuration data");
+ break;
+ case ConnectionMSTNAK.FNE_MAX_CONN:
+ Log(LogLevel.WARNING, $"({systemName}) PEER {this.peerId} master NAK; FNE has reached maximum permitted connections");
+ break;
+ case ConnectionMSTNAK.PEER_RESET:
+ Log(LogLevel.WARNING, $"({systemName}) PEER {this.peerId} master NAK; FNE demanded connection reset");
+ break;
+ case ConnectionMSTNAK.PEER_ACL:
+ Log(LogLevel.ERROR, $"({systemName}) PEER {this.peerId} master NAK; ACL rejection, network disabled");
+ info.State = ConnectionState.WAITING_LOGIN;
+ Stop();
+ break;
+
+ case ConnectionMSTNAK.GENERAL_FAILURE:
+ default:
+ Log(LogLevel.WARNING, $"({systemName}) PEER {this.peerId} master NAK; general failure");
+ break;
+ }
+ }
+
+ if (info.State == ConnectionState.RUNNING && (reason == ConnectionMSTNAK.FNE_MAX_CONN))
+ {
+ Log(LogLevel.WARNING, $"({systemName}) PEER {this.peerId} master NAK; attemping to relogin");
+
+ // reset states
+ PingsSent = 0;
+ PingsAcked = 0;
+ info.State = ConnectionState.WAITING_LOGIN;
+ }
+ else
+ {
+ Log(LogLevel.ERROR, $"({systemName}) PEER {this.peerId} master NAK; network reconnect");
+
+ // reset states
+ PingsSent = 0;
+ PingsAcked = 0;
+ info.State = ConnectionState.WAITING_LOGIN;
+ return;
+ }
}
}
break;
@@ -664,7 +724,6 @@ namespace fnecore
else
{
info.State = ConnectionState.WAITING_LOGIN;
- info.Connection = false;
Log(LogLevel.ERROR, $"({systemName}) PEER {this.peerId} master ACK contained wrong ID - connection reset");
}
}
@@ -672,7 +731,6 @@ namespace fnecore
{
if (this.peerId == peerId)
{
- info.Connection = true;
info.State = ConnectionState.RUNNING;
Log(LogLevel.INFO, $"({systemName}) PEER {this.peerId} connection to MASTER completed");
@@ -682,7 +740,6 @@ namespace fnecore
else
{
info.State = ConnectionState.WAITING_LOGIN;
- info.Connection = false;
Log(LogLevel.ERROR, $"({systemName}) PEER {this.peerId} master ACK contained wrong ID - connection reset");
}
}
@@ -692,7 +749,7 @@ namespace fnecore
{
if (this.peerId == peerId)
{
- info.Connection = false;
+ info.State = ConnectionState.WAITING_LOGIN;
Log(LogLevel.DEBUG, $"({systemName}) PEER {this.peerId} MSTCL received");
// userland actions
@@ -740,6 +797,12 @@ namespace fnecore
catch (InvalidOperationException)
{
Log(LogLevel.ERROR, $"({systemName}) Not connected or lost connection to {masterEndpoint}; reconnecting...");
+
+ // reset states
+ PingsSent = 0;
+ PingsAcked = 0;
+ info.State = ConnectionState.WAITING_LOGIN;
+
client.Connect(masterEndpoint);
}
catch (SocketException se)
@@ -752,6 +815,12 @@ namespace fnecore
case SocketError.ConnectionAborted:
case SocketError.ConnectionRefused:
Log(LogLevel.ERROR, $"({systemName}) Not connected or lost connection to {masterEndpoint}; reconnecting...");
+
+ // reset states
+ PingsSent = 0;
+ PingsAcked = 0;
+ info.State = ConnectionState.WAITING_LOGIN;
+
client.Connect(masterEndpoint);
break;
default:
@@ -776,8 +845,9 @@ namespace fnecore
try
{
// if we're not connected, zero out the connection stats and send a login request to the master
- if (!info.Connection || info.State == ConnectionState.WAITING_LOGIN)
+ if (info.State == ConnectionState.WAITING_LOGIN)
{
+ // reset states
PingsSent = 0;
PingsAcked = 0;
info.State = ConnectionState.WAITING_LOGIN;
@@ -792,12 +862,13 @@ namespace fnecore
}
// if we are connected, sent a ping to the master and increment the counter
- if (info.Connection && info.State == ConnectionState.RUNNING)
+ if (info.State == ConnectionState.RUNNING)
{
if (PingsSent > (PingsAcked + MAX_MISSED_PEER_PINGS))
{
Log(LogLevel.WARNING, $"({systemName} Peer connection lost to {masterEndpoint}; reconnecting...");
+ // reset states
PingsSent = 0;
PingsAcked = 0;
info.State = ConnectionState.WAITING_LOGIN;
@@ -818,6 +889,12 @@ namespace fnecore
catch (InvalidOperationException)
{
Log(LogLevel.ERROR, $"({systemName}) Not connected or lost connection to {masterEndpoint}; reconnecting...");
+
+ // reset states
+ PingsSent = 0;
+ PingsAcked = 0;
+ info.State = ConnectionState.WAITING_LOGIN;
+
client.Connect(masterEndpoint);
}
catch (SocketException se)
@@ -830,6 +907,12 @@ namespace fnecore
case SocketError.ConnectionAborted:
case SocketError.ConnectionRefused:
Log(LogLevel.ERROR, $"({systemName}) Not connected or lost connection to {masterEndpoint}; reconnecting...");
+
+ // reset states
+ PingsSent = 0;
+ PingsAcked = 0;
+ info.State = ConnectionState.WAITING_LOGIN;
+
client.Connect(masterEndpoint);
break;
default: