diff --git a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs
index 1c021b26..4113cee3 100644
--- a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs
+++ b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs
@@ -2154,6 +2154,12 @@ namespace IEC61850
OBJECT_UNDEFINED = 4
}
+ public enum ControlBlockAccessType
+ {
+ IEC61850_CB_ACCESS_TYPE_READ,
+ IEC61850_CB_ACCESS_TYPE_WRITE
+ }
+
public delegate CheckHandlerResult CheckHandler (ControlAction action, object parameter, MmsValue ctlVal, bool test, bool interlockCheck);
public static class SqliteLogStorage
@@ -2351,6 +2357,12 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
public static extern void IedServer_setListObjectsAccessHandler(IntPtr self, IedServer_ListObjectsAccessHandler handler, IntPtr parameter);
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void IedServer_setControlBlockAccessHandler(IntPtr self, IedServer_ControlBlockAccessHandler handler, IntPtr parameter);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate bool IedServer_ControlBlockAccessHandler(IntPtr parameter, IntPtr connection, int acsiClass, IntPtr ld, IntPtr ln, string objectName, string subObjectName, int accessType);
+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate bool IedServer_ListObjectsAccessHandler(IntPtr parameter, ClientConnection connection, ACSIClass acsiClass, LogicalDevice ld, LogicalNode ln, string objectName, string subObjectName, FunctionalConstraint fc);
@@ -2577,11 +2589,55 @@ namespace IEC61850
}
}
- public void SetListObjectsAccessHandler(IedServer_ListObjectsAccessHandler handler, System.IntPtr parameter)
+ public void SetListObjectsAccessHandler(IedServer_ListObjectsAccessHandler handler, IntPtr parameter)
{
IedServer_setListObjectsAccessHandler(self, handler, parameter);
}
+ public delegate bool ControlBlockAccessHandler(object parameter, ClientConnection connection, ACSIClass acsiClass, LogicalDevice ld, LogicalNode ln, string objectName, string subObjectName, ControlBlockAccessType accessType);
+
+ private ControlBlockAccessHandler rcbControlHandler = null;
+
+ private object rcbControlHandlerParameter = null;
+
+ private IedServer_ControlBlockAccessHandler internalRCBControlHandler = null;
+
+ private bool InternalRCBControlHandlerImplementation(IntPtr parameter, IntPtr connection, int acsiClass, IntPtr ld, IntPtr ln, string objectName, string subObjectName, int accessType)
+ {
+ if (rcbControlHandler != null && connection != IntPtr.Zero && ld != IntPtr.Zero && ln != IntPtr.Zero)
+ {
+ ClientConnection con = null;
+
+ this.clientConnections.TryGetValue(connection, out con);
+
+ ModelNode ldModelNode = iedModel.GetModelNodeFromNodeRef(ld);
+ ModelNode lnModelNode = iedModel.GetModelNodeFromNodeRef(ln);
+ return rcbControlHandler(rcbControlHandlerParameter, con, (ACSIClass)acsiClass, ldModelNode as LogicalDevice, lnModelNode as LogicalNode, objectName, subObjectName, (ControlBlockAccessType)accessType);
+ }
+
+ return false;
+
+ }
+
+
+ ///
+ /// Set a handler to control read and write access to control blocks and logs
+ ///
+ /// the callback handler to be used
+ /// a user provided parameter that is passed to the handler
+ public void SetControlBlockAccessHandler(ControlBlockAccessHandler handler, object parameter)
+ {
+ rcbControlHandler = handler;
+ rcbControlHandlerParameter = parameter;
+
+ if (internalRCBControlHandler == null)
+ {
+ internalRCBControlHandler = new IedServer_ControlBlockAccessHandler(InternalRCBControlHandlerImplementation);
+
+ IedServer_setControlBlockAccessHandler(self, internalRCBControlHandler, IntPtr.Zero);
+ }
+ }
+
private Dictionary writeAccessHandlers = new Dictionary ();
private void ConnectionIndicationHandlerImpl (IntPtr iedServer, IntPtr clientConnection, bool connected, IntPtr parameter)
diff --git a/dotnet/dotnet.sln b/dotnet/dotnet.sln
index 359ede93..06679868 100644
--- a/dotnet/dotnet.sln
+++ b/dotnet/dotnet.sln
@@ -3,54 +3,56 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.10.35004.147
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IEC61850.NET", "IEC61850forCSharp\IEC61850.NET.csproj", "{C35D624E-5506-4560-8074-1728F1FA1A4D}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IEC61850.NET", "IEC61850forCSharp\IEC61850.NET.csproj", "{C35D624E-5506-4560-8074-1728F1FA1A4D}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example1", "example1\example1.csproj", "{C616A6DF-831E-443C-9310-3F343A6E3D1A}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "example1", "example1\example1.csproj", "{C616A6DF-831E-443C-9310-3F343A6E3D1A}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "model_browsing", "model_browsing\model_browsing.csproj", "{59B85486-F48D-4978-BD35-8F5C3A8288D4}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "model_browsing", "model_browsing\model_browsing.csproj", "{59B85486-F48D-4978-BD35-8F5C3A8288D4}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "datasets", "datasets\datasets.csproj", "{D5C7DD38-032A-49B6-B74F-FFD9724A8AE4}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "datasets", "datasets\datasets.csproj", "{D5C7DD38-032A-49B6-B74F-FFD9724A8AE4}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "control", "control\control.csproj", "{C351CFA4-E54E-49A1-86CE-69643535541A}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "control", "control\control.csproj", "{C351CFA4-E54E-49A1-86CE-69643535541A}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "reporting", "reporting\reporting.csproj", "{9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "reporting", "reporting\reporting.csproj", "{9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example2", "example2\example2.csproj", "{2A226B6D-1D1F-4BFE-B8CC-158116F71270}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "example2", "example2\example2.csproj", "{2A226B6D-1D1F-4BFE-B8CC-158116F71270}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "authenticate", "authenticate\authenticate.csproj", "{0BECEC77-2315-4B95-AFF9-E6007E644BBF}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "authenticate", "authenticate\authenticate.csproj", "{0BECEC77-2315-4B95-AFF9-E6007E644BBF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tests", "tests\tests.csproj", "{FBDFE530-DBEB-474B-BA54-9AB287DD57B3}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "files", "files\files.csproj", "{77127456-19B9-4D1A-AEF9-40F8D1C5695E}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "files", "files\files.csproj", "{77127456-19B9-4D1A-AEF9-40F8D1C5695E}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example3", "example3\example3.csproj", "{5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "example3", "example3\example3.csproj", "{5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "report_new_dataset", "report_new_dataset\report_new_dataset.csproj", "{71485F99-2976-45E6-B73D-4946E594C15C}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "report_new_dataset", "report_new_dataset\report_new_dataset.csproj", "{71485F99-2976-45E6-B73D-4946E594C15C}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "log_client", "log_client\log_client.csproj", "{14C71267-2F38-460D-AA55-6803EE80AFB4}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "log_client", "log_client\log_client.csproj", "{14C71267-2F38-460D-AA55-6803EE80AFB4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{0D2F61F1-A173-44E7-BFB0-B698A1D44D12}"
ProjectSection(SolutionItems) = preProject
.nuget\packages.config = .nuget\packages.config
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "server1", "server1\server1.csproj", "{9286D2AB-96ED-4631-AB3C-ED20FF5D6E6C}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "server1", "server1\server1.csproj", "{9286D2AB-96ED-4631-AB3C-ED20FF5D6E6C}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tls_client_example", "tls_client_example\tls_client_example.csproj", "{6734BF52-2D0D-476B-8EA2-C9C2D1D69B03}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "tls_client_example", "tls_client_example\tls_client_example.csproj", "{6734BF52-2D0D-476B-8EA2-C9C2D1D69B03}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "goose_subscriber", "goose_subscriber\goose_subscriber.csproj", "{1285372C-2E62-494A-A661-8D5D3873318C}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "goose_subscriber", "goose_subscriber\goose_subscriber.csproj", "{1285372C-2E62-494A-A661-8D5D3873318C}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sv_subscriber", "sv_subscriber\sv_subscriber.csproj", "{44651D2D-3252-4FD5-8B8B-5552DBE1B499}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "sv_subscriber", "sv_subscriber\sv_subscriber.csproj", "{44651D2D-3252-4FD5-8B8B-5552DBE1B499}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tls_server_example", "tls_server_example\tls_server_example.csproj", "{B63F7A81-1D3A-4F2F-A7C2-D6F77E5BD307}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "tls_server_example", "tls_server_example\tls_server_example.csproj", "{B63F7A81-1D3A-4F2F-A7C2-D6F77E5BD307}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client_example_setting_groups", "client_example_setting_groups\client_example_setting_groups.csproj", "{0DA95476-B149-450B-AC36-01CEECFC1A43}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "client_example_setting_groups", "client_example_setting_groups\client_example_setting_groups.csproj", "{0DA95476-B149-450B-AC36-01CEECFC1A43}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client_example_async", "client_example_async\client_example_async.csproj", "{71902641-776A-47D8-9C0E-9ACBBEAC1370}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "client_example_async", "client_example_async\client_example_async.csproj", "{71902641-776A-47D8-9C0E-9ACBBEAC1370}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "server_goose_publisher", "server_goose_publisher\server_goose_publisher.csproj", "{C14BB883-86B8-401C-B3D6-B655F55F3298}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "server_goose_publisher", "server_goose_publisher\server_goose_publisher.csproj", "{C14BB883-86B8-401C-B3D6-B655F55F3298}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "log_server", "log_server\log_server.csproj", "{96124F40-D38E-499B-9968-674E0D32F933}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "log_server", "log_server\log_server.csproj", "{96124F40-D38E-499B-9968-674E0D32F933}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "server_example_access_control", "server_example_access_control\server_example_access_control.csproj", "{304D9146-1490-46EF-B771-20B0603084F5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -146,6 +148,10 @@ Global
{96124F40-D38E-499B-9968-674E0D32F933}.Debug|Any CPU.Build.0 = Debug|Any CPU
{96124F40-D38E-499B-9968-674E0D32F933}.Release|Any CPU.ActiveCfg = Release|Any CPU
{96124F40-D38E-499B-9968-674E0D32F933}.Release|Any CPU.Build.0 = Release|Any CPU
+ {304D9146-1490-46EF-B771-20B0603084F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {304D9146-1490-46EF-B771-20B0603084F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {304D9146-1490-46EF-B771-20B0603084F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {304D9146-1490-46EF-B771-20B0603084F5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/dotnet/server_example_access_control/Program.cs b/dotnet/server_example_access_control/Program.cs
new file mode 100644
index 00000000..b77c0cb2
--- /dev/null
+++ b/dotnet/server_example_access_control/Program.cs
@@ -0,0 +1,180 @@
+/*
+ * server_example_access_control.cs
+ *
+ * - How to use access control mechanisms
+ * - How to implement RBAC features based on access control mechanisms
+ */
+
+using System;
+using IEC61850.Server;
+using IEC61850.Common;
+using System.Threading;
+using System.Net;
+using static IEC61850.Server.IedServer;
+using System.Collections.Generic;
+
+namespace server_access_control
+{
+ class MainClass
+ {
+ public static void Main(string[] args)
+ {
+ bool running = true;
+
+ /* run until Ctrl-C is pressed */
+ Console.CancelKeyPress += delegate (object sender, ConsoleCancelEventArgs e)
+ {
+ e.Cancel = true;
+ running = false;
+ };
+
+ /* Create new server configuration object */
+ IedServerConfig config = new IedServerConfig();
+
+ /* Set buffer size for buffered report control blocks to 200000 bytes */
+ config.ReportBufferSize = 200000;
+
+ /* Set stack compliance to a specific edition of the standard (WARNING: data model has also to be checked for compliance) */
+ config.Edition = Iec61850Edition.EDITION_2;
+
+ /* Set the base path for the MMS file services */
+ config.FileServiceBasePath = "./vmd-filestore/";
+
+ /* disable MMS file service */
+ config.FileServiceEnabled = false;
+
+ /* enable dynamic data set service */
+ config.DynamicDataSetServiceEnabled = true;
+
+ /* disable log service */
+ config.LogServiceEnabled = false;
+
+ /* set maximum number of clients */
+ config.MaxMmsConnections = 2;
+
+ IedModel iedModel = ConfigFileParser.CreateModelFromConfigFile("model.cfg");
+
+ IedServer iedServer = new IedServer(iedModel, config);
+
+ iedServer.SetServerIdentity("libiec61850.com", "access control example", "1.0.0");
+
+ DataObject spcso1 = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/GGIO1.SPCSO1");
+
+ iedServer.SetControlHandler(spcso1, delegate (ControlAction action, object parameter, MmsValue value, bool test)
+ {
+ if (test)
+ return ControlHandlerResult.FAILED;
+
+ if (value.GetType() == MmsType.MMS_BOOLEAN)
+ {
+ Console.WriteLine("received binary control command: ");
+
+ if (value.GetBoolean())
+ Console.WriteLine("on\n");
+ else
+ Console.WriteLine("off\n");
+ }
+ else
+ return ControlHandlerResult.FAILED;
+
+ return ControlHandlerResult.OK;
+ }, spcso1);
+
+ void ConnectionCallBack(IedServer server, ClientConnection clientConnection, bool connected, object parameter)
+ {
+ if (connected)
+ Console.WriteLine("Connection opened\n");
+ else
+ Console.WriteLine("Connection closed\n");
+ }
+
+ var connectionCallBack = new ConnectionIndicationHandler(ConnectionCallBack);
+ iedServer.SetConnectionIndicationHandler(connectionCallBack, "127.0.0.1");
+
+
+ /* Install handler to log RCB events */
+
+ iedServer.SetRCBEventHandler(delegate (object parameter, ReportControlBlock rcb, ClientConnection con, RCBEventType eventType, string parameterName, MmsDataAccessError serviceError)
+ {
+ Console.WriteLine("RCB: " + rcb.Parent.GetObjectReference() + "." + rcb.Name + " event: " + eventType.ToString());
+
+ if (con != null)
+ {
+ Console.WriteLine(" caused by client " + con.GetPeerAddress());
+ }
+ else
+ {
+ Console.WriteLine(" client = null");
+ }
+
+ if ((eventType == RCBEventType.SET_PARAMETER) || (eventType == RCBEventType.GET_PARAMETER))
+ {
+ Console.WriteLine("RCB: "+rcb.Name + " event: "+ eventType .ToString()+ "\n");
+ Console.WriteLine(" param: "+ parameterName + "\n");
+ Console.WriteLine(" result: "+ serviceError.ToString() + "\n");
+ }
+
+ if (eventType == RCBEventType.ENABLED)
+ {
+ Console.WriteLine("RCB: "+ rcb.Name + " event: " + eventType.ToString() + "\n");
+ string rptId = rcb.RptID;
+ Console.WriteLine(" rptID: "+ rptId+"\n");
+ string dataSet =rcb.DataSet;
+ Console.WriteLine(" datSet:"+ dataSet+"\n");
+ }
+
+
+ }, null);
+
+ /* Install handler to control access to control blocks (RCBs, LCBs, GoCBs, SVCBs, SGCBs)*/
+ bool ControlBlockAccessCallBack(object parameter, ClientConnection connection, ACSIClass acsiClass, LogicalDevice ld, LogicalNode ln, string objectName, string subObjectName, ControlBlockAccessType accessType)
+ {
+ IedServer iedServer1 = parameter as IedServer;
+
+ Console.WriteLine(acsiClass.ToString() + " "+ accessType.ToString() + " access " + ld.GetName() + ln.GetName() +"/"+ objectName + "." + subObjectName);
+
+ if (objectName == "EventsIndexed03")
+ return false;
+
+
+ Console.WriteLine("Control block access callback");
+ return true;
+ }
+
+ iedServer.SetControlBlockAccessHandler(ControlBlockAccessCallBack, iedServer);
+
+ iedServer.Start(102);
+
+ if (iedServer.IsRunning())
+ {
+ Console.WriteLine("Server started");
+
+ GC.Collect();
+
+ DataObject ggio1AnIn1 = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/GGIO1.AnIn1");
+
+ DataAttribute ggio1AnIn1magF = (DataAttribute)ggio1AnIn1.GetChild("mag.f");
+ DataAttribute ggio1AnIn1T = (DataAttribute)ggio1AnIn1.GetChild("t");
+
+ float floatVal = 1.0f;
+
+ while (running)
+ {
+ floatVal += 1f;
+ iedServer.UpdateTimestampAttributeValue(ggio1AnIn1T, new Timestamp(DateTime.Now));
+ iedServer.UpdateFloatAttributeValue(ggio1AnIn1magF, floatVal);
+ Thread.Sleep(100);
+ }
+
+ iedServer.Stop();
+ Console.WriteLine("Server stopped");
+ }
+ else
+ {
+ Console.WriteLine("Failed to start server");
+ }
+
+ iedServer.Destroy();
+ }
+ }
+}
\ No newline at end of file
diff --git a/dotnet/server_example_access_control/model.cfg b/dotnet/server_example_access_control/model.cfg
new file mode 100644
index 00000000..3c8b17ae
--- /dev/null
+++ b/dotnet/server_example_access_control/model.cfg
@@ -0,0 +1,220 @@
+MODEL(simpleIO){
+LD(GenericIO){
+LN(LLN0){
+DO(Mod 0){
+DA(stVal 0 12 0 17 0)=1;
+DA(q 0 23 0 18 0);
+DA(t 0 22 0 16 0);
+DA(ctlModel 0 12 4 16 0)=0;
+}
+DO(Beh 0){
+DA(stVal 0 12 0 17 0)=1;
+DA(q 0 23 0 18 0);
+DA(t 0 22 0 16 0);
+}
+DO(Health 0){
+DA(stVal 0 12 0 17 0)=1;
+DA(q 0 23 0 18 0);
+DA(t 0 22 0 16 0);
+}
+DO(NamPlt 0){
+DA(vendor 0 20 5 16 0)="MZ Automation";
+DA(swRev 0 20 5 16 0)="1.3.0";
+DA(d 0 20 5 16 0)="libiec61850 server example";
+DA(configRev 0 20 5 16 0);
+DA(ldNs 0 20 11 16 0);
+}
+DS(Events){
+DE(GGIO1$ST$SPCSO1$stVal);
+DE(GGIO1$ST$SPCSO2$stVal);
+DE(GGIO1$ST$SPCSO3$stVal);
+DE(GGIO1$ST$SPCSO4$stVal);
+}
+DS(Events2){
+DE(GGIO1$ST$SPCSO1);
+DE(GGIO1$ST$SPCSO2);
+DE(GGIO1$ST$SPCSO3);
+DE(GGIO1$ST$SPCSO4);
+}
+DS(Measurements){
+DE(GGIO1$MX$AnIn1$mag$f);
+DE(GGIO1$MX$AnIn1$q);
+DE(GGIO1$MX$AnIn2$mag$f);
+DE(GGIO1$MX$AnIn2$q);
+DE(GGIO1$MX$AnIn3$mag$f);
+DE(GGIO1$MX$AnIn3$q);
+DE(GGIO1$MX$AnIn4$mag$f);
+DE(GGIO1$MX$AnIn4$q);
+}
+RC(EventsRCB01 Events1 0 Events 1 24 175 50 1000);
+RC(EventsRCBPreConf01 Events1 0 Events 1 24 175 50 1000);
+RC(EventsBRCB01 Events2 1 Events 1 24 175 50 1000);
+RC(EventsBRCBPreConf01 Events2 1 Events 1 24 175 50 1000);
+RC(EventsIndexed01 Events2 0 Events 1 24 175 50 1000);
+RC(EventsIndexed02 Events2 0 Events 1 24 175 50 1000);
+RC(EventsIndexed03 Events2 0 Events 1 24 175 50 1000);
+RC(Measurements01 Measurements 1 Measurements 1 16 239 50 1000);
+RC(Measurements02 Measurements 1 Measurements 1 16 239 50 1000);
+RC(Measurements03 Measurements 1 Measurements 1 16 239 50 1000);
+}
+LN(LPHD1){
+DO(PhyNam 0){
+DA(vendor 0 20 5 16 0);
+}
+DO(PhyHealth 0){
+DA(stVal 0 12 0 17 0)=1;
+DA(q 0 23 0 18 0);
+DA(t 0 22 0 16 0);
+}
+DO(Proxy 0){
+DA(stVal 0 0 0 17 0);
+DA(q 0 23 0 18 0);
+DA(t 0 22 0 16 0);
+}
+}
+LN(GGIO1){
+DO(Mod 0){
+DA(stVal 0 12 0 17 0)=1;
+DA(q 0 23 0 18 0);
+DA(t 0 22 0 16 0);
+DA(ctlModel 0 12 4 16 0)=0;
+}
+DO(Beh 0){
+DA(stVal 0 12 0 17 0)=1;
+DA(q 0 23 0 18 0);
+DA(t 0 22 0 16 0);
+}
+DO(Health 0){
+DA(stVal 0 12 0 17 0)=1;
+DA(q 0 23 0 18 0);
+DA(t 0 22 0 16 0);
+}
+DO(NamPlt 0){
+DA(vendor 0 20 5 16 0);
+DA(swRev 0 20 5 16 0);
+DA(d 0 20 5 16 0);
+}
+DO(AnIn1 0){
+DA(mag 0 27 1 17 0){
+DA(f 0 10 1 16 0);
+}
+DA(q 0 23 1 18 0);
+DA(t 0 22 1 16 0);
+}
+DO(AnIn2 0){
+DA(mag 0 27 1 17 0){
+DA(f 0 10 1 16 0);
+}
+DA(q 0 23 1 18 0);
+DA(t 0 22 1 16 0);
+}
+DO(AnIn3 0){
+DA(mag 0 27 1 17 0){
+DA(f 0 10 1 16 0);
+}
+DA(q 0 23 1 18 0);
+DA(t 0 22 1 16 0);
+}
+DO(AnIn4 0){
+DA(mag 0 27 1 17 0){
+DA(f 0 10 1 16 0);
+}
+DA(q 0 23 1 18 0);
+DA(t 0 22 1 16 0);
+}
+DO(SPCSO1 0){
+DA(origin 0 27 0 16 0){
+DA(orCat 0 12 0 16 0);
+DA(orIdent 0 13 0 16 0);
+}
+DA(ctlNum 0 6 0 16 0);
+DA(stVal 0 0 0 17 0);
+DA(q 0 23 0 18 0);
+DA(t 0 22 0 16 0);
+DA(ctlModel 0 12 4 16 0)=1;
+DA(Oper 0 27 12 16 0){
+DA(ctlVal 0 0 12 16 0);
+DA(origin 0 27 12 16 0){
+DA(orCat 0 12 12 16 0);
+DA(orIdent 0 13 12 16 0);
+}
+DA(ctlNum 0 6 12 16 0);
+DA(T 0 22 12 16 0);
+DA(Test 0 0 12 16 0);
+DA(Check 0 24 12 16 0);
+}
+}
+DO(SPCSO2 0){
+DA(stVal 0 0 0 17 0);
+DA(q 0 23 0 18 0);
+DA(Oper 0 27 12 16 0){
+DA(ctlVal 0 0 12 16 0);
+DA(origin 0 27 12 16 0){
+DA(orCat 0 12 12 16 0);
+DA(orIdent 0 13 12 16 0);
+}
+DA(ctlNum 0 6 12 16 0);
+DA(T 0 22 12 16 0);
+DA(Test 0 0 12 16 0);
+DA(Check 0 24 12 16 0);
+}
+DA(ctlModel 0 12 4 16 0)=1;
+DA(t 0 22 0 16 0);
+}
+DO(SPCSO3 0){
+DA(stVal 0 0 0 17 0);
+DA(q 0 23 0 18 0);
+DA(Oper 0 27 12 16 0){
+DA(ctlVal 0 0 12 16 0);
+DA(origin 0 27 12 16 0){
+DA(orCat 0 12 12 16 0);
+DA(orIdent 0 13 12 16 0);
+}
+DA(ctlNum 0 6 12 16 0);
+DA(T 0 22 12 16 0);
+DA(Test 0 0 12 16 0);
+DA(Check 0 24 12 16 0);
+}
+DA(ctlModel 0 12 4 16 0)=1;
+DA(t 0 22 0 16 0);
+}
+DO(SPCSO4 0){
+DA(stVal 0 0 0 17 0);
+DA(q 0 23 0 18 0);
+DA(Oper 0 27 12 16 0){
+DA(ctlVal 0 0 12 16 0);
+DA(origin 0 27 12 16 0){
+DA(orCat 0 12 12 16 0);
+DA(orIdent 0 13 12 16 0);
+}
+DA(ctlNum 0 6 12 16 0);
+DA(T 0 22 12 16 0);
+DA(Test 0 0 12 16 0);
+DA(Check 0 24 12 16 0);
+}
+DA(ctlModel 0 12 4 16 0)=1;
+DA(t 0 22 0 16 0);
+}
+DO(Ind1 0){
+DA(stVal 0 0 0 17 0);
+DA(q 0 23 0 18 0);
+DA(t 0 22 0 16 0);
+}
+DO(Ind2 0){
+DA(stVal 0 0 0 17 0);
+DA(q 0 23 0 18 0);
+DA(t 0 22 0 16 0);
+}
+DO(Ind3 0){
+DA(stVal 0 0 0 17 0);
+DA(q 0 23 0 18 0);
+DA(t 0 22 0 16 0);
+}
+DO(Ind4 0){
+DA(stVal 0 0 0 17 0);
+DA(q 0 23 0 18 0);
+DA(t 0 22 0 16 0);
+}
+}
+}
+}
diff --git a/dotnet/server_example_access_control/server_example_access_control.csproj b/dotnet/server_example_access_control/server_example_access_control.csproj
new file mode 100644
index 00000000..c34022ad
--- /dev/null
+++ b/dotnet/server_example_access_control/server_example_access_control.csproj
@@ -0,0 +1,24 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
+
+
+
+
diff --git a/examples/server_example_access_control/server_example_access_control.c b/examples/server_example_access_control/server_example_access_control.c
index 6b13ca7b..58554d09 100644
--- a/examples/server_example_access_control/server_example_access_control.c
+++ b/examples/server_example_access_control/server_example_access_control.c
@@ -114,6 +114,7 @@ controlBlockAccessHandler(void* parameter, ClientConnection connection, ACSIClas
{
printf("%s %s access %s/%s.%s.%s\n", ACSIClassToStr(acsiClass), accessType == IEC61850_CB_ACCESS_TYPE_WRITE ? "write" : "read", ld->name, ln->name, objectName, subObjectName);
+ return false;
/* allow only read access to LCBs */
if (acsiClass == ACSI_CLASS_LCB) {
if (accessType == IEC61850_CB_ACCESS_TYPE_READ)