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)