From e77bd15134ad8f3cfb1d5ee2c2b51789c9bbe4e8 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Fri, 24 Feb 2023 07:31:48 +0000 Subject: [PATCH 1/9] - added new callback function headers for dataset access (LIB61850-387) --- src/iec61850/inc/iec61850_server.h | 15 +++++++++++ src/mms/inc/mms_server.h | 23 ++++++++++++++++ src/mms/inc_private/mms_server_internal.h | 2 +- .../iso_mms/server/mms_named_variable_list.c | 27 +++++++++---------- 4 files changed, 51 insertions(+), 16 deletions(-) diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index e3790011..9d34084c 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -1841,6 +1841,21 @@ typedef MmsDataAccessError LIB61850_API void IedServer_setReadAccessHandler(IedServer self, ReadAccessHandler handler, void* parameter); + +typedef enum { + DATASET_CREATE, + DATASET_DELETE, + DATASET_READ, + DATASET_WRITE, + DATASET_GET_DIRECTORY +} IedServer_DataSetOperation; + +typedef bool +(*IedServer_DataSetAccessHandler) (void* parameter, ClientConnection connection, IedServer_DataSetOperation operation, const char* datasetRef); + +LIB61850_API void +IedServer_setDataSetAccessHandler(IedServer self, IedServer_DataSetAccessHandler handler, void* parameter); + /**@}*/ /**@}*/ diff --git a/src/mms/inc/mms_server.h b/src/mms/inc/mms_server.h index 98e4c796..2986d5b3 100644 --- a/src/mms/inc/mms_server.h +++ b/src/mms/inc/mms_server.h @@ -57,6 +57,29 @@ MmsServer_setLocalIpAddress(MmsServer self, const char* localIpAddress); LIB61850_INTERNAL bool MmsServer_isRunning(MmsServer self); +typedef enum { + MMS_VARLIST_CREATE, + MMS_VARLIST_DELETE, + MMS_VARLIST_READ, + MMS_VARLIST_WRITE, + MMS_VARLIST_GET_DIRECTORY +} MmsVariableListAccessType; + +/** + * \brief callback handler that is called for each named variable list access + * + * \param parameter a user provided parameter + * \param accessType the kind of access (create, delete, read, write, get directory) + * \param listType the type (scope) of the named variable list (either domain, association or VMD specific) + * \param domain the MMS domain the list is belonging to (is NULL for association or VMD specific lists!) + * \param listName the name + * \param connection client connection that is accessing the named variable list + * + * \return MMS_ERROR_NONE if the request is accepted, otherwise the MmsError value that has to be sent back to the client + */ +typedef MmsError (*MmsNamedVariableListAccessHandler)(void* parameter, MmsVariableListAccessType accessType, MmsVariableListType listType, MmsDomain* domain, + char* listName, MmsServerConnection connection); + /** * \brief callback handler that is called whenever a named variable list changes * diff --git a/src/mms/inc_private/mms_server_internal.h b/src/mms/inc_private/mms_server_internal.h index 727e97a3..bbf5195f 100644 --- a/src/mms/inc_private/mms_server_internal.h +++ b/src/mms/inc_private/mms_server_internal.h @@ -123,7 +123,7 @@ struct sMmsServer { MmsConnectionHandler connectionHandler; void* connectionHandlerParameter; - MmsNamedVariableListChangedHandler variableListChangedHandler; /* TODO this is only required if dynamic data sets are supported! */ + MmsNamedVariableListChangedHandler variableListChangedHandler; void* variableListChangedHandlerParameter; AcseAuthenticator authenticator; diff --git a/src/mms/iso_mms/server/mms_named_variable_list.c b/src/mms/iso_mms/server/mms_named_variable_list.c index 31694780..3c5ea5c3 100644 --- a/src/mms/iso_mms/server/mms_named_variable_list.c +++ b/src/mms/iso_mms/server/mms_named_variable_list.c @@ -3,22 +3,22 @@ * * Copyright 2013 Michael Zillgith * - * This file is part of libIEC61850. + * This file is part of libIEC61850. * - * libIEC61850 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * libIEC61850 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with libIEC61850. If not, see . + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . * - * See COPYING file for the complete license text. + * See COPYING file for the complete license text. */ #include "libiec61850_platform_includes.h" @@ -51,7 +51,6 @@ MmsNamedVariableListEntry_destroy(MmsNamedVariableListEntry self) GLOBAL_FREEMEM(self); } - MmsDomain* MmsNamedVariableListEntry_getDomain(MmsNamedVariableListEntry self) { @@ -120,5 +119,3 @@ MmsNamedVariableList_destroy(MmsNamedVariableList self) GLOBAL_FREEMEM(self->name); GLOBAL_FREEMEM(self); } - - From 39a55f672cb056167a4ffd9a30e13e11283ca2e0 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Fri, 24 Feb 2023 19:15:48 +0000 Subject: [PATCH 2/9] - MMS server: replaced MmsNamedVariableListChangedHandler by more generic MmsNamedVariableListAccessHandler (LIB61850-387) - MMS server: implemented dataset access handler callback in dataset read access (LIB61850-387) --- src/iec61850/server/mms_mapping/mms_mapping.c | 35 ++++++++--- src/mms/inc/mms_server.h | 19 +----- src/mms/inc_private/mms_server_internal.h | 6 +- .../server/mms_named_variable_list_service.c | 24 +++---- src/mms/iso_mms/server/mms_read_service.c | 63 ++++++++++++++----- src/mms/iso_mms/server/mms_server.c | 6 +- 6 files changed, 96 insertions(+), 57 deletions(-) diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index fc080ea2..4d6d8b31 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -1,7 +1,7 @@ /* * mms_mapping.c * - * Copyright 2013-2022 Michael Zillgith + * Copyright 2013-2023 Michael Zillgith * * This file is part of libIEC61850. * @@ -3379,7 +3379,7 @@ mmsReadAccessHandler (void* parameter, MmsDomain* domain, char* variableId, MmsS } static MmsError -variableListChangedHandler (void* parameter, bool create, MmsVariableListType listType, MmsDomain* domain, +variableListAccessHandler (void* parameter, MmsVariableListAccessType accessType, MmsVariableListType listType, MmsDomain* domain, char* listName, MmsServerConnection connection) { MmsError allow = MMS_ERROR_NONE; @@ -3389,10 +3389,16 @@ variableListChangedHandler (void* parameter, bool create, MmsVariableListType li /* TODO add log message */ #if (DEBUG_IED_SERVER == 1) - if (create) + if (accessType == MMS_VARLIST_CREATE) printf("IED_SERVER: create data set "); - else + else if (accessType == MMS_VARLIST_DELETE) printf("IED_SERVER: delete data set "); + else if (accessType == MMS_VARLIST_READ) + printf("IED_SERVER: read data set "); + else if (accessType == MMS_VARLIST_WRITE) + printf("IED_SERVER: write data set "); + else if (accessType == MMS_VARLIST_READ) + printf("IED_SERVER: get directory of data set "); switch (listType) { case MMS_VMD_SPECIFIC: @@ -3411,7 +3417,10 @@ variableListChangedHandler (void* parameter, bool create, MmsVariableListType li MmsMapping* self = (MmsMapping*) parameter; - if (create) { + if (accessType == MMS_VARLIST_CREATE) { + + //TODO call user callback hander (IedServer_DataSetAccessHandler) + if (listType == MMS_DOMAIN_SPECIFIC) { /* check if LN exists - otherwise reject request (to fulfill test case sDsN1c) */ @@ -3441,7 +3450,10 @@ variableListChangedHandler (void* parameter, bool create, MmsVariableListType li } } - else { + else if (accessType == MMS_VARLIST_DELETE) { + + //TODO call user callback hander (IedServer_DataSetAccessHandler) + /* Check if data set is referenced in a report */ LinkedList rcElement = self->reportControls; @@ -3519,6 +3531,15 @@ variableListChangedHandler (void* parameter, bool create, MmsVariableListType li #endif /* (CONFIG_IEC61850_LOG_SERVICE == 1) */ } + else if (accessType == MMS_VARLIST_READ) { + //TODO call user callback hander (IedServer_DataSetAccessHandler) + } + else if (accessType == MMS_VARLIST_WRITE) { + //TODO call user callback hander (IedServer_DataSetAccessHandler) + } + else if (accessType == MMS_VARLIST_GET_DIRECTORY) { + //TODO call user callback hander (IedServer_DataSetAccessHandler) + } return allow; } @@ -3530,7 +3551,7 @@ MmsMapping_installHandlers(MmsMapping* self) MmsServer_installWriteHandler(self->mmsServer, mmsWriteHandler, (void*) self); MmsServer_installReadAccessHandler(self->mmsServer, mmsReadAccessHandler, (void*) self); MmsServer_installConnectionHandler(self->mmsServer, mmsConnectionHandler, (void*) self); - MmsServer_installVariableListChangedHandler(self->mmsServer, variableListChangedHandler, (void*) self); + MmsServer_installVariableListAccessHandler(self->mmsServer, variableListAccessHandler, (void*) self); } void diff --git a/src/mms/inc/mms_server.h b/src/mms/inc/mms_server.h index 2986d5b3..b9c22417 100644 --- a/src/mms/inc/mms_server.h +++ b/src/mms/inc/mms_server.h @@ -81,29 +81,14 @@ typedef MmsError (*MmsNamedVariableListAccessHandler)(void* parameter, MmsVariab char* listName, MmsServerConnection connection); /** - * \brief callback handler that is called whenever a named variable list changes - * - * \param parameter a user provided parameter - * \param create if true the the request if a request to create a new variable list, false is a delete request - * \param listType the type (scope) of the named variable list (either domain, association or VMD specific) - * \param domain the MMS domain the list is belonging to (is NULL for association or VMD specific lists!) - * \param listName the name - * \param connection client connection that requests the creation of deletion of the variable list - * - * \return MMS_ERROR_NONE if the request is accepted, otherwise the MmsError value that has to be sent back to the client - */ -typedef MmsError (*MmsNamedVariableListChangedHandler)(void* parameter, bool create, MmsVariableListType listType, MmsDomain* domain, - char* listName, MmsServerConnection connection); - -/** - * \brief Install callback handler that is called when a named variable list changes (is created or deleted) + * \brief Install callback handler that is called when a named variable list is accessed by a client * * \param self the MmsServer instance to operate on * \param handler the callback handler function * \param parameter user provided parameter that is passed to the callback handler */ LIB61850_INTERNAL void -MmsServer_installVariableListChangedHandler(MmsServer self, MmsNamedVariableListChangedHandler handler, void* parameter); +MmsServer_installVariableListAccessHandler(MmsServer self, MmsNamedVariableListAccessHandler handler, void* parameter); /** * \brief ObtainFile service callback handler diff --git a/src/mms/inc_private/mms_server_internal.h b/src/mms/inc_private/mms_server_internal.h index bbf5195f..fc875597 100644 --- a/src/mms/inc_private/mms_server_internal.h +++ b/src/mms/inc_private/mms_server_internal.h @@ -123,8 +123,8 @@ struct sMmsServer { MmsConnectionHandler connectionHandler; void* connectionHandlerParameter; - MmsNamedVariableListChangedHandler variableListChangedHandler; - void* variableListChangedHandlerParameter; + MmsNamedVariableListAccessHandler variableListAccessHandler; + void* variableListAccessHandlerParameter; AcseAuthenticator authenticator; void* authenticatorParameter; @@ -421,7 +421,7 @@ mmsServer_createMmsWriteResponse(MmsServerConnection connection, uint32_t invokeId, ByteBuffer* response, int numberOfItems, MmsDataAccessError* accessResults); LIB61850_INTERNAL MmsError -mmsServer_callVariableListChangedHandler(bool create, MmsVariableListType listType, MmsDomain* domain, +mmsServer_callVariableListChangedHandler(MmsVariableListAccessType accessType, MmsVariableListType listType, MmsDomain* domain, char* listName, MmsServerConnection connection); #endif /* MMS_SERVER_INTERNAL_H_ */ diff --git a/src/mms/iso_mms/server/mms_named_variable_list_service.c b/src/mms/iso_mms/server/mms_named_variable_list_service.c index 3a27061c..4baf4ab3 100644 --- a/src/mms/iso_mms/server/mms_named_variable_list_service.c +++ b/src/mms/iso_mms/server/mms_named_variable_list_service.c @@ -1,7 +1,7 @@ /* * mms_named_variable_list_service.c * - * Copyright 2013-2020 Michael Zillgith + * Copyright 2013-2023 Michael Zillgith * * This file is part of libIEC61850. * @@ -49,17 +49,17 @@ #endif MmsError -mmsServer_callVariableListChangedHandler(bool create, MmsVariableListType listType, MmsDomain* domain, +mmsServer_callVariableListChangedHandler(MmsVariableListAccessType accessType, MmsVariableListType listType, MmsDomain* domain, char* listName, MmsServerConnection connection) { MmsServer self = connection->server; - if (self->variableListChangedHandler != NULL) { + if (self->variableListAccessHandler != NULL) { if (DEBUG_MMS_SERVER) - printf("MMS_SERVER: call MmsNamedVariableListChangedHandler for new list %s\n", listName); + printf("MMS_SERVER: call MmsNamedVariableListAccessHandler for new list %s\n", listName); - return self->variableListChangedHandler(self->variableListChangedHandlerParameter, - create, listType, domain, listName, connection); + return self->variableListAccessHandler(self->variableListAccessHandlerParameter, + accessType, listType, domain, listName, connection); } else return MMS_ERROR_NONE; @@ -180,7 +180,7 @@ mmsServer_handleDeleteNamedVariableListRequest(MmsServerConnection connection, if (MmsNamedVariableList_isDeletable(variableList)) { - MmsError deleteError = mmsServer_callVariableListChangedHandler(false, MMS_DOMAIN_SPECIFIC, domain, listName, connection); + MmsError deleteError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_DELETE, MMS_DOMAIN_SPECIFIC, domain, listName, connection); if (deleteError == MMS_ERROR_NONE) { MmsDomain_deleteNamedVariableList(domain, listName); @@ -203,7 +203,7 @@ mmsServer_handleDeleteNamedVariableListRequest(MmsServerConnection connection, if (variableList != NULL) { numberMatched++; - MmsError deleteError = mmsServer_callVariableListChangedHandler(false, MMS_ASSOCIATION_SPECIFIC, NULL, listName, connection); + MmsError deleteError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_DELETE, MMS_ASSOCIATION_SPECIFIC, NULL, listName, connection); if (deleteError == MMS_ERROR_NONE) { numberDeleted++; @@ -224,7 +224,7 @@ mmsServer_handleDeleteNamedVariableListRequest(MmsServerConnection connection, if (variableList != NULL) { numberMatched++; - MmsError deleteError = mmsServer_callVariableListChangedHandler(false, MMS_VMD_SPECIFIC, NULL, listName, connection); + MmsError deleteError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_DELETE, MMS_VMD_SPECIFIC, NULL, listName, connection); if (deleteError == MMS_ERROR_NONE) { numberDeleted++; @@ -526,7 +526,7 @@ mmsServer_handleDefineNamedVariableListRequest( if (namedVariableList != NULL) { - mmsError = mmsServer_callVariableListChangedHandler(true, MMS_DOMAIN_SPECIFIC, domain, variableListName, connection); + mmsError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_CREATE, MMS_DOMAIN_SPECIFIC, domain, variableListName, connection); if (mmsError == MMS_ERROR_NONE) { MmsDomain_addNamedVariableList(domain, namedVariableList); @@ -576,7 +576,7 @@ mmsServer_handleDefineNamedVariableListRequest( if (namedVariableList != NULL) { - if (mmsServer_callVariableListChangedHandler(true, MMS_ASSOCIATION_SPECIFIC, NULL, variableListName, connection) == MMS_ERROR_NONE) { + if (mmsServer_callVariableListChangedHandler(MMS_VARLIST_CREATE, MMS_ASSOCIATION_SPECIFIC, NULL, variableListName, connection) == MMS_ERROR_NONE) { MmsServerConnection_addNamedVariableList(connection, namedVariableList); createDefineNamedVariableListResponse(invokeId, response); } @@ -619,7 +619,7 @@ mmsServer_handleDefineNamedVariableListRequest( request, variableListName, &mmsError); if (namedVariableList != NULL) { - if (mmsServer_callVariableListChangedHandler(true, MMS_VMD_SPECIFIC, NULL, variableListName, connection) + if (mmsServer_callVariableListChangedHandler(MMS_VARLIST_CREATE, MMS_VMD_SPECIFIC, NULL, variableListName, connection) == MMS_ERROR_NONE) { LinkedList_add(vmdScopeNVLs, (void*) namedVariableList); diff --git a/src/mms/iso_mms/server/mms_read_service.c b/src/mms/iso_mms/server/mms_read_service.c index 2638bc0b..3193c699 100644 --- a/src/mms/iso_mms/server/mms_read_service.c +++ b/src/mms/iso_mms/server/mms_read_service.c @@ -768,9 +768,21 @@ handleReadNamedVariableListRequest( else { MmsNamedVariableList namedList = MmsDomain_getNamedVariableList(domain, nameIdStr); - if (namedList != NULL) { - createNamedVariableListResponse(connection, namedList, invokeId, response, isSpecWithResult(read), - &accessSpec); + if (namedList) + { + + MmsError accessError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_READ, MMS_DOMAIN_SPECIFIC, domain, namedList->name, connection); + + if (accessError == MMS_ERROR_NONE) { + createNamedVariableListResponse(connection, namedList, invokeId, response, isSpecWithResult(read), + &accessSpec); + } + else { + if (DEBUG_MMS_SERVER) printf("MMS read: named variable list %s access error: %i\n", nameIdStr, accessError); + + mmsMsg_createServiceErrorPdu(invokeId, response, accessError); + } + } else { if (DEBUG_MMS_SERVER) printf("MMS read: named variable list %s not found!\n", nameIdStr); @@ -791,14 +803,24 @@ handleReadNamedVariableListRequest( mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); else { - VarAccessSpec accessSpec; + MmsError accessError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_READ, MMS_VMD_SPECIFIC, NULL, namedList->name, connection); + + if (accessError == MMS_ERROR_NONE) { + VarAccessSpec accessSpec; - accessSpec.isNamedVariableList = true; - accessSpec.specific = 0; - accessSpec.domainId = NULL; - accessSpec.itemId = listName; + accessSpec.isNamedVariableList = true; + accessSpec.specific = 0; + accessSpec.domainId = NULL; + accessSpec.itemId = listName; + + createNamedVariableListResponse(connection, namedList, invokeId, response, isSpecWithResult(read), &accessSpec); + } + else { + if (DEBUG_MMS_SERVER) printf("MMS read: VMD specific named variable list %s access error: %i\n", listName, accessError); + + mmsMsg_createServiceErrorPdu(invokeId, response, accessError); + } - createNamedVariableListResponse(connection, namedList, invokeId, response, isSpecWithResult(read), &accessSpec); } } #if (MMS_DYNAMIC_DATA_SETS == 1) @@ -815,14 +837,25 @@ handleReadNamedVariableListRequest( if (namedList == NULL) mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); else { - VarAccessSpec accessSpec; - accessSpec.isNamedVariableList = true; - accessSpec.specific = 2; - accessSpec.domainId = NULL; - accessSpec.itemId = listName; + MmsError accessError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_READ, MMS_ASSOCIATION_SPECIFIC, NULL, namedList->name, connection); + + if (accessError == MMS_ERROR_NONE) { + + VarAccessSpec accessSpec; - createNamedVariableListResponse(connection, namedList, invokeId, response, isSpecWithResult(read), &accessSpec); + accessSpec.isNamedVariableList = true; + accessSpec.specific = 2; + accessSpec.domainId = NULL; + accessSpec.itemId = listName; + + createNamedVariableListResponse(connection, namedList, invokeId, response, isSpecWithResult(read), &accessSpec); + } + else { + if (DEBUG_MMS_SERVER) printf("MMS read: association specific named variable list %s access error: %i\n", listName, accessError); + + mmsMsg_createServiceErrorPdu(invokeId, response, accessError); + } } } #endif /* (MMS_DYNAMIC_DATA_SETS == 1) */ diff --git a/src/mms/iso_mms/server/mms_server.c b/src/mms/iso_mms/server/mms_server.c index ed2cf725..e6cccfa5 100644 --- a/src/mms/iso_mms/server/mms_server.c +++ b/src/mms/iso_mms/server/mms_server.c @@ -359,10 +359,10 @@ MmsServer_installConnectionHandler(MmsServer self, MmsConnectionHandler connecti } void -MmsServer_installVariableListChangedHandler(MmsServer self, MmsNamedVariableListChangedHandler handler, void* parameter) +MmsServer_installVariableListAccessHandler(MmsServer self, MmsNamedVariableListAccessHandler handler, void* parameter) { - self->variableListChangedHandler = handler; - self->variableListChangedHandlerParameter = parameter; + self->variableListAccessHandler = handler; + self->variableListAccessHandlerParameter = parameter; } void From acfbe16452256d04472c4429ef28f456d094cb2f Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Mon, 27 Feb 2023 16:55:03 +0000 Subject: [PATCH 3/9] - IED server/MMS server: added data set access callbacks and example (LIB61850-387) --- examples/CMakeLists.txt | 1 + .../CMakeLists.txt | 21 + .../server_example_access_control/Makefile | 32 + .../server_example_access_control.c | 243 ++ .../static_model.c | 2223 +++++++++++++++++ .../static_model.h | 311 +++ .../inc_private/mms_mapping_internal.h | 3 + src/iec61850/server/impl/ied_server.c | 7 + src/iec61850/server/mms_mapping/mms_mapping.c | 193 +- src/mms/inc/iso_connection_parameters.h | 6 +- .../server/mms_named_variable_list_service.c | 767 +++--- src/mms/iso_mms/server/mms_write_service.c | 47 +- 12 files changed, 3410 insertions(+), 444 deletions(-) create mode 100644 examples/server_example_access_control/CMakeLists.txt create mode 100644 examples/server_example_access_control/Makefile create mode 100644 examples/server_example_access_control/server_example_access_control.c create mode 100644 examples/server_example_access_control/static_model.c create mode 100644 examples/server_example_access_control/static_model.h diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index d787fb9b..899cd7b7 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -14,6 +14,7 @@ add_subdirectory(server_example_files) add_subdirectory(server_example_substitution) add_subdirectory(server_example_service_tracking) add_subdirectory(server_example_deadband) +add_subdirectory(server_example_access_control) add_subdirectory(iec61850_client_example1) add_subdirectory(iec61850_client_example2) diff --git a/examples/server_example_access_control/CMakeLists.txt b/examples/server_example_access_control/CMakeLists.txt new file mode 100644 index 00000000..a71a7383 --- /dev/null +++ b/examples/server_example_access_control/CMakeLists.txt @@ -0,0 +1,21 @@ +include_directories( + . +) + +set(server_example_SRCS + server_example_access_control.c + static_model.c +) + +IF(MSVC) +set_source_files_properties(${server_example_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(MSVC) + +add_executable(server_example_access_control + ${server_example_SRCS} +) + +target_link_libraries(server_example_access_control + iec61850 +) diff --git a/examples/server_example_access_control/Makefile b/examples/server_example_access_control/Makefile new file mode 100644 index 00000000..4b288a51 --- /dev/null +++ b/examples/server_example_access_control/Makefile @@ -0,0 +1,32 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = server_example_access_control +PROJECT_SOURCES = server_example_access_control.c +PROJECT_SOURCES += static_model.c + +PROJECT_ICD_FILE = simpleIO_direct_control.cid + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +LDLIBS += -lm + +CP = cp + +model: $(PROJECT_ICD_FILE) + java -jar $(LIBIEC_HOME)/tools/model_generator/genmodel.jar $(PROJECT_ICD_FILE) + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + mkdir -p vmd-filestore + $(CP) $(PROJECT_BINARY_NAME) vmd-filestore/IEDSERVER.BIN + +clean: + rm -f $(PROJECT_BINARY_NAME) + rm -f vmd-filestore/IEDSERVER.BIN + + diff --git a/examples/server_example_access_control/server_example_access_control.c b/examples/server_example_access_control/server_example_access_control.c new file mode 100644 index 00000000..024bf77a --- /dev/null +++ b/examples/server_example_access_control/server_example_access_control.c @@ -0,0 +1,243 @@ +/* + * server_example_access_control.c + * + * - How to use access control mechanisms + * - How to implement RBAC features based on access control mechanisms + */ + +#include "iec61850_server.h" +#include "hal_thread.h" +#include +#include +#include +#include + +#include "static_model.h" + +static int running = 0; +static IedServer iedServer = NULL; + +void +sigint_handler(int signalId) +{ + running = 0; +} + +static ControlHandlerResult +controlHandlerForBinaryOutput(ControlAction action, void* parameter, MmsValue* value, bool test) +{ + if (test) + return CONTROL_RESULT_FAILED; + + if (MmsValue_getType(value) == MMS_BOOLEAN) { + printf("received binary control command: "); + + if (MmsValue_getBoolean(value)) + printf("on\n"); + else + printf("off\n"); + } + else + return CONTROL_RESULT_FAILED; + + uint64_t timeStamp = Hal_getTimeInMs(); + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO1) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_t, timeStamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal, value); + } + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO2) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_t, timeStamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal, value); + } + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO3) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_t, timeStamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal, value); + } + + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO4) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_t, timeStamp); + IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal, value); + } + + return CONTROL_RESULT_OK; +} + + +static void +connectionHandler (IedServer self, ClientConnection connection, bool connected, void* parameter) +{ + if (connected) + printf("Connection opened\n"); + else + printf("Connection closed\n"); +} + +static void +rcbEventHandler(void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType event, const char* parameterName, MmsDataAccessError serviceError) +{ + printf("RCB: %s event: %i\n", ReportControlBlock_getName(rcb), event); + + if ((event == RCB_EVENT_SET_PARAMETER) || (event == RCB_EVENT_GET_PARAMETER)) { + printf(" param: %s\n", parameterName); + printf(" result: %i\n", serviceError); + } + + if (event == RCB_EVENT_ENABLE) { + char* rptId = ReportControlBlock_getRptID(rcb); + printf(" rptID: %s\n", rptId); + char* dataSet = ReportControlBlock_getDataSet(rcb); + printf(" datSet: %s\n", dataSet); + + free(rptId); + free(dataSet); + } +} + +static bool +dataSetAccessHandler(void* parameter, ClientConnection connection, IedServer_DataSetOperation operation, const char* datasetRef) +{ + printf("Data set access: %s operation: %i\n", datasetRef, operation); + + return true; +} + +int +main(int argc, char** argv) +{ + int tcpPort = 102; + + if (argc > 1) { + tcpPort = atoi(argv[1]); + } + + printf("Using libIEC61850 version %s\n", LibIEC61850_getVersionString()); + + /* Create new server configuration object */ + IedServerConfig config = IedServerConfig_create(); + + /* Set buffer size for buffered report control blocks to 200000 bytes */ + IedServerConfig_setReportBufferSize(config, 200000); + + /* Set stack compliance to a specific edition of the standard (WARNING: data model has also to be checked for compliance) */ + IedServerConfig_setEdition(config, IEC_61850_EDITION_2); + + /* Set the base path for the MMS file services */ + IedServerConfig_setFileServiceBasePath(config, "./vmd-filestore/"); + + /* disable MMS file service */ + IedServerConfig_enableFileService(config, false); + + /* enable dynamic data set service */ + IedServerConfig_enableDynamicDataSetService(config, true); + + /* disable log service */ + IedServerConfig_enableLogService(config, false); + + /* set maximum number of clients */ + IedServerConfig_setMaxMmsConnections(config, 2); + + /* Create a new IEC 61850 server instance */ + iedServer = IedServer_createWithConfig(&iedModel, NULL, config); + + /* configuration object is no longer required */ + IedServerConfig_destroy(config); + + /* set the identity values for MMS identify service */ + IedServer_setServerIdentity(iedServer, "libiec61850.com", "access control example", "1.0.0"); + + /* Install handler for operate command */ + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1, + (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO1); + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2, + (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO2); + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3, + (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO3); + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4, + (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO4); + + IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL); + + IedServer_setRCBEventHandler(iedServer, rcbEventHandler, NULL); + + /* By default access to variables with FC=DC and FC=CF is not allowed. + * This allow to write to simpleIOGenericIO/GGIO1.NamPlt.vendor variable used + * by iec61850_client_example1. + */ + IedServer_setWriteAccessPolicy(iedServer, IEC61850_FC_DC, ACCESS_POLICY_ALLOW); + + IedServer_setDataSetAccessHandler(iedServer, dataSetAccessHandler, NULL); + + /* MMS server will be instructed to start listening for client connections. */ + IedServer_start(iedServer, tcpPort); + + if (!IedServer_isRunning(iedServer)) { + printf("Starting server failed (maybe need root permissions or another server is already using the port)! Exit.\n"); + IedServer_destroy(iedServer); + exit(-1); + } + + running = 1; + + signal(SIGINT, sigint_handler); + + float t = 0.f; + + while (running) { + uint64_t timestamp = Hal_getTimeInMs(); + + t += 0.1f; + + float an1 = sinf(t); + float an2 = sinf(t + 1.f); + float an3 = sinf(t + 2.f); + float an4 = sinf(t + 3.f); + + Timestamp iecTimestamp; + + Timestamp_clearFlags(&iecTimestamp); + Timestamp_setTimeInMilliseconds(&iecTimestamp, timestamp); + Timestamp_setLeapSecondKnown(&iecTimestamp, true); + + /* toggle clock-not-synchronized flag in timestamp */ + if (((int) t % 2) == 0) + Timestamp_setClockNotSynchronized(&iecTimestamp, true); + +#if 1 + IedServer_lockDataModel(iedServer); + + IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_t, &iecTimestamp); + IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f, an1); + + IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_t, &iecTimestamp); + IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_mag_f, an2); + + IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_t, &iecTimestamp); + IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_mag_f, an3); + + IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_t, &iecTimestamp); + IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_mag_f, an4); + + IedServer_unlockDataModel(iedServer); +#endif + + Thread_sleep(100); + } + + /* stop MMS server - close TCP server socket and all client sockets */ + IedServer_stop(iedServer); + + /* Cleanup - free all resources */ + IedServer_destroy(iedServer); + + return 0; +} /* main() */ diff --git a/examples/server_example_access_control/static_model.c b/examples/server_example_access_control/static_model.c new file mode 100644 index 00000000..26f5f4fc --- /dev/null +++ b/examples/server_example_access_control/static_model.c @@ -0,0 +1,2223 @@ +/* + * static_model.c + * + * automatically generated from simpleIO_direct_control.cid + */ +#include "static_model.h" + +static void initializeValues(); + +extern DataSet iedModelds_GenericIO_LLN0_Events; +extern DataSet iedModelds_GenericIO_LLN0_Events2; +extern DataSet iedModelds_GenericIO_LLN0_Measurements; + + +extern DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda0; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda1; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda2; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda3; + +DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda0 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO1$stVal", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events_fcda1 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda1 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO2$stVal", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events_fcda2 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda2 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO3$stVal", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events_fcda3 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda3 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO4$stVal", + -1, + NULL, + NULL, + NULL +}; + +DataSet iedModelds_GenericIO_LLN0_Events = { + "GenericIO", + "LLN0$Events", + 4, + &iedModelds_GenericIO_LLN0_Events_fcda0, + &iedModelds_GenericIO_LLN0_Events2 +}; + +extern DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda0; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda1; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda2; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda3; + +DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda0 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO1", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events2_fcda1 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda1 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO2", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events2_fcda2 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda2 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO3", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events2_fcda3 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda3 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO4", + -1, + NULL, + NULL, + NULL +}; + +DataSet iedModelds_GenericIO_LLN0_Events2 = { + "GenericIO", + "LLN0$Events2", + 4, + &iedModelds_GenericIO_LLN0_Events2_fcda0, + &iedModelds_GenericIO_LLN0_Measurements +}; + +extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda0; +extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda1; +extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda2; +extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda3; +extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda4; +extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda5; +extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda6; +extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda7; + +DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda0 = { + "GenericIO", + false, + "GGIO1$MX$AnIn1$mag$f", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Measurements_fcda1 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda1 = { + "GenericIO", + false, + "GGIO1$MX$AnIn1$q", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Measurements_fcda2 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda2 = { + "GenericIO", + false, + "GGIO1$MX$AnIn2$mag$f", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Measurements_fcda3 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda3 = { + "GenericIO", + false, + "GGIO1$MX$AnIn2$q", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Measurements_fcda4 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda4 = { + "GenericIO", + false, + "GGIO1$MX$AnIn3$mag$f", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Measurements_fcda5 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda5 = { + "GenericIO", + false, + "GGIO1$MX$AnIn3$q", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Measurements_fcda6 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda6 = { + "GenericIO", + false, + "GGIO1$MX$AnIn4$mag$f", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Measurements_fcda7 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda7 = { + "GenericIO", + false, + "GGIO1$MX$AnIn4$q", + -1, + NULL, + NULL, + NULL +}; + +DataSet iedModelds_GenericIO_LLN0_Measurements = { + "GenericIO", + "LLN0$Measurements", + 8, + &iedModelds_GenericIO_LLN0_Measurements_fcda0, + NULL +}; + +LogicalDevice iedModel_GenericIO = { + LogicalDeviceModelType, + "GenericIO", + (ModelNode*) &iedModel, + NULL, + (ModelNode*) &iedModel_GenericIO_LLN0, + NULL +}; + +LogicalNode iedModel_GenericIO_LLN0 = { + LogicalNodeModelType, + "LLN0", + (ModelNode*) &iedModel_GenericIO, + (ModelNode*) &iedModel_GenericIO_LPHD1, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, +}; + +DataObject iedModel_GenericIO_LLN0_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_GenericIO_LLN0, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_stVal, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_q, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_t, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + (ModelNode*) &iedModel_GenericIO_LLN0_Mod_ctlModel, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_LLN0_Mod, + NULL, + NULL, + 0, + -1, + IEC61850_FC_CF, + IEC61850_ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LLN0_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_GenericIO_LLN0, + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh_stVal, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_LLN0_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh_q, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + (ModelNode*) &iedModel_GenericIO_LLN0_Beh_t, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LLN0_Beh, + NULL, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LLN0_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_GenericIO_LLN0, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_Health_stVal, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_LLN0_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + (ModelNode*) &iedModel_GenericIO_LLN0_Health_q, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + (ModelNode*) &iedModel_GenericIO_LLN0_Health_t, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LLN0_Health, + NULL, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LLN0_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_GenericIO_LLN0, + NULL, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_vendor, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_swRev, + NULL, + 0, + -1, + IEC61850_FC_DC, + IEC61850_VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_d, + NULL, + 0, + -1, + IEC61850_FC_DC, + IEC61850_VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_configRev, + NULL, + 0, + -1, + IEC61850_FC_DC, + IEC61850_VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev = { + DataAttributeModelType, + "configRev", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_ldNs, + NULL, + 0, + -1, + IEC61850_FC_DC, + IEC61850_VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs = { + DataAttributeModelType, + "ldNs", + (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt, + NULL, + NULL, + 0, + -1, + IEC61850_FC_EX, + IEC61850_VISIBLE_STRING_255, + 0, + NULL, + 0}; + +LogicalNode iedModel_GenericIO_LPHD1 = { + LogicalNodeModelType, + "LPHD1", + (ModelNode*) &iedModel_GenericIO, + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam, +}; + +DataObject iedModel_GenericIO_LPHD1_PhyNam = { + DataObjectModelType, + "PhyNam", + (ModelNode*) &iedModel_GenericIO_LPHD1, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam_vendor, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam, + NULL, + NULL, + 0, + -1, + IEC61850_FC_DC, + IEC61850_VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LPHD1_PhyHealth = { + DataObjectModelType, + "PhyHealth", + (ModelNode*) &iedModel_GenericIO_LPHD1, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_stVal, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_q, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_t, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth, + NULL, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_LPHD1_Proxy = { + DataObjectModelType, + "Proxy", + (ModelNode*) &iedModel_GenericIO_LPHD1, + NULL, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_stVal, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_q, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_Proxy_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_t, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_LPHD1_Proxy_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy, + NULL, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +LogicalNode iedModel_GenericIO_GGIO1 = { + LogicalNodeModelType, + "GGIO1", + (ModelNode*) &iedModel_GenericIO, + NULL, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, +}; + +DataObject iedModel_GenericIO_GGIO1_Mod = { + DataObjectModelType, + "Mod", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_stVal, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_q, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_t, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_ctlModel, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_Mod, + NULL, + NULL, + 0, + -1, + IEC61850_FC_CF, + IEC61850_ENUMERATED, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Beh = { + DataObjectModelType, + "Beh", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_stVal, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_q, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Beh_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_t, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Beh_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Beh, + NULL, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Health = { + DataObjectModelType, + "Health", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health_stVal, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Health_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health_q, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_ENUMERATED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Health_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + (ModelNode*) &iedModel_GenericIO_GGIO1_Health_t, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Health_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Health, + NULL, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_NamPlt = { + DataObjectModelType, + "NamPlt", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_vendor, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor = { + DataAttributeModelType, + "vendor", + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_swRev, + NULL, + 0, + -1, + IEC61850_FC_DC, + IEC61850_VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev = { + DataAttributeModelType, + "swRev", + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_d, + NULL, + 0, + -1, + IEC61850_FC_DC, + IEC61850_VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d = { + DataAttributeModelType, + "d", + (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt, + NULL, + NULL, + 0, + -1, + IEC61850_FC_DC, + IEC61850_VISIBLE_STRING_255, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn1 = { + DataObjectModelType, + "AnIn1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag_f, + 0, + -1, + IEC61850_FC_MX, + IEC61850_CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag, + NULL, + NULL, + 0, + -1, + IEC61850_FC_MX, + IEC61850_FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_t, + NULL, + 0, + -1, + IEC61850_FC_MX, + IEC61850_QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1, + NULL, + NULL, + 0, + -1, + IEC61850_FC_MX, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn2 = { + DataObjectModelType, + "AnIn2", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag_f, + 0, + -1, + IEC61850_FC_MX, + IEC61850_CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag, + NULL, + NULL, + 0, + -1, + IEC61850_FC_MX, + IEC61850_FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_t, + NULL, + 0, + -1, + IEC61850_FC_MX, + IEC61850_QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2, + NULL, + NULL, + 0, + -1, + IEC61850_FC_MX, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn3 = { + DataObjectModelType, + "AnIn3", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag_f, + 0, + -1, + IEC61850_FC_MX, + IEC61850_CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag, + NULL, + NULL, + 0, + -1, + IEC61850_FC_MX, + IEC61850_FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_t, + NULL, + 0, + -1, + IEC61850_FC_MX, + IEC61850_QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3, + NULL, + NULL, + 0, + -1, + IEC61850_FC_MX, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_AnIn4 = { + DataObjectModelType, + "AnIn4", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag = { + DataAttributeModelType, + "mag", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_q, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag_f, + 0, + -1, + IEC61850_FC_MX, + IEC61850_CONSTRUCTED, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f = { + DataAttributeModelType, + "f", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag, + NULL, + NULL, + 0, + -1, + IEC61850_FC_MX, + IEC61850_FLOAT32, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_t, + NULL, + 0, + -1, + IEC61850_FC_MX, + IEC61850_QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4, + NULL, + NULL, + 0, + -1, + IEC61850_FC_MX, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO1 = { + DataObjectModelType, + "SPCSO1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_origin, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_origin_orCat, + 0, + -1, + IEC61850_FC_ST, + IEC61850_CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_origin_orIdent, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_origin, + NULL, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_stVal, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_q, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_t, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_ctlModel, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + NULL, + 0, + -1, + IEC61850_FC_CF, + IEC61850_ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1, + NULL, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal, + 0, + -1, + IEC61850_FC_CO, + IEC61850_CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat, + 0, + -1, + IEC61850_FC_CO, + IEC61850_CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin, + NULL, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_T, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper, + NULL, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_CHECK, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO2 = { + DataObjectModelType, + "SPCSO2", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_stVal, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_q, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal, + 0, + -1, + IEC61850_FC_CO, + IEC61850_CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat, + 0, + -1, + IEC61850_FC_CO, + IEC61850_CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin, + NULL, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_T, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper, + NULL, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_t, + NULL, + 0, + -1, + IEC61850_FC_CF, + IEC61850_ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2, + NULL, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO3 = { + DataObjectModelType, + "SPCSO3", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_stVal, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_q, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal, + 0, + -1, + IEC61850_FC_CO, + IEC61850_CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat, + 0, + -1, + IEC61850_FC_CO, + IEC61850_CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin, + NULL, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_T, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper, + NULL, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_t, + NULL, + 0, + -1, + IEC61850_FC_CF, + IEC61850_ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3, + NULL, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_SPCSO4 = { + DataObjectModelType, + "SPCSO4", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_stVal, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_q, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_ctlModel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal, + 0, + -1, + IEC61850_FC_CO, + IEC61850_CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat, + 0, + -1, + IEC61850_FC_CO, + IEC61850_CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin, + NULL, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_T, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper, + NULL, + NULL, + 0, + -1, + IEC61850_FC_CO, + IEC61850_CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_t, + NULL, + 0, + -1, + IEC61850_FC_CF, + IEC61850_ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4, + NULL, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind1 = { + DataObjectModelType, + "Ind1", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_stVal, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_q, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind1_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_t, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind1_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + NULL, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind2 = { + DataObjectModelType, + "Ind2", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_stVal, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_q, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind2_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_t, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind2_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2, + NULL, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind3 = { + DataObjectModelType, + "Ind3", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_stVal, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_q, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind3_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_t, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind3_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3, + NULL, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +DataObject iedModel_GenericIO_GGIO1_Ind4 = { + DataObjectModelType, + "Ind4", + (ModelNode*) &iedModel_GenericIO_GGIO1, + NULL, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_stVal, + 0, + -1 +}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_q, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind4_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_t, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4, + NULL, + NULL, + 0, + -1, + IEC61850_FC_ST, + IEC61850_TIMESTAMP, + 0, + NULL, + 0}; + +extern ReportControlBlock iedModel_GenericIO_LLN0_report0; +extern ReportControlBlock iedModel_GenericIO_LLN0_report1; +extern ReportControlBlock iedModel_GenericIO_LLN0_report2; +extern ReportControlBlock iedModel_GenericIO_LLN0_report3; +extern ReportControlBlock iedModel_GenericIO_LLN0_report4; +extern ReportControlBlock iedModel_GenericIO_LLN0_report5; +extern ReportControlBlock iedModel_GenericIO_LLN0_report6; +extern ReportControlBlock iedModel_GenericIO_LLN0_report7; +extern ReportControlBlock iedModel_GenericIO_LLN0_report8; +extern ReportControlBlock iedModel_GenericIO_LLN0_report9; + +ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events1", false, "Events", 1, 88, 175, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report1}; +ReportControlBlock iedModel_GenericIO_LLN0_report1 = {&iedModel_GenericIO_LLN0, "EventsRCBPreConf01", "Events1", false, "Events", 1, 88, 175, 50, 1000, {0x4, 0xc0, 0xa8, 0x2, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report2}; +ReportControlBlock iedModel_GenericIO_LLN0_report2 = {&iedModel_GenericIO_LLN0, "EventsBRCB01", "Events2", true, "Events", 1, 88, 175, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report3}; +ReportControlBlock iedModel_GenericIO_LLN0_report3 = {&iedModel_GenericIO_LLN0, "EventsBRCBPreConf01", "Events2", true, "Events", 1, 88, 175, 50, 1000, {0x4, 0xc0, 0xa8, 0x2, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report4}; +ReportControlBlock iedModel_GenericIO_LLN0_report4 = {&iedModel_GenericIO_LLN0, "EventsIndexed01", "Events2", false, "Events", 1, 88, 175, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report5}; +ReportControlBlock iedModel_GenericIO_LLN0_report5 = {&iedModel_GenericIO_LLN0, "EventsIndexed02", "Events2", false, "Events", 1, 88, 175, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report6}; +ReportControlBlock iedModel_GenericIO_LLN0_report6 = {&iedModel_GenericIO_LLN0, "EventsIndexed03", "Events2", false, "Events", 1, 88, 175, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report7}; +ReportControlBlock iedModel_GenericIO_LLN0_report7 = {&iedModel_GenericIO_LLN0, "Measurements01", "Measurements", true, "Measurements", 1, 80, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report8}; +ReportControlBlock iedModel_GenericIO_LLN0_report8 = {&iedModel_GenericIO_LLN0, "Measurements02", "Measurements", true, "Measurements", 1, 80, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report9}; +ReportControlBlock iedModel_GenericIO_LLN0_report9 = {&iedModel_GenericIO_LLN0, "Measurements03", "Measurements", true, "Measurements", 1, 80, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, NULL}; + + + + + + + +IedModel iedModel = { + "simpleIO", + &iedModel_GenericIO, + &iedModelds_GenericIO_LLN0_Events, + &iedModel_GenericIO_LLN0_report0, + NULL, + NULL, + NULL, + NULL, + NULL, + initializeValues +}; + +static void +initializeValues() +{ + +iedModel_GenericIO_LLN0_Mod_stVal.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_LLN0_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_GenericIO_LLN0_Beh_stVal.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_LLN0_Health_stVal.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_LLN0_NamPlt_vendor.mmsValue = MmsValue_newVisibleString("MZ Automation"); + +iedModel_GenericIO_LLN0_NamPlt_swRev.mmsValue = MmsValue_newVisibleString("1.3.0"); + +iedModel_GenericIO_LLN0_NamPlt_d.mmsValue = MmsValue_newVisibleString("libiec61850 server example"); + +iedModel_GenericIO_LPHD1_PhyHealth_stVal.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_Mod_stVal.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0); + +iedModel_GenericIO_GGIO1_Beh_stVal.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_Health_stVal.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_SPCSO1_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_SPCSO2_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_SPCSO3_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); + +iedModel_GenericIO_GGIO1_SPCSO4_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1); +} diff --git a/examples/server_example_access_control/static_model.h b/examples/server_example_access_control/static_model.h new file mode 100644 index 00000000..b6030e51 --- /dev/null +++ b/examples/server_example_access_control/static_model.h @@ -0,0 +1,311 @@ +/* + * static_model.h + * + * automatically generated from simpleIO_direct_control.cid + */ + +#ifndef STATIC_MODEL_H_ +#define STATIC_MODEL_H_ + +#include +#include "iec61850_model.h" + +extern IedModel iedModel; +extern LogicalDevice iedModel_GenericIO; +extern LogicalNode iedModel_GenericIO_LLN0; +extern DataObject iedModel_GenericIO_LLN0_Mod; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_q; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_t; +extern DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel; +extern DataObject iedModel_GenericIO_LLN0_Beh; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_q; +extern DataAttribute iedModel_GenericIO_LLN0_Beh_t; +extern DataObject iedModel_GenericIO_LLN0_Health; +extern DataAttribute iedModel_GenericIO_LLN0_Health_stVal; +extern DataAttribute iedModel_GenericIO_LLN0_Health_q; +extern DataAttribute iedModel_GenericIO_LLN0_Health_t; +extern DataObject iedModel_GenericIO_LLN0_NamPlt; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_d; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev; +extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs; +extern LogicalNode iedModel_GenericIO_LPHD1; +extern DataObject iedModel_GenericIO_LPHD1_PhyNam; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor; +extern DataObject iedModel_GenericIO_LPHD1_PhyHealth; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q; +extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t; +extern DataObject iedModel_GenericIO_LPHD1_Proxy; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_q; +extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_t; +extern LogicalNode iedModel_GenericIO_GGIO1; +extern DataObject iedModel_GenericIO_GGIO1_Mod; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_t; +extern DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_Beh; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Beh_t; +extern DataObject iedModel_GenericIO_GGIO1_Health; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Health_t; +extern DataObject iedModel_GenericIO_GGIO1_NamPlt; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev; +extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d; +extern DataObject iedModel_GenericIO_GGIO1_AnIn1; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn2; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn3; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t; +extern DataObject iedModel_GenericIO_GGIO1_AnIn4; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO1; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO2; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO3; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO4; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind1; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind2; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind3; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_t; +extern DataObject iedModel_GenericIO_GGIO1_Ind4; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_q; +extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t; + + + +#define IEDMODEL_GenericIO (&iedModel_GenericIO) +#define IEDMODEL_GenericIO_LLN0 (&iedModel_GenericIO_LLN0) +#define IEDMODEL_GenericIO_LLN0_Mod (&iedModel_GenericIO_LLN0_Mod) +#define IEDMODEL_GenericIO_LLN0_Mod_stVal (&iedModel_GenericIO_LLN0_Mod_stVal) +#define IEDMODEL_GenericIO_LLN0_Mod_q (&iedModel_GenericIO_LLN0_Mod_q) +#define IEDMODEL_GenericIO_LLN0_Mod_t (&iedModel_GenericIO_LLN0_Mod_t) +#define IEDMODEL_GenericIO_LLN0_Mod_ctlModel (&iedModel_GenericIO_LLN0_Mod_ctlModel) +#define IEDMODEL_GenericIO_LLN0_Beh (&iedModel_GenericIO_LLN0_Beh) +#define IEDMODEL_GenericIO_LLN0_Beh_stVal (&iedModel_GenericIO_LLN0_Beh_stVal) +#define IEDMODEL_GenericIO_LLN0_Beh_q (&iedModel_GenericIO_LLN0_Beh_q) +#define IEDMODEL_GenericIO_LLN0_Beh_t (&iedModel_GenericIO_LLN0_Beh_t) +#define IEDMODEL_GenericIO_LLN0_Health (&iedModel_GenericIO_LLN0_Health) +#define IEDMODEL_GenericIO_LLN0_Health_stVal (&iedModel_GenericIO_LLN0_Health_stVal) +#define IEDMODEL_GenericIO_LLN0_Health_q (&iedModel_GenericIO_LLN0_Health_q) +#define IEDMODEL_GenericIO_LLN0_Health_t (&iedModel_GenericIO_LLN0_Health_t) +#define IEDMODEL_GenericIO_LLN0_NamPlt (&iedModel_GenericIO_LLN0_NamPlt) +#define IEDMODEL_GenericIO_LLN0_NamPlt_vendor (&iedModel_GenericIO_LLN0_NamPlt_vendor) +#define IEDMODEL_GenericIO_LLN0_NamPlt_swRev (&iedModel_GenericIO_LLN0_NamPlt_swRev) +#define IEDMODEL_GenericIO_LLN0_NamPlt_d (&iedModel_GenericIO_LLN0_NamPlt_d) +#define IEDMODEL_GenericIO_LLN0_NamPlt_configRev (&iedModel_GenericIO_LLN0_NamPlt_configRev) +#define IEDMODEL_GenericIO_LLN0_NamPlt_ldNs (&iedModel_GenericIO_LLN0_NamPlt_ldNs) +#define IEDMODEL_GenericIO_LPHD1 (&iedModel_GenericIO_LPHD1) +#define IEDMODEL_GenericIO_LPHD1_PhyNam (&iedModel_GenericIO_LPHD1_PhyNam) +#define IEDMODEL_GenericIO_LPHD1_PhyNam_vendor (&iedModel_GenericIO_LPHD1_PhyNam_vendor) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth (&iedModel_GenericIO_LPHD1_PhyHealth) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth_stVal (&iedModel_GenericIO_LPHD1_PhyHealth_stVal) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth_q (&iedModel_GenericIO_LPHD1_PhyHealth_q) +#define IEDMODEL_GenericIO_LPHD1_PhyHealth_t (&iedModel_GenericIO_LPHD1_PhyHealth_t) +#define IEDMODEL_GenericIO_LPHD1_Proxy (&iedModel_GenericIO_LPHD1_Proxy) +#define IEDMODEL_GenericIO_LPHD1_Proxy_stVal (&iedModel_GenericIO_LPHD1_Proxy_stVal) +#define IEDMODEL_GenericIO_LPHD1_Proxy_q (&iedModel_GenericIO_LPHD1_Proxy_q) +#define IEDMODEL_GenericIO_LPHD1_Proxy_t (&iedModel_GenericIO_LPHD1_Proxy_t) +#define IEDMODEL_GenericIO_GGIO1 (&iedModel_GenericIO_GGIO1) +#define IEDMODEL_GenericIO_GGIO1_Mod (&iedModel_GenericIO_GGIO1_Mod) +#define IEDMODEL_GenericIO_GGIO1_Mod_stVal (&iedModel_GenericIO_GGIO1_Mod_stVal) +#define IEDMODEL_GenericIO_GGIO1_Mod_q (&iedModel_GenericIO_GGIO1_Mod_q) +#define IEDMODEL_GenericIO_GGIO1_Mod_t (&iedModel_GenericIO_GGIO1_Mod_t) +#define IEDMODEL_GenericIO_GGIO1_Mod_ctlModel (&iedModel_GenericIO_GGIO1_Mod_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_Beh (&iedModel_GenericIO_GGIO1_Beh) +#define IEDMODEL_GenericIO_GGIO1_Beh_stVal (&iedModel_GenericIO_GGIO1_Beh_stVal) +#define IEDMODEL_GenericIO_GGIO1_Beh_q (&iedModel_GenericIO_GGIO1_Beh_q) +#define IEDMODEL_GenericIO_GGIO1_Beh_t (&iedModel_GenericIO_GGIO1_Beh_t) +#define IEDMODEL_GenericIO_GGIO1_Health (&iedModel_GenericIO_GGIO1_Health) +#define IEDMODEL_GenericIO_GGIO1_Health_stVal (&iedModel_GenericIO_GGIO1_Health_stVal) +#define IEDMODEL_GenericIO_GGIO1_Health_q (&iedModel_GenericIO_GGIO1_Health_q) +#define IEDMODEL_GenericIO_GGIO1_Health_t (&iedModel_GenericIO_GGIO1_Health_t) +#define IEDMODEL_GenericIO_GGIO1_NamPlt (&iedModel_GenericIO_GGIO1_NamPlt) +#define IEDMODEL_GenericIO_GGIO1_NamPlt_vendor (&iedModel_GenericIO_GGIO1_NamPlt_vendor) +#define IEDMODEL_GenericIO_GGIO1_NamPlt_swRev (&iedModel_GenericIO_GGIO1_NamPlt_swRev) +#define IEDMODEL_GenericIO_GGIO1_NamPlt_d (&iedModel_GenericIO_GGIO1_NamPlt_d) +#define IEDMODEL_GenericIO_GGIO1_AnIn1 (&iedModel_GenericIO_GGIO1_AnIn1) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_mag (&iedModel_GenericIO_GGIO1_AnIn1_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f (&iedModel_GenericIO_GGIO1_AnIn1_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_q (&iedModel_GenericIO_GGIO1_AnIn1_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn1_t (&iedModel_GenericIO_GGIO1_AnIn1_t) +#define IEDMODEL_GenericIO_GGIO1_AnIn2 (&iedModel_GenericIO_GGIO1_AnIn2) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_mag (&iedModel_GenericIO_GGIO1_AnIn2_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_mag_f (&iedModel_GenericIO_GGIO1_AnIn2_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_q (&iedModel_GenericIO_GGIO1_AnIn2_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn2_t (&iedModel_GenericIO_GGIO1_AnIn2_t) +#define IEDMODEL_GenericIO_GGIO1_AnIn3 (&iedModel_GenericIO_GGIO1_AnIn3) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_mag (&iedModel_GenericIO_GGIO1_AnIn3_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_mag_f (&iedModel_GenericIO_GGIO1_AnIn3_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_q (&iedModel_GenericIO_GGIO1_AnIn3_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn3_t (&iedModel_GenericIO_GGIO1_AnIn3_t) +#define IEDMODEL_GenericIO_GGIO1_AnIn4 (&iedModel_GenericIO_GGIO1_AnIn4) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_mag (&iedModel_GenericIO_GGIO1_AnIn4_mag) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_mag_f (&iedModel_GenericIO_GGIO1_AnIn4_mag_f) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_q (&iedModel_GenericIO_GGIO1_AnIn4_q) +#define IEDMODEL_GenericIO_GGIO1_AnIn4_t (&iedModel_GenericIO_GGIO1_AnIn4_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1 (&iedModel_GenericIO_GGIO1_SPCSO1) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_origin (&iedModel_GenericIO_GGIO1_SPCSO1_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO1_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO1_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO1_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal (&iedModel_GenericIO_GGIO1_SPCSO1_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_q (&iedModel_GenericIO_GGIO1_SPCSO1_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_t (&iedModel_GenericIO_GGIO1_SPCSO1_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO1_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper (&iedModel_GenericIO_GGIO1_SPCSO1_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2 (&iedModel_GenericIO_GGIO1_SPCSO2) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal (&iedModel_GenericIO_GGIO1_SPCSO2_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_q (&iedModel_GenericIO_GGIO1_SPCSO2_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper (&iedModel_GenericIO_GGIO1_SPCSO2_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO2_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO2_t (&iedModel_GenericIO_GGIO1_SPCSO2_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3 (&iedModel_GenericIO_GGIO1_SPCSO3) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal (&iedModel_GenericIO_GGIO1_SPCSO3_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_q (&iedModel_GenericIO_GGIO1_SPCSO3_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper (&iedModel_GenericIO_GGIO1_SPCSO3_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO3_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO3_t (&iedModel_GenericIO_GGIO1_SPCSO3_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4 (&iedModel_GenericIO_GGIO1_SPCSO4) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal (&iedModel_GenericIO_GGIO1_SPCSO4_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_q (&iedModel_GenericIO_GGIO1_SPCSO4_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper (&iedModel_GenericIO_GGIO1_SPCSO4_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO4_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO4_t (&iedModel_GenericIO_GGIO1_SPCSO4_t) +#define IEDMODEL_GenericIO_GGIO1_Ind1 (&iedModel_GenericIO_GGIO1_Ind1) +#define IEDMODEL_GenericIO_GGIO1_Ind1_stVal (&iedModel_GenericIO_GGIO1_Ind1_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind1_q (&iedModel_GenericIO_GGIO1_Ind1_q) +#define IEDMODEL_GenericIO_GGIO1_Ind1_t (&iedModel_GenericIO_GGIO1_Ind1_t) +#define IEDMODEL_GenericIO_GGIO1_Ind2 (&iedModel_GenericIO_GGIO1_Ind2) +#define IEDMODEL_GenericIO_GGIO1_Ind2_stVal (&iedModel_GenericIO_GGIO1_Ind2_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind2_q (&iedModel_GenericIO_GGIO1_Ind2_q) +#define IEDMODEL_GenericIO_GGIO1_Ind2_t (&iedModel_GenericIO_GGIO1_Ind2_t) +#define IEDMODEL_GenericIO_GGIO1_Ind3 (&iedModel_GenericIO_GGIO1_Ind3) +#define IEDMODEL_GenericIO_GGIO1_Ind3_stVal (&iedModel_GenericIO_GGIO1_Ind3_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind3_q (&iedModel_GenericIO_GGIO1_Ind3_q) +#define IEDMODEL_GenericIO_GGIO1_Ind3_t (&iedModel_GenericIO_GGIO1_Ind3_t) +#define IEDMODEL_GenericIO_GGIO1_Ind4 (&iedModel_GenericIO_GGIO1_Ind4) +#define IEDMODEL_GenericIO_GGIO1_Ind4_stVal (&iedModel_GenericIO_GGIO1_Ind4_stVal) +#define IEDMODEL_GenericIO_GGIO1_Ind4_q (&iedModel_GenericIO_GGIO1_Ind4_q) +#define IEDMODEL_GenericIO_GGIO1_Ind4_t (&iedModel_GenericIO_GGIO1_Ind4_t) + +#endif /* STATIC_MODEL_H_ */ + diff --git a/src/iec61850/inc_private/mms_mapping_internal.h b/src/iec61850/inc_private/mms_mapping_internal.h index 3e896495..c22311f6 100644 --- a/src/iec61850/inc_private/mms_mapping_internal.h +++ b/src/iec61850/inc_private/mms_mapping_internal.h @@ -334,6 +334,9 @@ struct sMmsMapping { IedServer_RCBEventHandler rcbEventHandler; void* rcbEventHandlerParameter; + + IedServer_DataSetAccessHandler dataSetAccessHandler; + void* dataSetAccessHandlerParameter; }; #endif /* MMS_MAPPING_INTERNAL_H_ */ diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index c543a41d..d748bf5a 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -1917,3 +1917,10 @@ IedServer_ignoreClientRequests(IedServer self, bool enable) MmsServer_ignoreClientRequests(self->mmsServer, enable); } } + +void +IedServer_setDataSetAccessHandler(IedServer self, IedServer_DataSetAccessHandler handler, void* parameter) +{ + self->mmsMapping->dataSetAccessHandler = handler; + self->mmsMapping->dataSetAccessHandlerParameter = parameter; +} diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index 4d6d8b31..a33e31b2 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -3378,13 +3378,46 @@ mmsReadAccessHandler (void* parameter, MmsDomain* domain, char* variableId, MmsS return DATA_ACCESS_ERROR_SUCCESS; } +static bool +checkDataSetAccess(MmsMapping* self, MmsServerConnection connection, MmsVariableListType listType, MmsDomain* domain, char* listName, IedServer_DataSetOperation operation) +{ + bool accessGranted = true; + + if (self->dataSetAccessHandler) { + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + + char dataSetRef[130]; + dataSetRef[0] = 0; + + if (listType == MMS_ASSOCIATION_SPECIFIC) { + dataSetRef[0] = '@'; + StringUtils_copyStringToBuffer(dataSetRef + 1, listName); + } + else if (listType == MMS_VMD_SPECIFIC) { + StringUtils_copyStringToBuffer(dataSetRef, listName); + } + else if (listType == MMS_DOMAIN_SPECIFIC) { + StringUtils_appendString(dataSetRef, 129, domain->domainName); + StringUtils_appendString(dataSetRef, 129, "/"); + StringUtils_appendString(dataSetRef, 129, listName); + } + + accessGranted = self->dataSetAccessHandler(self->dataSetAccessHandlerParameter, + private_IedServer_getClientConnectionByHandle(self->iedServer, connection), + operation, dataSetRef); + } + + return accessGranted; +} + static MmsError variableListAccessHandler (void* parameter, MmsVariableListAccessType accessType, MmsVariableListType listType, MmsDomain* domain, char* listName, MmsServerConnection connection) { MmsError allow = MMS_ERROR_NONE; - (void)connection; + MmsMapping* self = (MmsMapping*) parameter; /* TODO add log message */ @@ -3415,130 +3448,142 @@ variableListAccessHandler (void* parameter, MmsVariableListAccessType accessType printf("specific (name=%s)\n", listName); #endif /* (DEBUG_IED_SERVER == 1) */ - MmsMapping* self = (MmsMapping*) parameter; - if (accessType == MMS_VARLIST_CREATE) { - //TODO call user callback hander (IedServer_DataSetAccessHandler) + if (checkDataSetAccess(self, connection, listType, domain, listName, DATASET_CREATE)) { - if (listType == MMS_DOMAIN_SPECIFIC) { - /* check if LN exists - otherwise reject request (to fulfill test case sDsN1c) */ + if (listType == MMS_DOMAIN_SPECIFIC) { + /* check if LN exists - otherwise reject request (to fulfill test case sDsN1c) */ - allow = MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT; + allow = MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT; - IedModel* model = self->model; + IedModel* model = self->model; - LogicalDevice* ld = IedModel_getDevice(model, domain->domainName); + LogicalDevice* ld = IedModel_getDevice(model, domain->domainName); - if (ld != NULL) { + if (ld != NULL) { - char lnName[129]; + char lnName[129]; - char* separator = strchr(listName, '$'); + char* separator = strchr(listName, '$'); - if (separator != NULL) { - int lnNameLen = separator - listName; + if (separator != NULL) { + int lnNameLen = separator - listName; - memcpy(lnName, listName, lnNameLen); - lnName[lnNameLen] = 0; + memcpy(lnName, listName, lnNameLen); + lnName[lnNameLen] = 0; - if (LogicalDevice_getLogicalNode(ld, lnName) != NULL) - allow = MMS_ERROR_NONE; - } + if (LogicalDevice_getLogicalNode(ld, lnName) != NULL) + allow = MMS_ERROR_NONE; + } + } } - + } + else { + allow = MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED; } } else if (accessType == MMS_VARLIST_DELETE) { - //TODO call user callback hander (IedServer_DataSetAccessHandler) + if (checkDataSetAccess(self, connection, listType, domain, listName, DATASET_DELETE)) { + /* Check if data set is referenced in a report */ - /* Check if data set is referenced in a report */ + LinkedList rcElement = self->reportControls; - LinkedList rcElement = self->reportControls; + while ((rcElement = LinkedList_getNext(rcElement)) != NULL) { + ReportControl* rc = (ReportControl*) rcElement->data; - while ((rcElement = LinkedList_getNext(rcElement)) != NULL) { - ReportControl* rc = (ReportControl*) rcElement->data; + if (rc->isDynamicDataSet) { + if (rc->dataSet != NULL) { - if (rc->isDynamicDataSet) { - if (rc->dataSet != NULL) { - - if (listType == MMS_DOMAIN_SPECIFIC) { - if (rc->dataSet->logicalDeviceName != NULL) { - if (strcmp(rc->dataSet->name, listName) == 0) { - if (strcmp(rc->dataSet->logicalDeviceName, MmsDomain_getName(domain) + strlen(self->model->name)) == 0) { - allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT; - break; + if (listType == MMS_DOMAIN_SPECIFIC) { + if (rc->dataSet->logicalDeviceName != NULL) { + if (strcmp(rc->dataSet->name, listName) == 0) { + if (strcmp(rc->dataSet->logicalDeviceName, MmsDomain_getName(domain) + strlen(self->model->name)) == 0) { + allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT; + break; + } } } } - } - else if (listType == MMS_VMD_SPECIFIC) { - if (rc->dataSet->logicalDeviceName == NULL) { - if (strcmp(rc->dataSet->name, listName) == 0) { - allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT; - break; + else if (listType == MMS_VMD_SPECIFIC) { + if (rc->dataSet->logicalDeviceName == NULL) { + if (strcmp(rc->dataSet->name, listName) == 0) { + allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT; + break; + } } } - } - else if (listType == MMS_ASSOCIATION_SPECIFIC) { - if (rc->dataSet->logicalDeviceName == NULL) { - if (strcmp(rc->dataSet->name, listName) == 0) { - allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT; - break; + else if (listType == MMS_ASSOCIATION_SPECIFIC) { + if (rc->dataSet->logicalDeviceName == NULL) { + if (strcmp(rc->dataSet->name, listName) == 0) { + allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT; + break; + } } } - } + } } } - } - #if (CONFIG_IEC61850_LOG_SERVICE == 1) - /* check if data set is referenced in a log control block*/ - LinkedList logElement = self->logControls; + /* check if data set is referenced in a log control block*/ + LinkedList logElement = self->logControls; - while ((logElement = LinkedList_getNext(logElement)) != NULL) { - LogControl* lc = (LogControl*) logElement->data; + while ((logElement = LinkedList_getNext(logElement)) != NULL) { + LogControl* lc = (LogControl*) logElement->data; - if (lc->isDynamicDataSet) { - if (lc->dataSet != NULL) { + if (lc->isDynamicDataSet) { + if (lc->dataSet != NULL) { - if (listType == MMS_DOMAIN_SPECIFIC) { - if (lc->dataSet->logicalDeviceName != NULL) { - if (strcmp(lc->dataSet->name, listName) == 0) { - if (strcmp(lc->dataSet->logicalDeviceName, MmsDomain_getName(domain) + strlen(self->model->name)) == 0) { - allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT; - break; + if (listType == MMS_DOMAIN_SPECIFIC) { + if (lc->dataSet->logicalDeviceName != NULL) { + if (strcmp(lc->dataSet->name, listName) == 0) { + if (strcmp(lc->dataSet->logicalDeviceName, MmsDomain_getName(domain) + strlen(self->model->name)) == 0) { + allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT; + break; + } } } } - } - else if (listType == MMS_VMD_SPECIFIC) { - if (lc->dataSet->logicalDeviceName == NULL) { - if (strcmp(lc->dataSet->name, listName) == 0) { - allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT; - break; + else if (listType == MMS_VMD_SPECIFIC) { + if (lc->dataSet->logicalDeviceName == NULL) { + if (strcmp(lc->dataSet->name, listName) == 0) { + allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT; + break; + } } } - } + } } } - } #endif /* (CONFIG_IEC61850_LOG_SERVICE == 1) */ + + } + else { + allow = MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED; + } } - else if (accessType == MMS_VARLIST_READ) { - //TODO call user callback hander (IedServer_DataSetAccessHandler) + else if (accessType == MMS_VARLIST_READ) + { + if (checkDataSetAccess(self, connection, listType, domain, listName, DATASET_READ) == false) { + allow = MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED; + } } - else if (accessType == MMS_VARLIST_WRITE) { - //TODO call user callback hander (IedServer_DataSetAccessHandler) + else if (accessType == MMS_VARLIST_WRITE) + { + if (checkDataSetAccess(self, connection, listType, domain, listName, DATASET_WRITE) == false) { + allow = MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED; + } } else if (accessType == MMS_VARLIST_GET_DIRECTORY) { - //TODO call user callback hander (IedServer_DataSetAccessHandler) + if (checkDataSetAccess(self, connection, listType, domain, listName, DATASET_GET_DIRECTORY) == false) { + allow = MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED; + } } return allow; diff --git a/src/mms/inc/iso_connection_parameters.h b/src/mms/inc/iso_connection_parameters.h index cdd04bcb..e3af848f 100644 --- a/src/mms/inc/iso_connection_parameters.h +++ b/src/mms/inc/iso_connection_parameters.h @@ -1,7 +1,7 @@ /* * iso_connection_parameters.h * - * Copyright 2013-2018 Michael Zillgith + * Copyright 2013-2023 Michael Zillgith * * This file is part of libIEC61850. * @@ -24,6 +24,10 @@ #ifndef ISO_CONNECTION_PARAMETERS_H_ #define ISO_CONNECTION_PARAMETERS_H_ +#ifndef CONFIG_MMS_SUPPORT_TLS +#define CONFIG_MMS_SUPPORT_TLS 0 +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/src/mms/iso_mms/server/mms_named_variable_list_service.c b/src/mms/iso_mms/server/mms_named_variable_list_service.c index 4baf4ab3..85f1b960 100644 --- a/src/mms/iso_mms/server/mms_named_variable_list_service.c +++ b/src/mms/iso_mms/server/mms_named_variable_list_service.c @@ -50,66 +50,66 @@ MmsError mmsServer_callVariableListChangedHandler(MmsVariableListAccessType accessType, MmsVariableListType listType, MmsDomain* domain, - char* listName, MmsServerConnection connection) + char* listName, MmsServerConnection connection) { - MmsServer self = connection->server; + MmsServer self = connection->server; - if (self->variableListAccessHandler != NULL) { - if (DEBUG_MMS_SERVER) - printf("MMS_SERVER: call MmsNamedVariableListAccessHandler for new list %s\n", listName); + if (self->variableListAccessHandler != NULL) { + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: call MmsNamedVariableListAccessHandler for new list %s\n", listName); - return self->variableListAccessHandler(self->variableListAccessHandlerParameter, - accessType, listType, domain, listName, connection); - } - else - return MMS_ERROR_NONE; + return self->variableListAccessHandler(self->variableListAccessHandlerParameter, + accessType, listType, domain, listName, connection); + } + else + return MMS_ERROR_NONE; } static void createDeleteNamedVariableListResponse(uint32_t invokeId, ByteBuffer* response, - uint32_t numberMatched, uint32_t numberDeleted) + uint32_t numberMatched, uint32_t numberDeleted) { - uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId) + 2; + uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId) + 2; - uint32_t numberMatchedSize = - 2 + BerEncoder_UInt32determineEncodedSize(numberMatched); + uint32_t numberMatchedSize = + 2 + BerEncoder_UInt32determineEncodedSize(numberMatched); - uint32_t numberDeletedSize = - 2 + BerEncoder_UInt32determineEncodedSize(numberDeleted); + uint32_t numberDeletedSize = + 2 + BerEncoder_UInt32determineEncodedSize(numberDeleted); - uint32_t deleteNVLSize = 2 + numberMatchedSize + numberDeletedSize; + uint32_t deleteNVLSize = 2 + numberMatchedSize + numberDeletedSize; - uint32_t confirmedResponsePDUSize = invokeIdSize + deleteNVLSize; + uint32_t confirmedResponsePDUSize = invokeIdSize + deleteNVLSize; - int bufPos = 0; - uint8_t* buffer = response->buffer; + int bufPos = 0; + uint8_t* buffer = response->buffer; - bufPos = BerEncoder_encodeTL(0xa1, confirmedResponsePDUSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0xa1, confirmedResponsePDUSize, buffer, bufPos); - bufPos = BerEncoder_encodeTL(0x02, invokeIdSize - 2, buffer, bufPos); - bufPos = BerEncoder_encodeUInt32(invokeId, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x02, invokeIdSize - 2, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(invokeId, buffer, bufPos); - bufPos = BerEncoder_encodeTL(0xad, numberMatchedSize + numberDeletedSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0xad, numberMatchedSize + numberDeletedSize, buffer, bufPos); - bufPos = BerEncoder_encodeTL(0x80, numberMatchedSize - 2, buffer, bufPos); - bufPos = BerEncoder_encodeUInt32(numberMatched, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x80, numberMatchedSize - 2, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(numberMatched, buffer, bufPos); - bufPos = BerEncoder_encodeTL(0x81, numberDeletedSize - 2, buffer, bufPos); - bufPos = BerEncoder_encodeUInt32(numberDeleted, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x81, numberDeletedSize - 2, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(numberDeleted, buffer, bufPos); - response->size = bufPos; + response->size = bufPos; } static void /* Confirmed service error (ServiceError) */ createServiceErrorDeleteVariableLists(uint32_t invokeId, ByteBuffer* response, - MmsError errorType, uint32_t numberDeleted) + MmsError errorType, uint32_t numberDeleted) { - uint8_t buffer[8]; + uint8_t buffer[8]; - int size = BerEncoder_encodeUInt32WithTL(0x86, numberDeleted, buffer, 0); + int size = BerEncoder_encodeUInt32WithTL(0x86, numberDeleted, buffer, 0); - mmsServer_createServiceErrorPduWithServiceSpecificInfo(invokeId, response, errorType, - buffer, size); + mmsServer_createServiceErrorPduWithServiceSpecificInfo(invokeId, response, errorType, + buffer, size); } void @@ -118,38 +118,38 @@ mmsServer_handleDeleteNamedVariableListRequest(MmsServerConnection connection, uint32_t invokeId, ByteBuffer* response) { - (void)bufPos; - - DeleteNamedVariableListRequest_t* request = NULL; - MmsPdu_t* mmsPdu = NULL; - - asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu, (void**) &mmsPdu, buffer, maxBufPos); - - if (rval.code != RC_OK) { - mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); - goto exit_function; - } - - if ((mmsPdu->present == MmsPdu_PR_confirmedRequestPdu) && - (mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present - == ConfirmedServiceRequest_PR_deleteNamedVariableList)) - { - request = &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.deleteNamedVariableList); - } - else { - mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); - goto exit_function; - } + (void)bufPos; + + DeleteNamedVariableListRequest_t* request = NULL; + MmsPdu_t* mmsPdu = NULL; + + asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu, (void**) &mmsPdu, buffer, maxBufPos); + + if (rval.code != RC_OK) { + mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + goto exit_function; + } + + if ((mmsPdu->present == MmsPdu_PR_confirmedRequestPdu) && + (mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present + == ConfirmedServiceRequest_PR_deleteNamedVariableList)) + { + request = &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.deleteNamedVariableList); + } + else { + mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + goto exit_function; + } long scopeOfDelete = DeleteNamedVariableListRequest__scopeOfDelete_specific; if (request->scopeOfDelete) - asn_INTEGER2long(request->scopeOfDelete, &scopeOfDelete); + asn_INTEGER2long(request->scopeOfDelete, &scopeOfDelete); MmsDevice* device = MmsServer_getDevice(connection->server); if (scopeOfDelete == DeleteNamedVariableListRequest__scopeOfDelete_specific) { - MmsError serviceError = MMS_ERROR_NONE; + MmsError serviceError = MMS_ERROR_NONE; int numberMatched = 0; int numberDeleted = 0; @@ -160,43 +160,43 @@ mmsServer_handleDeleteNamedVariableListRequest(MmsServerConnection connection, for (i = 0; i < numberItems; i++) { if (request->listOfVariableListName->list.array[i]->present == ObjectName_PR_domainspecific) { - char domainName[65]; - char listName[65]; + char domainName[65]; + char listName[65]; - mmsMsg_copyAsn1IdentifierToStringBuffer(request->listOfVariableListName->list.array[i]->choice.domainspecific.domainId, - domainName, 65); + mmsMsg_copyAsn1IdentifierToStringBuffer(request->listOfVariableListName->list.array[i]->choice.domainspecific.domainId, + domainName, 65); - mmsMsg_copyAsn1IdentifierToStringBuffer(request->listOfVariableListName->list.array[i]->choice.domainspecific.itemId, - listName, 65); + mmsMsg_copyAsn1IdentifierToStringBuffer(request->listOfVariableListName->list.array[i]->choice.domainspecific.itemId, + listName, 65); - MmsDomain* domain = MmsDevice_getDomain(device, domainName); + MmsDomain* domain = MmsDevice_getDomain(device, domainName); - if (domain != NULL) { + if (domain != NULL) { - MmsNamedVariableList variableList = MmsDomain_getNamedVariableList(domain, listName); + MmsNamedVariableList variableList = MmsDomain_getNamedVariableList(domain, listName); - if (variableList != NULL) { - numberMatched++; + if (variableList != NULL) { + numberMatched++; - if (MmsNamedVariableList_isDeletable(variableList)) { + if (MmsNamedVariableList_isDeletable(variableList)) { - MmsError deleteError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_DELETE, MMS_DOMAIN_SPECIFIC, domain, listName, connection); + MmsError deleteError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_DELETE, MMS_DOMAIN_SPECIFIC, domain, listName, connection); - if (deleteError == MMS_ERROR_NONE) { - MmsDomain_deleteNamedVariableList(domain, listName); - numberDeleted++; - } - else - serviceError = deleteError; - } - } - } + if (deleteError == MMS_ERROR_NONE) { + MmsDomain_deleteNamedVariableList(domain, listName); + numberDeleted++; + } + else + serviceError = deleteError; + } + } + } } else if (request->listOfVariableListName->list.array[i]->present == ObjectName_PR_aaspecific) { - char listName[65]; + char listName[65]; - mmsMsg_copyAsn1IdentifierToStringBuffer(request->listOfVariableListName->list.array[i]->choice.aaspecific, - listName, 65); + mmsMsg_copyAsn1IdentifierToStringBuffer(request->listOfVariableListName->list.array[i]->choice.aaspecific, + listName, 65); MmsNamedVariableList variableList = MmsServerConnection_getNamedVariableList(connection, listName); @@ -206,40 +206,40 @@ mmsServer_handleDeleteNamedVariableListRequest(MmsServerConnection connection, MmsError deleteError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_DELETE, MMS_ASSOCIATION_SPECIFIC, NULL, listName, connection); if (deleteError == MMS_ERROR_NONE) { - numberDeleted++; - MmsServerConnection_deleteNamedVariableList(connection, listName); + numberDeleted++; + MmsServerConnection_deleteNamedVariableList(connection, listName); } else - serviceError = deleteError; + serviceError = deleteError; } } else if (request->listOfVariableListName->list.array[i]->present == ObjectName_PR_vmdspecific) { - char listName[65]; + char listName[65]; - mmsMsg_copyAsn1IdentifierToStringBuffer(request->listOfVariableListName->list.array[i]->choice.vmdspecific, - listName, 65); + mmsMsg_copyAsn1IdentifierToStringBuffer(request->listOfVariableListName->list.array[i]->choice.vmdspecific, + listName, 65); - MmsNamedVariableList variableList = mmsServer_getNamedVariableListWithName(device->namedVariableLists, listName); + MmsNamedVariableList variableList = mmsServer_getNamedVariableListWithName(device->namedVariableLists, listName); - if (variableList != NULL) { - numberMatched++; + if (variableList != NULL) { + numberMatched++; - MmsError deleteError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_DELETE, MMS_VMD_SPECIFIC, NULL, listName, connection); + MmsError deleteError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_DELETE, MMS_VMD_SPECIFIC, NULL, listName, connection); - if (deleteError == MMS_ERROR_NONE) { - numberDeleted++; - mmsServer_deleteVariableList(device->namedVariableLists, listName); - } - else - serviceError = deleteError; - } + if (deleteError == MMS_ERROR_NONE) { + numberDeleted++; + mmsServer_deleteVariableList(device->namedVariableLists, listName); + } + else + serviceError = deleteError; + } } } if (serviceError == MMS_ERROR_NONE) - createDeleteNamedVariableListResponse(invokeId, response, numberMatched, numberDeleted); + createDeleteNamedVariableListResponse(invokeId, response, numberMatched, numberDeleted); else - createServiceErrorDeleteVariableLists(invokeId, response, serviceError, numberDeleted); + createServiceErrorDeleteVariableLists(invokeId, response, serviceError, numberDeleted); } else { mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED); @@ -247,61 +247,61 @@ mmsServer_handleDeleteNamedVariableListRequest(MmsServerConnection connection, exit_function: - asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); - return; + return; } static void createDefineNamedVariableListResponse(uint32_t invokeId, ByteBuffer* response) { - uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize((uint32_t) invokeId) + 2; + uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize((uint32_t) invokeId) + 2; - uint32_t confirmedResponsePDUSize = 2 + invokeIdSize; + uint32_t confirmedResponsePDUSize = 2 + invokeIdSize; - int bufPos = 0; - uint8_t* buffer = response->buffer; + int bufPos = 0; + uint8_t* buffer = response->buffer; - bufPos = BerEncoder_encodeTL(0xa1, confirmedResponsePDUSize, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0xa1, confirmedResponsePDUSize, buffer, bufPos); - bufPos = BerEncoder_encodeTL(0x02, invokeIdSize - 2, buffer, bufPos); - bufPos = BerEncoder_encodeUInt32(invokeId, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x02, invokeIdSize - 2, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(invokeId, buffer, bufPos); - bufPos = BerEncoder_encodeTL(0x8b, 0, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x8b, 0, buffer, bufPos); - response->size = bufPos; + response->size = bufPos; } static bool checkIfVariableExists(MmsDevice* device, MmsAccessSpecifier* accessSpecifier) { - (void)device; + (void)device; - if (accessSpecifier->domain == NULL) - return false; + if (accessSpecifier->domain == NULL) + return false; - MmsVariableSpecification* variableSpec = - MmsDomain_getNamedVariable(accessSpecifier->domain, accessSpecifier->variableName); + MmsVariableSpecification* variableSpec = + MmsDomain_getNamedVariable(accessSpecifier->domain, accessSpecifier->variableName); - if (variableSpec == NULL) - return false; + if (variableSpec == NULL) + return false; - if (accessSpecifier->arrayIndex != -1) { - if (variableSpec->type != MMS_ARRAY) - return false; + if (accessSpecifier->arrayIndex != -1) { + if (variableSpec->type != MMS_ARRAY) + return false; - if (accessSpecifier->arrayIndex >= variableSpec->typeSpec.array.elementCount) - return false; + if (accessSpecifier->arrayIndex >= variableSpec->typeSpec.array.elementCount) + return false; - if (accessSpecifier->componentName != NULL) { - variableSpec = variableSpec->typeSpec.array.elementTypeSpec; + if (accessSpecifier->componentName != NULL) { + variableSpec = variableSpec->typeSpec.array.elementTypeSpec; - if (MmsVariableSpecification_getNamedVariableRecursive(variableSpec, accessSpecifier->componentName) == NULL) - return false; - } - } + if (MmsVariableSpecification_getNamedVariableRecursive(variableSpec, accessSpecifier->componentName) == NULL) + return false; + } + } - return true; + return true; } static MmsNamedVariableList @@ -309,20 +309,20 @@ createNamedVariableList(MmsServer server, MmsDomain* domain, MmsDevice* device, DefineNamedVariableListRequest_t* request, char* variableListName, MmsError* mmsError) { - MmsNamedVariableList namedVariableList = NULL; + MmsNamedVariableList namedVariableList = NULL; int variableCount = request->listOfVariable.list.count; if (DEBUG_MMS_SERVER) - printf("MMS_SERVER: create-named-variable-list (%i variable(s) | max=%i)\n", variableCount, server->maxDataSetEntries); + printf("MMS_SERVER: create-named-variable-list (%i variable(s) | max=%i)\n", variableCount, server->maxDataSetEntries); #if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) if ((variableCount == 0 ) || (variableCount > server->maxDataSetEntries)) { #else if ((variableCount == 0 ) || (variableCount > CONFIG_MMS_MAX_NUMBER_OF_DATA_SET_MEMBERS)) { #endif - *mmsError = MMS_ERROR_DEFINITION_OTHER; - goto exit_function; + *mmsError = MMS_ERROR_DEFINITION_OTHER; + goto exit_function; } namedVariableList = MmsNamedVariableList_create(domain, variableListName, true); @@ -342,8 +342,8 @@ createNamedVariableList(MmsServer server, MmsDomain* domain, MmsDevice* device, if (request->listOfVariable.list.array[i]->alternateAccess->list.count != 1) { - if (DEBUG_MMS_SERVER) - printf("MMS_SERVER: create-named-variable list - only one alternate access specification allowed!\n"); + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: create-named-variable list - only one alternate access specification allowed!\n"); MmsNamedVariableList_destroy(namedVariableList); namedVariableList = NULL; @@ -355,31 +355,31 @@ createNamedVariableList(MmsServer server, MmsDomain* domain, MmsDevice* device, request->listOfVariable.list.array[i]->alternateAccess->list.array[0]; if ((alternateAccess->present == AlternateAccess__Member_PR_unnamed) - && (alternateAccess->choice.unnamed->present == AlternateAccessSelection_PR_selectAlternateAccess) - && (alternateAccess->choice.unnamed->choice.selectAlternateAccess.accessSelection.present == - AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_index)) + && (alternateAccess->choice.unnamed->present == AlternateAccessSelection_PR_selectAlternateAccess) + && (alternateAccess->choice.unnamed->choice.selectAlternateAccess.accessSelection.present == + AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_index)) { asn_INTEGER2long(&(alternateAccess->choice.unnamed->choice.selectAlternateAccess.accessSelection.choice.index), &arrayIndex); if (alternateAccess->choice.unnamed->choice.selectAlternateAccess.alternateAccess) { - componentNameBuf[0] = 0; + componentNameBuf[0] = 0; - componentName = mmsMsg_getComponentNameFromAlternateAccess( - alternateAccess->choice.unnamed->choice.selectAlternateAccess.alternateAccess, - componentNameBuf, 0); + componentName = mmsMsg_getComponentNameFromAlternateAccess( + alternateAccess->choice.unnamed->choice.selectAlternateAccess.alternateAccess, + componentNameBuf, 0); + } + else { + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: create-named-variable-list - component specification is missing!\n"); } - else { - if (DEBUG_MMS_SERVER) - printf("MMS_SERVER: create-named-variable-list - component specification is missing!\n"); - } } else if ((alternateAccess->present == AlternateAccess__Member_PR_unnamed) - && (alternateAccess->choice.unnamed->present == AlternateAccessSelection_PR_selectAccess) - && (alternateAccess->choice.unnamed->choice.selectAccess.present == AlternateAccessSelection__selectAccess_PR_index) - ) + && (alternateAccess->choice.unnamed->present == AlternateAccessSelection_PR_selectAccess) + && (alternateAccess->choice.unnamed->choice.selectAccess.present == AlternateAccessSelection__selectAccess_PR_index) + ) { - asn_INTEGER2long(&(alternateAccess->choice.unnamed->choice.selectAccess.choice.index), &arrayIndex); + asn_INTEGER2long(&(alternateAccess->choice.unnamed->choice.selectAccess.choice.index), &arrayIndex); } else { MmsNamedVariableList_destroy(namedVariableList); @@ -392,16 +392,16 @@ createNamedVariableList(MmsServer server, MmsDomain* domain, MmsDevice* device, if (varSpec->present == VariableSpecification_PR_name) { - char variableName[65]; - char domainId[65]; + char variableName[65]; + char domainId[65]; - StringUtils_createStringFromBufferInBuffer(variableName, - varSpec->choice.name.choice.domainspecific.itemId.buf, - varSpec->choice.name.choice.domainspecific.itemId.size); + StringUtils_createStringFromBufferInBuffer(variableName, + varSpec->choice.name.choice.domainspecific.itemId.buf, + varSpec->choice.name.choice.domainspecific.itemId.size); - StringUtils_createStringFromBufferInBuffer(domainId, - varSpec->choice.name.choice.domainspecific.domainId.buf, - varSpec->choice.name.choice.domainspecific.domainId.size); + StringUtils_createStringFromBufferInBuffer(domainId, + varSpec->choice.name.choice.domainspecific.domainId.buf, + varSpec->choice.name.choice.domainspecific.domainId.size); MmsDomain* elementDomain = MmsDevice_getDomain(device, domainId); @@ -413,24 +413,24 @@ createNamedVariableList(MmsServer server, MmsDomain* domain, MmsDevice* device, accessSpecifier.componentName = componentName; if (DEBUG_MMS_SERVER) - printf("MMS SERVER: add named variable list entry: %s/%s(%li)%s\n", MmsDomain_getName(elementDomain), variableName, arrayIndex, componentName); + printf("MMS SERVER: add named variable list entry: %s/%s(%li)%s\n", MmsDomain_getName(elementDomain), variableName, arrayIndex, componentName); /* check if element exists */ if (checkIfVariableExists(device, &accessSpecifier) == true) { - MmsNamedVariableListEntry variable = - MmsNamedVariableListEntry_create(accessSpecifier); + MmsNamedVariableListEntry variable = + MmsNamedVariableListEntry_create(accessSpecifier); - MmsNamedVariableList_addVariable(namedVariableList, variable); + MmsNamedVariableList_addVariable(namedVariableList, variable); } else { - if (DEBUG_MMS_SERVER) - printf("MMS_SERVER: failed - variable does not exist!\n"); + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: failed - variable does not exist!\n"); - MmsNamedVariableList_destroy(namedVariableList); - namedVariableList = NULL; - i = variableCount; /* exit loop after freeing loop variables */ - *mmsError = MMS_ERROR_DEFINITION_OBJECT_UNDEFINED; + MmsNamedVariableList_destroy(namedVariableList); + namedVariableList = NULL; + i = variableCount; /* exit loop after freeing loop variables */ + *mmsError = MMS_ERROR_DEFINITION_OBJECT_UNDEFINED; } } else { @@ -453,7 +453,7 @@ mmsServer_handleDefineNamedVariableListRequest( uint32_t invokeId, ByteBuffer* response) { - (void)bufPos; + (void)bufPos; DefineNamedVariableListRequest_t* request = 0; @@ -462,177 +462,177 @@ mmsServer_handleDefineNamedVariableListRequest( asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu, (void**) &mmsPdu, buffer, maxBufPos); if (rval.code != RC_OK) { - mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); - goto exit_free_struct; + mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + goto exit_free_struct; } - if ((mmsPdu->present == MmsPdu_PR_confirmedRequestPdu) && - (mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present - == ConfirmedServiceRequest_PR_defineNamedVariableList)) - { - request = &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.defineNamedVariableList); - } - else { - mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); - goto exit_free_struct; - } + if ((mmsPdu->present == MmsPdu_PR_confirmedRequestPdu) && + (mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present + == ConfirmedServiceRequest_PR_defineNamedVariableList)) + { + request = &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.defineNamedVariableList); + } + else { + mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + goto exit_free_struct; + } - MmsDevice* device = MmsServer_getDevice(connection->server); + MmsDevice* device = MmsServer_getDevice(connection->server); - if (request->variableListName.present == ObjectName_PR_domainspecific) { + if (request->variableListName.present == ObjectName_PR_domainspecific) { - char domainName[65]; + char domainName[65]; - if (request->variableListName.choice.domainspecific.domainId.size > 64) { - mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); - goto exit_free_struct; - } + if (request->variableListName.choice.domainspecific.domainId.size > 64) { + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + goto exit_free_struct; + } - StringUtils_createStringFromBufferInBuffer(domainName, - request->variableListName.choice.domainspecific.domainId.buf, - request->variableListName.choice.domainspecific.domainId.size); + StringUtils_createStringFromBufferInBuffer(domainName, + request->variableListName.choice.domainspecific.domainId.buf, + request->variableListName.choice.domainspecific.domainId.size); - MmsDomain* domain = MmsDevice_getDomain(device, domainName); + MmsDomain* domain = MmsDevice_getDomain(device, domainName); - if (domain == NULL) { - mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); - goto exit_free_struct; - } + if (domain == NULL) { + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + goto exit_free_struct; + } #if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) - if (LinkedList_size(domain->namedVariableLists) < connection->server->maxDomainSpecificDataSets) { + if (LinkedList_size(domain->namedVariableLists) < connection->server->maxDomainSpecificDataSets) { #else - if (LinkedList_size(domain->namedVariableLists) < CONFIG_MMS_MAX_NUMBER_OF_DOMAIN_SPECIFIC_DATA_SETS) { + if (LinkedList_size(domain->namedVariableLists) < CONFIG_MMS_MAX_NUMBER_OF_DOMAIN_SPECIFIC_DATA_SETS) { #endif - char variableListName[65]; - - if (request->variableListName.choice.domainspecific.itemId.size > 64) { - mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); - goto exit_free_struct; - } - - StringUtils_createStringFromBufferInBuffer(variableListName, - request->variableListName.choice.domainspecific.itemId.buf, - request->variableListName.choice.domainspecific.itemId.size); - - if (MmsDomain_getNamedVariableList(domain, variableListName) != NULL) { - mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_DEFINITION_OBJECT_EXISTS); - } - else { - MmsError mmsError; - - MmsNamedVariableList namedVariableList = createNamedVariableList(connection->server, domain, device, - request, variableListName, &mmsError); - - if (namedVariableList != NULL) { - - mmsError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_CREATE, MMS_DOMAIN_SPECIFIC, domain, variableListName, connection); - - if (mmsError == MMS_ERROR_NONE) { - MmsDomain_addNamedVariableList(domain, namedVariableList); - createDefineNamedVariableListResponse(invokeId, response); - } - else { - MmsNamedVariableList_destroy(namedVariableList); - mmsMsg_createServiceErrorPdu(invokeId, response, mmsError); - } - } - else - mmsMsg_createServiceErrorPdu(invokeId, response, mmsError); - } + char variableListName[65]; + + if (request->variableListName.choice.domainspecific.itemId.size > 64) { + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + goto exit_free_struct; + } + + StringUtils_createStringFromBufferInBuffer(variableListName, + request->variableListName.choice.domainspecific.itemId.buf, + request->variableListName.choice.domainspecific.itemId.size); + + if (MmsDomain_getNamedVariableList(domain, variableListName) != NULL) { + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_DEFINITION_OBJECT_EXISTS); + } + else { + MmsError mmsError; + + MmsNamedVariableList namedVariableList = createNamedVariableList(connection->server, domain, device, + request, variableListName, &mmsError); + + if (namedVariableList != NULL) { + + mmsError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_CREATE, MMS_DOMAIN_SPECIFIC, domain, variableListName, connection); + + if (mmsError == MMS_ERROR_NONE) { + MmsDomain_addNamedVariableList(domain, namedVariableList); + createDefineNamedVariableListResponse(invokeId, response); + } + else { + MmsNamedVariableList_destroy(namedVariableList); + mmsMsg_createServiceErrorPdu(invokeId, response, mmsError); + } + } + else + mmsMsg_createServiceErrorPdu(invokeId, response, mmsError); + } } else - mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_CAPABILITY_UNAVAILABLE); + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_CAPABILITY_UNAVAILABLE); } else if (request->variableListName.present == ObjectName_PR_aaspecific) { #if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) - if (LinkedList_size(connection->namedVariableLists) < connection->server->maxAssociationSpecificDataSets) { + if (LinkedList_size(connection->namedVariableLists) < connection->server->maxAssociationSpecificDataSets) { #else - if (LinkedList_size(connection->namedVariableLists) < CONFIG_MMS_MAX_NUMBER_OF_ASSOCIATION_SPECIFIC_DATA_SETS) { + if (LinkedList_size(connection->namedVariableLists) < CONFIG_MMS_MAX_NUMBER_OF_ASSOCIATION_SPECIFIC_DATA_SETS) { #endif - char variableListName[65]; - - if (request->variableListName.choice.aaspecific.size > 64) { - mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response); - goto exit_free_struct; - } - - StringUtils_createStringFromBufferInBuffer(variableListName, - request->variableListName.choice.aaspecific.buf, - request->variableListName.choice.aaspecific.size); - - if (MmsServerConnection_getNamedVariableList(connection, variableListName) != NULL) { - mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_DEFINITION_OBJECT_EXISTS); - } - else { - MmsError mmsError; - - MmsNamedVariableList namedVariableList = createNamedVariableList(connection->server, NULL, device, - request, variableListName, &mmsError); - - if (namedVariableList != NULL) { - - if (mmsServer_callVariableListChangedHandler(MMS_VARLIST_CREATE, MMS_ASSOCIATION_SPECIFIC, NULL, variableListName, connection) == MMS_ERROR_NONE) { - MmsServerConnection_addNamedVariableList(connection, namedVariableList); - createDefineNamedVariableListResponse(invokeId, response); - } - else { - MmsNamedVariableList_destroy(namedVariableList); - mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED); - } - - } - else - mmsMsg_createServiceErrorPdu(invokeId, response, mmsError); - } - } - else - mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_CAPABILITY_UNAVAILABLE); + char variableListName[65]; + + if (request->variableListName.choice.aaspecific.size > 64) { + mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response); + goto exit_free_struct; + } + + StringUtils_createStringFromBufferInBuffer(variableListName, + request->variableListName.choice.aaspecific.buf, + request->variableListName.choice.aaspecific.size); + + if (MmsServerConnection_getNamedVariableList(connection, variableListName) != NULL) { + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_DEFINITION_OBJECT_EXISTS); + } + else { + MmsError mmsError; + + MmsNamedVariableList namedVariableList = createNamedVariableList(connection->server, NULL, device, + request, variableListName, &mmsError); + + if (namedVariableList != NULL) { + + if (mmsServer_callVariableListChangedHandler(MMS_VARLIST_CREATE, MMS_ASSOCIATION_SPECIFIC, NULL, variableListName, connection) == MMS_ERROR_NONE) { + MmsServerConnection_addNamedVariableList(connection, namedVariableList); + createDefineNamedVariableListResponse(invokeId, response); + } + else { + MmsNamedVariableList_destroy(namedVariableList); + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED); + } + + } + else + mmsMsg_createServiceErrorPdu(invokeId, response, mmsError); + } + } + else + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_CAPABILITY_UNAVAILABLE); } else if (request->variableListName.present == ObjectName_PR_vmdspecific) { - LinkedList vmdScopeNVLs = MmsDevice_getNamedVariableLists(connection->server->device); + LinkedList vmdScopeNVLs = MmsDevice_getNamedVariableLists(connection->server->device); - if (LinkedList_size(vmdScopeNVLs) < CONFIG_MMS_MAX_NUMBER_OF_VMD_SPECIFIC_DATA_SETS) { + if (LinkedList_size(vmdScopeNVLs) < CONFIG_MMS_MAX_NUMBER_OF_VMD_SPECIFIC_DATA_SETS) { - char variableListName[65]; + char variableListName[65]; - if (request->variableListName.choice.vmdspecific.size > 64) { - mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response); - goto exit_free_struct; - } + if (request->variableListName.choice.vmdspecific.size > 64) { + mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response); + goto exit_free_struct; + } - StringUtils_createStringFromBufferInBuffer(variableListName, - request->variableListName.choice.vmdspecific.buf, - request->variableListName.choice.vmdspecific.size); + StringUtils_createStringFromBufferInBuffer(variableListName, + request->variableListName.choice.vmdspecific.buf, + request->variableListName.choice.vmdspecific.size); - if (mmsServer_getNamedVariableListWithName(MmsDevice_getNamedVariableLists(connection->server->device), variableListName) != NULL) { - mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_DEFINITION_OBJECT_EXISTS); - } - else { - MmsError mmsError; + if (mmsServer_getNamedVariableListWithName(MmsDevice_getNamedVariableLists(connection->server->device), variableListName) != NULL) { + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_DEFINITION_OBJECT_EXISTS); + } + else { + MmsError mmsError; - MmsNamedVariableList namedVariableList = createNamedVariableList(connection->server, NULL, device, - request, variableListName, &mmsError); + MmsNamedVariableList namedVariableList = createNamedVariableList(connection->server, NULL, device, + request, variableListName, &mmsError); - if (namedVariableList != NULL) { - if (mmsServer_callVariableListChangedHandler(MMS_VARLIST_CREATE, MMS_VMD_SPECIFIC, NULL, variableListName, connection) - == MMS_ERROR_NONE) { - LinkedList_add(vmdScopeNVLs, (void*) namedVariableList); + if (namedVariableList != NULL) { + if (mmsServer_callVariableListChangedHandler(MMS_VARLIST_CREATE, MMS_VMD_SPECIFIC, NULL, variableListName, connection) + == MMS_ERROR_NONE) { + LinkedList_add(vmdScopeNVLs, (void*) namedVariableList); - createDefineNamedVariableListResponse(invokeId, response); - } - else { - MmsNamedVariableList_destroy(namedVariableList); - mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED); - } + createDefineNamedVariableListResponse(invokeId, response); + } + else { + MmsNamedVariableList_destroy(namedVariableList); + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED); + } - } - } - } + } + } + } } else mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_DEFINITION_TYPE_UNSUPPORTED); @@ -640,7 +640,7 @@ mmsServer_handleDefineNamedVariableListRequest( exit_free_struct: asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); - return; + return; } #endif /* (MMS_DYNAMIC_DATA_SETS == 1) */ @@ -670,7 +670,7 @@ createGetNamedVariableListAttributesResponse(int invokeId, ByteBuffer* response, varListResponse->listOfVariable.list.size = variableCount; varListResponse->listOfVariable.list.array = (struct GetNamedVariableListAttributesResponse__listOfVariable__Member**) - GLOBAL_CALLOC(variableCount, sizeof(void*)); + GLOBAL_CALLOC(variableCount, sizeof(void*)); LinkedList variable = LinkedList_getNext(variables); @@ -679,7 +679,7 @@ createGetNamedVariableListAttributesResponse(int invokeId, ByteBuffer* response, MmsNamedVariableListEntry variableEntry = (MmsNamedVariableListEntry) variable->data; varListResponse->listOfVariable.list.array[i] = (struct GetNamedVariableListAttributesResponse__listOfVariable__Member*) - GLOBAL_CALLOC(1, sizeof(struct GetNamedVariableListAttributesResponse__listOfVariable__Member)); + GLOBAL_CALLOC(1, sizeof(struct GetNamedVariableListAttributesResponse__listOfVariable__Member)); varListResponse->listOfVariable.list.array[i]->variableSpecification.present = VariableSpecification_PR_name; @@ -702,12 +702,12 @@ createGetNamedVariableListAttributesResponse(int invokeId, ByteBuffer* response, domainspecific.itemId.size = strlen(variableEntry->variableName); if (variableEntry->arrayIndex != -1) { - varListResponse->listOfVariable.list.array[i]->alternateAccess = - mmsClient_createAlternateAccessIndexComponent(variableEntry->arrayIndex, variableEntry->componentName); + varListResponse->listOfVariable.list.array[i]->alternateAccess = + mmsClient_createAlternateAccessIndexComponent(variableEntry->arrayIndex, variableEntry->componentName); } else if (variableEntry->componentName) { - varListResponse->listOfVariable.list.array[i]->alternateAccess = - mmsClient_createAlternateAccessComponent(variableEntry->componentName); + varListResponse->listOfVariable.list.array[i]->alternateAccess = + mmsClient_createAlternateAccessComponent(variableEntry->componentName); } variable = LinkedList_getNext(variable); @@ -718,9 +718,9 @@ createGetNamedVariableListAttributesResponse(int invokeId, ByteBuffer* response, asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); if (res.encoded == -1) - return false; + return false; else - return true; + return true; } void @@ -736,44 +736,53 @@ mmsServer_handleGetNamedVariableListAttributesRequest( (void**) &request, buffer + bufPos, maxBufPos - bufPos); if (rval.code != RC_OK) { - mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); - goto exit_function; + mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + goto exit_function; } if (request->present == ObjectName_PR_domainspecific) { - char domainName[65]; - char itemName[65]; + char domainName[65]; + char itemName[65]; - if ((request->choice.domainspecific.domainId.size > 64) || - (request->choice.domainspecific.itemId.size > 64)) { - mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OTHER); - goto exit_function; - } + if ((request->choice.domainspecific.domainId.size > 64) || + (request->choice.domainspecific.itemId.size > 64)) { + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OTHER); + goto exit_function; + } - StringUtils_createStringFromBufferInBuffer(domainName, request->choice.domainspecific.domainId.buf, - request->choice.domainspecific.domainId.size); + StringUtils_createStringFromBufferInBuffer(domainName, request->choice.domainspecific.domainId.buf, + request->choice.domainspecific.domainId.size); - StringUtils_createStringFromBufferInBuffer(itemName, request->choice.domainspecific.itemId.buf, - request->choice.domainspecific.itemId.size); + StringUtils_createStringFromBufferInBuffer(itemName, request->choice.domainspecific.itemId.buf, + request->choice.domainspecific.itemId.size); MmsDevice* mmsDevice = MmsServer_getDevice(connection->server); MmsDomain* domain = MmsDevice_getDomain(mmsDevice, domainName); if (domain != NULL) { - MmsNamedVariableList variableList = - MmsDomain_getNamedVariableList(domain, itemName); + MmsNamedVariableList varList = MmsDomain_getNamedVariableList(domain, itemName); - if (variableList != NULL) { + if (varList) { - if (createGetNamedVariableListAttributesResponse(invokeId, response, variableList) == false) { + MmsError accessError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_GET_DIRECTORY, MMS_DOMAIN_SPECIFIC, domain, varList->name, connection); - /* encoding failed - probably because buffer size is too small for message */ - ByteBuffer_setSize(response, 0); + if (accessError == MMS_ERROR_NONE) { + if (createGetNamedVariableListAttributesResponse(invokeId, response, varList) == false) { - mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_OTHER); + /* encoding failed - probably because buffer size is too small for message */ + ByteBuffer_setSize(response, 0); + + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_OTHER); + } + } + else { + if (DEBUG_MMS_SERVER) printf("MMS get named variable list attributes: variable list %s access error: %i\n", varList->name, accessError); + + mmsMsg_createServiceErrorPdu(invokeId, response, accessError); } + } else mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); @@ -785,43 +794,77 @@ mmsServer_handleGetNamedVariableListAttributesRequest( #if (MMS_DYNAMIC_DATA_SETS == 1) else if (request->present == ObjectName_PR_aaspecific) { - char listName[65]; + char listName[65]; - if (request->choice.aaspecific.size > 64) { - mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OTHER); - goto exit_function; - } + if (request->choice.aaspecific.size > 64) { + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OTHER); + goto exit_function; + } + + StringUtils_createStringFromBufferInBuffer(listName, request->choice.aaspecific.buf, + request->choice.aaspecific.size); + + MmsNamedVariableList varList = MmsServerConnection_getNamedVariableList(connection, listName); + + if (varList) { + + MmsError accessError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_GET_DIRECTORY, MMS_ASSOCIATION_SPECIFIC, NULL, varList->name, connection); - StringUtils_createStringFromBufferInBuffer(listName, request->choice.aaspecific.buf, - request->choice.aaspecific.size); + if (accessError == MMS_ERROR_NONE) { + if (createGetNamedVariableListAttributesResponse(invokeId, response, varList) == false) { - MmsNamedVariableList varList = MmsServerConnection_getNamedVariableList(connection, listName); + /* encoding failed - probably because buffer size is too small for message */ + ByteBuffer_setSize(response, 0); - if (varList != NULL) - createGetNamedVariableListAttributesResponse(invokeId, response, varList); - else - mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_OTHER); + } + } + else { + if (DEBUG_MMS_SERVER) printf("MMS get named variable list attributes: variable list %s access error: %i\n", varList->name, accessError); + + mmsMsg_createServiceErrorPdu(invokeId, response, accessError); + } + } + else + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); } #endif /* (MMS_DYNAMIC_DATA_SETS == 1) */ else if (request->present == ObjectName_PR_vmdspecific) { - char listName[65]; + char listName[65]; + + if (request->choice.vmdspecific.size > 64) { + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OTHER); + goto exit_function; + } + + StringUtils_createStringFromBufferInBuffer(listName, request->choice.vmdspecific.buf, + request->choice.vmdspecific.size); + + MmsDevice* mmsDevice = MmsServer_getDevice(connection->server); - if (request->choice.vmdspecific.size > 64) { - mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OTHER); - goto exit_function; - } + MmsNamedVariableList varList = mmsServer_getNamedVariableListWithName(mmsDevice->namedVariableLists, listName); - StringUtils_createStringFromBufferInBuffer(listName, request->choice.vmdspecific.buf, - request->choice.vmdspecific.size); + if (varList) { - MmsDevice* mmsDevice = MmsServer_getDevice(connection->server); + MmsError accessError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_GET_DIRECTORY, MMS_VMD_SPECIFIC, NULL, varList->name, connection); - MmsNamedVariableList varList = mmsServer_getNamedVariableListWithName(mmsDevice->namedVariableLists, listName); + if (accessError == MMS_ERROR_NONE) { + if (createGetNamedVariableListAttributesResponse(invokeId, response, varList) == false) { - if (varList != NULL) - createGetNamedVariableListAttributesResponse(invokeId, response, varList); - else - mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + /* encoding failed - probably because buffer size is too small for message */ + ByteBuffer_setSize(response, 0); + + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_OTHER); + } + } + else { + if (DEBUG_MMS_SERVER) printf("MMS get named variable list attributes: variable list %s access error: %i\n", varList->name, accessError); + + mmsMsg_createServiceErrorPdu(invokeId, response, accessError); + } + } + else + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); } else { mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED); diff --git a/src/mms/iso_mms/server/mms_write_service.c b/src/mms/iso_mms/server/mms_write_service.c index 11306e4d..6a9d909f 100644 --- a/src/mms/iso_mms/server/mms_write_service.c +++ b/src/mms/iso_mms/server/mms_write_service.c @@ -1,7 +1,7 @@ /* * mms_write_service.c * - * Copyright 2013-2022 Michael Zillgith + * Copyright 2013-2023 Michael Zillgith * * This file is part of libIEC61850. * @@ -430,8 +430,19 @@ handleWriteNamedVariableListRequest( else { MmsNamedVariableList namedList = MmsDomain_getNamedVariableList(domain, nameIdStr); - if (namedList != NULL) { - createWriteNamedVariableListResponse(connection, writeRequest, invokeId, namedList, response); + if (namedList) { + + MmsError accessError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_WRITE, MMS_DOMAIN_SPECIFIC, domain, namedList->name, connection); + + if (accessError == MMS_ERROR_NONE) { + createWriteNamedVariableListResponse(connection, writeRequest, invokeId, namedList, response); + } + else { + if (DEBUG_MMS_SERVER) printf("MMS write: named variable list %s access error: %i\n", nameIdStr, accessError); + + mmsMsg_createServiceErrorPdu(invokeId, response, accessError); + } + } else { if (DEBUG_MMS_SERVER) printf("MMS write: named variable list %s not found!\n", nameIdStr); @@ -448,8 +459,19 @@ handleWriteNamedVariableListRequest( MmsNamedVariableList namedList = mmsServer_getNamedVariableListWithName(connection->server->device->namedVariableLists, listName); - if (namedList != NULL) { - createWriteNamedVariableListResponse(connection, writeRequest, invokeId, namedList, response); + if (namedList) { + + MmsError accessError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_WRITE, MMS_VMD_SPECIFIC, NULL, namedList->name, connection); + + if (accessError == MMS_ERROR_NONE) { + createWriteNamedVariableListResponse(connection, writeRequest, invokeId, namedList, response); + } + else { + if (DEBUG_MMS_SERVER) printf("MMS write: vmd specific named variable list %s access error: %i\n", namedList->name, accessError); + + mmsMsg_createServiceErrorPdu(invokeId, response, accessError); + } + } else { if (DEBUG_MMS_SERVER) printf("MMS write: vmd specific named variable list %s not found!\n", listName); @@ -465,8 +487,19 @@ handleWriteNamedVariableListRequest( MmsNamedVariableList namedList = MmsServerConnection_getNamedVariableList(connection, listName); - if (namedList != NULL) { - createWriteNamedVariableListResponse(connection, writeRequest, invokeId, namedList, response); + if (namedList) { + + MmsError accessError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_WRITE, MMS_ASSOCIATION_SPECIFIC, NULL, namedList->name, connection); + + if (accessError == MMS_ERROR_NONE) { + createWriteNamedVariableListResponse(connection, writeRequest, invokeId, namedList, response); + } + else { + if (DEBUG_MMS_SERVER) printf("MMS write: association specific named variable list %s access error: %i\n", namedList->name, accessError); + + mmsMsg_createServiceErrorPdu(invokeId, response, accessError); + } + } else { if (DEBUG_MMS_SERVER) printf("MMS write: association specific named variable list %s not found!\n", listName); From 76dbcb4496d46ceb5b981788c4520dedb7438b25 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Sat, 4 Mar 2023 08:43:14 +0000 Subject: [PATCH 4/9] - IED server: Implemented read/write access control to RCBs (LIB61850-391) --- .../server_example_access_control.c | 13 +++++++ src/iec61850/inc/iec61850_server.h | 24 +++++++++++++ .../inc_private/mms_mapping_internal.h | 3 ++ src/iec61850/inc_private/reporting.h | 2 +- src/iec61850/server/impl/ied_server.c | 7 ++++ src/iec61850/server/mms_mapping/reporting.c | 35 ++++++++++++++++--- 6 files changed, 78 insertions(+), 6 deletions(-) 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 024bf77a..dcb93d0f 100644 --- a/examples/server_example_access_control/server_example_access_control.c +++ b/examples/server_example_access_control/server_example_access_control.c @@ -75,6 +75,17 @@ connectionHandler (IedServer self, ClientConnection connection, bool connected, printf("Connection closed\n"); } +/* + * This handler is called before the rcbEventHandler and can be use to allow or permit read or write access to the RCB + */ +bool +rcbAccessHandler(void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType operation) +{ + printf("RCB: %s access: %s\n", ReportControlBlock_getName(rcb), operation == RCB_EVENT_GET_PARAMETER ? "READ" : "WRITE"); + + return false; +} + static void rcbEventHandler(void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType event, const char* parameterName, MmsDataAccessError serviceError) { @@ -167,6 +178,8 @@ main(int argc, char** argv) IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL); + IedServer_setRCBAccessHandler(iedServer, rcbAccessHandler, NULL); + IedServer_setRCBEventHandler(iedServer, rcbEventHandler, NULL); /* By default access to variables with FC=DC and FC=CF is not allowed. diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index 9d34084c..93bb02e2 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -1622,6 +1622,30 @@ typedef void (*IedServer_RCBEventHandler) (void* parameter, ReportControlBlock* LIB61850_API void IedServer_setRCBEventHandler(IedServer self, IedServer_RCBEventHandler handler, void* parameter); + +/** + * \brief Callback that is called in case of RCB access to give the user the opportunity to block or allow the operation + * + * \note This callback is called before the IedServer_RCBEventHandler and only in case of operations (RCB_EVENT_GET_PARAMETER, RCB_EVENT_SET_PARAMETER, RCB_EVENT_ENABLE + * + * \param parameter user provided parameter + * \param rcb affected report control block + * \param connection client connection that is involved + * \param operation one of the following operation event types: RCB_EVENT_GET_PARAMETER, RCB_EVENT_SET_PARAMETER + */ +typedef bool +(*IedServer_RCBAccessHandler) (void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType operation); + +/** + * \brief Set a handler to control read and write access to report control blocks (RCBs) + * + * \param self the instance of IedServer to operate on. + * \param handler the event handler to be used + * \param parameter a user provided parameter that is passed to the handler. + */ +LIB61850_API void +IedServer_setRCBAccessHandler(IedServer self, IedServer_RCBAccessHandler handler, void* parameter); + /**@}*/ /** diff --git a/src/iec61850/inc_private/mms_mapping_internal.h b/src/iec61850/inc_private/mms_mapping_internal.h index c22311f6..c42df272 100644 --- a/src/iec61850/inc_private/mms_mapping_internal.h +++ b/src/iec61850/inc_private/mms_mapping_internal.h @@ -335,6 +335,9 @@ struct sMmsMapping { IedServer_RCBEventHandler rcbEventHandler; void* rcbEventHandlerParameter; + IedServer_RCBAccessHandler rcbAccessHandler; + void* rcbAccessHandlerParameter; + IedServer_DataSetAccessHandler dataSetAccessHandler; void* dataSetAccessHandlerParameter; }; diff --git a/src/iec61850/inc_private/reporting.h b/src/iec61850/inc_private/reporting.h index a4e3433f..558343c2 100644 --- a/src/iec61850/inc_private/reporting.h +++ b/src/iec61850/inc_private/reporting.h @@ -140,7 +140,7 @@ LIB61850_INTERNAL MmsDataAccessError Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* elementName, MmsValue* value, MmsServerConnection connection); -LIB61850_INTERNAL void +LIB61850_INTERNAL bool ReportControl_readAccess(ReportControl* rc, MmsMapping* mmsMapping, MmsServerConnection connection, char* elementName); LIB61850_INTERNAL void diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index d748bf5a..c398e143 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -689,6 +689,13 @@ IedServer_setRCBEventHandler(IedServer self, IedServer_RCBEventHandler handler, self->mmsMapping->rcbEventHandlerParameter = parameter; } +void +IedServer_setRCBAccessHandler(IedServer self, IedServer_RCBAccessHandler handler, void* parameter) +{ + self->mmsMapping->rcbAccessHandler = handler; + self->mmsMapping->rcbAccessHandlerParameter = parameter; +} + void IedServer_destroy(IedServer self) { diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index 3b170a54..d0779138 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -1697,21 +1697,35 @@ checkReservationTimeout(MmsMapping* self, ReportControl* rc) } } -void +bool ReportControl_readAccess(ReportControl* rc, MmsMapping* mmsMapping, MmsServerConnection connection, char* elementName) { - (void)elementName; + bool accessAllowed = true; + MmsDataAccessError accessError = DATA_ACCESS_ERROR_SUCCESS; /* check reservation timeout */ if (rc->buffered) { checkReservationTimeout(mmsMapping, rc); } - if (mmsMapping->rcbEventHandler) { - ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(mmsMapping->iedServer, connection); + ClientConnection clientConnection = NULL; + + if (mmsMapping->rcbAccessHandler || mmsMapping->rcbEventHandler) { + clientConnection = private_IedServer_getClientConnectionByHandle(mmsMapping->iedServer, connection); + } + + if (mmsMapping->rcbAccessHandler) { + if (mmsMapping->rcbAccessHandler(mmsMapping->rcbAccessHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_GET_PARAMETER) == false) { + accessError = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + accessAllowed = false; + } + } - mmsMapping->rcbEventHandler(mmsMapping->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_GET_PARAMETER, elementName, DATA_ACCESS_ERROR_SUCCESS); + if (mmsMapping->rcbEventHandler) { + mmsMapping->rcbEventHandler(mmsMapping->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_GET_PARAMETER, elementName, accessError); } + + return accessAllowed; } static bool @@ -1809,6 +1823,15 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + /* check if write access to RCB is allowed on this connection */ + if (self->rcbAccessHandler) { + if (self->rcbAccessHandler(self->rcbAccessHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_SET_PARAMETER) == false) { + retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + + goto exit_function_only_tracking; + } + } + /* check reservation timeout for buffered RCBs */ if (rc->buffered) { @@ -2491,6 +2514,8 @@ exit_function: ReportControl_unlockNotify(rc); +exit_function_only_tracking: + #if (CONFIG_IEC61850_SERVICE_TRACKING == 1) if (rc->buffered) updateGenericTrackingObjectValues(self, rc, IEC61850_SERVICE_TYPE_SET_BRCB_VALUES, retVal); From dc5bd43f0fe87269275c81058df076c2f59e84a5 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Sun, 5 Mar 2023 08:25:02 +0000 Subject: [PATCH 5/9] - IED server: fixed read handling in RCB access control (LIB61850-391) --- .../server_example_access_control.c | 7 +++- src/iec61850/server/mms_mapping/mms_mapping.c | 35 +++++++++++-------- 2 files changed, 27 insertions(+), 15 deletions(-) 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 dcb93d0f..2d8bde93 100644 --- a/examples/server_example_access_control/server_example_access_control.c +++ b/examples/server_example_access_control/server_example_access_control.c @@ -83,7 +83,12 @@ rcbAccessHandler(void* parameter, ReportControlBlock* rcb, ClientConnection conn { printf("RCB: %s access: %s\n", ReportControlBlock_getName(rcb), operation == RCB_EVENT_GET_PARAMETER ? "READ" : "WRITE"); - return false; + if (operation == RCB_EVENT_GET_PARAMETER) { + return true; + } + else { + return false; + } } static void diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index a33e31b2..a91ace26 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -25,6 +25,7 @@ #include "mms_mapping.h" #include "mms_mapping_internal.h" #include "mms_server_internal.h" +#include "mms_value_internal.h" #include "stack_config.h" #include "mms_goose.h" @@ -68,6 +69,8 @@ typedef struct uint64_t reservationTimeout; } SettingGroup; +static MmsValue objectAccessDenied = {MMS_DATA_ACCESS_ERROR, false, {DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED}}; + #if (CONFIG_IEC61850_CONTROL_SERVICE == 1) bool @@ -3155,31 +3158,35 @@ mmsReadHandler(void* parameter, MmsDomain* domain, char* variableId, MmsServerCo continue; if (strlen(rc->name) == variableIdLen) { - if (strncmp(variableId, rc->name, variableIdLen) == 0) { - + if (strncmp(variableId, rc->name, variableIdLen) == 0) + { char* elementName = MmsMapping_getNextNameElement(reportName); - ReportControl_readAccess(rc, self, connection, elementName); - MmsValue* value = NULL; + if (ReportControl_readAccess(rc, self, connection, elementName)) + { #if (CONFIG_MMS_THREADLESS_STACK != 1) - Semaphore_wait(rc->rcbValuesLock); + Semaphore_wait(rc->rcbValuesLock); #endif - if (elementName != NULL) - value = ReportControl_getRCBValue(rc, elementName); - else - value = rc->rcbValues; + if (elementName != NULL) + value = ReportControl_getRCBValue(rc, elementName); + else + value = rc->rcbValues; - if (value) { - value = MmsValue_clone(value); - MmsValue_setDeletableRecursive(value); - } + if (value) { + value = MmsValue_clone(value); + MmsValue_setDeletableRecursive(value); + } #if (CONFIG_MMS_THREADLESS_STACK != 1) - Semaphore_post(rc->rcbValuesLock); + Semaphore_post(rc->rcbValuesLock); #endif + } + else { + value = &objectAccessDenied; + } retValue = value; From 41ed0dd51ae2f7a79ceba4b1b441fa4cf56e9e0e Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Fri, 10 Mar 2023 17:14:19 +0000 Subject: [PATCH 6/9] - implemented access control callbacks for logs and LCBs (LIB61850-392) --- CMakeLists.txt | 5 ++ .../server_example_access_control.c | 17 ++++- .../server_example_logging.c | 26 ++++++++ src/iec61850/inc/iec61850_dynamic_model.h | 6 ++ src/iec61850/inc/iec61850_server.h | 63 ++++++++++++------- src/iec61850/inc_private/logging.h | 2 +- .../inc_private/mms_mapping_internal.h | 6 ++ src/iec61850/server/impl/ied_server.c | 14 +++++ src/iec61850/server/mms_mapping/logging.c | 49 ++++++++++++--- src/iec61850/server/mms_mapping/mms_mapping.c | 35 +++++++++-- src/iec61850/server/model/dynamic_model.c | 12 ++++ src/mms/inc/mms_server.h | 20 ++++++ src/mms/inc_private/mms_server_internal.h | 3 + src/mms/iso_mms/server/mms_journal_service.c | 14 +++++ src/mms/iso_mms/server/mms_server.c | 7 +++ 15 files changed, 239 insertions(+), 40 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 28477596..80cb5d17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,6 +130,11 @@ set(USE_PREBUILD_MBEDTLS 1) set(MBEDTLS_INCLUDE_DIR ${CONFIG_EXTERNAL_MBEDTLS_INCLUDE_PATH}) endif(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB) +if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/sqlite/sqlite3.h) +set(FOUND_SQLITE3_SOURCE 1) +message("Found sqlite3 source in third_party folder -> can compile with log service support") +endif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/sqlite/sqlite3.h) + if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28) set(WITH_MBEDTLS 1) set(MBEDTLS_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28/include") 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 2d8bde93..7c18fd46 100644 --- a/examples/server_example_access_control/server_example_access_control.c +++ b/examples/server_example_access_control/server_example_access_control.c @@ -78,7 +78,7 @@ connectionHandler (IedServer self, ClientConnection connection, bool connected, /* * This handler is called before the rcbEventHandler and can be use to allow or permit read or write access to the RCB */ -bool +static bool rcbAccessHandler(void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType operation) { printf("RCB: %s access: %s\n", ReportControlBlock_getName(rcb), operation == RCB_EVENT_GET_PARAMETER ? "READ" : "WRITE"); @@ -91,6 +91,19 @@ rcbAccessHandler(void* parameter, ReportControlBlock* rcb, ClientConnection conn } } +static bool +lcbAccessHandler(void* parameter, LogControlBlock* lcb, ClientConnection connection, IedServer_LCBEventType operation) +{ + printf("LCB: %s access: %s\n", LogControlBlock_getName(lcb), operation == LCB_EVENT_GET_PARAMETER ? "READ" : "WRITE"); + + if (operation == LCB_EVENT_GET_PARAMETER) { + return true; + } + else { + return false; + } +} + static void rcbEventHandler(void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType event, const char* parameterName, MmsDataAccessError serviceError) { @@ -185,6 +198,8 @@ main(int argc, char** argv) IedServer_setRCBAccessHandler(iedServer, rcbAccessHandler, NULL); + IedServer_setLCBAccessHandler(iedServer, lcbAccessHandler, NULL); + IedServer_setRCBEventHandler(iedServer, rcbEventHandler, NULL); /* By default access to variables with FC=DC and FC=CF is not allowed. diff --git a/examples/server_example_logging/server_example_logging.c b/examples/server_example_logging/server_example_logging.c index 51c7a0df..ee388be8 100644 --- a/examples/server_example_logging/server_example_logging.c +++ b/examples/server_example_logging/server_example_logging.c @@ -115,6 +115,28 @@ entryDataCallback (void* parameter, const char* dataRef, const uint8_t* data, in return true; } +static bool +lcbAccessHandler(void* parameter, LogControlBlock* lcb, ClientConnection connection, IedServer_LCBEventType operation) +{ + printf("%s access to LCB %s from %s\n", operation == LCB_EVENT_GET_PARAMETER ? "read" : "write", LogControlBlock_getName(lcb), ClientConnection_getPeerAddress(connection)); + + /* only allow read access */ + if (operation == LCB_EVENT_GET_PARAMETER) { + return true; + } + else { + return false; + } +} + +static bool +logAccessHandler(void* parameter, const char* logName, ClientConnection connection) +{ + printf("Access to log %s from %s\n", logName, ClientConnection_getPeerAddress(connection)); + + return false; +} + int main(int argc, char** argv) { @@ -147,6 +169,10 @@ main(int argc, char** argv) IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL); + IedServer_setLCBAccessHandler(iedServer, lcbAccessHandler, NULL); + + IedServer_setLogAccessHandler(iedServer, logAccessHandler, NULL); + LogStorage statusLog = SqliteLogStorage_createInstance("log_status.db"); LogStorage_setMaxLogEntries(statusLog, 10); diff --git a/src/iec61850/inc/iec61850_dynamic_model.h b/src/iec61850/inc/iec61850_dynamic_model.h index 32f6ff04..693dc7f4 100644 --- a/src/iec61850/inc/iec61850_dynamic_model.h +++ b/src/iec61850/inc/iec61850_dynamic_model.h @@ -395,6 +395,12 @@ LIB61850_API LogControlBlock* LogControlBlock_create(const char* name, LogicalNode* parent, const char* dataSetName, const char* logRef, uint8_t trgOps, uint32_t intgPd, bool logEna, bool reasonCode); +LIB61850_API const char* +LogControlBlock_getName(LogControlBlock* self); + +LIB61850_API LogicalNode* +LogControlBlock_getParent(LogControlBlock* self); + /** * \brief create a log (used by the IEC 61850 log service) * diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index 93bb02e2..ec023b4d 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -1622,30 +1622,6 @@ typedef void (*IedServer_RCBEventHandler) (void* parameter, ReportControlBlock* LIB61850_API void IedServer_setRCBEventHandler(IedServer self, IedServer_RCBEventHandler handler, void* parameter); - -/** - * \brief Callback that is called in case of RCB access to give the user the opportunity to block or allow the operation - * - * \note This callback is called before the IedServer_RCBEventHandler and only in case of operations (RCB_EVENT_GET_PARAMETER, RCB_EVENT_SET_PARAMETER, RCB_EVENT_ENABLE - * - * \param parameter user provided parameter - * \param rcb affected report control block - * \param connection client connection that is involved - * \param operation one of the following operation event types: RCB_EVENT_GET_PARAMETER, RCB_EVENT_SET_PARAMETER - */ -typedef bool -(*IedServer_RCBAccessHandler) (void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType operation); - -/** - * \brief Set a handler to control read and write access to report control blocks (RCBs) - * - * \param self the instance of IedServer to operate on. - * \param handler the event handler to be used - * \param parameter a user provided parameter that is passed to the handler. - */ -LIB61850_API void -IedServer_setRCBAccessHandler(IedServer self, IedServer_RCBAccessHandler handler, void* parameter); - /**@}*/ /** @@ -1865,6 +1841,45 @@ typedef MmsDataAccessError LIB61850_API void IedServer_setReadAccessHandler(IedServer self, ReadAccessHandler handler, void* parameter); +/** + * \brief Callback that is called in case of RCB access to give the user the opportunity to block or allow the operation + * + * \note This callback is called before the IedServer_RCBEventHandler and only in case of operations (RCB_EVENT_GET_PARAMETER, RCB_EVENT_SET_PARAMETER, RCB_EVENT_ENABLE + * + * \param parameter user provided parameter + * \param rcb affected report control block + * \param connection client connection that is involved + * \param operation one of the following operation event types: RCB_EVENT_GET_PARAMETER, RCB_EVENT_SET_PARAMETER + */ +typedef bool +(*IedServer_RCBAccessHandler) (void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType operation); + +/** + * \brief Set a handler to control read and write access to report control blocks (RCBs) + * + * \param self the instance of IedServer to operate on. + * \param handler the event handler to be used + * \param parameter a user provided parameter that is passed to the handler. + */ +LIB61850_API void +IedServer_setRCBAccessHandler(IedServer self, IedServer_RCBAccessHandler handler, void* parameter); + +typedef enum { + LCB_EVENT_GET_PARAMETER, + LCB_EVENT_SET_PARAMETER +} IedServer_LCBEventType; + +typedef bool +(*IedServer_LCBAccessHandler) (void* parameter, LogControlBlock* lcb, ClientConnection connection, IedServer_LCBEventType operation); + +LIB61850_API void +IedServer_setLCBAccessHandler(IedServer self, IedServer_LCBAccessHandler handler, void* parameter); + +typedef bool +(*IedServer_LogAccessHandler) (void* parameter, const char* logName, ClientConnection connection); + +LIB61850_API void +IedServer_setLogAccessHandler(IedServer self, IedServer_LogAccessHandler handler, void* parameter); typedef enum { DATASET_CREATE, diff --git a/src/iec61850/inc_private/logging.h b/src/iec61850/inc_private/logging.h index 7684739a..82ef712b 100644 --- a/src/iec61850/inc_private/logging.h +++ b/src/iec61850/inc_private/logging.h @@ -121,7 +121,7 @@ LIB61850_INTERNAL void Logging_processIntegrityLogs(MmsMapping* self, uint64_t currentTimeInMs); LIB61850_INTERNAL MmsValue* -LIBIEC61850_LOG_SVC_readAccessControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig); +LIBIEC61850_LOG_SVC_readAccessControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, MmsServerConnection connection); LIB61850_INTERNAL MmsDataAccessError LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, diff --git a/src/iec61850/inc_private/mms_mapping_internal.h b/src/iec61850/inc_private/mms_mapping_internal.h index c42df272..09aba970 100644 --- a/src/iec61850/inc_private/mms_mapping_internal.h +++ b/src/iec61850/inc_private/mms_mapping_internal.h @@ -338,6 +338,12 @@ struct sMmsMapping { IedServer_RCBAccessHandler rcbAccessHandler; void* rcbAccessHandlerParameter; + IedServer_LCBAccessHandler lcbAccessHandler; + void* lcbAccessHandlerParameter; + + IedServer_LogAccessHandler logAccessHandler; + void* logAccessHandlerParameter; + IedServer_DataSetAccessHandler dataSetAccessHandler; void* dataSetAccessHandlerParameter; }; diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index c398e143..fb39ead3 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -696,6 +696,20 @@ IedServer_setRCBAccessHandler(IedServer self, IedServer_RCBAccessHandler handler self->mmsMapping->rcbAccessHandlerParameter = parameter; } +void +IedServer_setLCBAccessHandler(IedServer self, IedServer_LCBAccessHandler handler, void* parameter) +{ + self->mmsMapping->lcbAccessHandler = handler; + self->mmsMapping->lcbAccessHandlerParameter = parameter; +} + +void +IedServer_setLogAccessHandler(IedServer self, IedServer_LogAccessHandler handler, void* parameter) +{ + self->mmsMapping->logAccessHandler = handler; + self->mmsMapping->logAccessHandlerParameter = parameter; +} + void IedServer_destroy(IedServer self) { diff --git a/src/iec61850/server/mms_mapping/logging.c b/src/iec61850/server/mms_mapping/logging.c index e841feb2..c55a1ff4 100644 --- a/src/iec61850/server/mms_mapping/logging.c +++ b/src/iec61850/server/mms_mapping/logging.c @@ -1,7 +1,7 @@ /* * logging.c * - * Copyright 2016-2022 Michael Zillgith + * Copyright 2016-2023 Michael Zillgith * * This file is part of libIEC61850. * @@ -43,6 +43,8 @@ #if (CONFIG_IEC61850_LOG_SERVICE == 1) +static MmsValue objectAccessDenied = {MMS_DATA_ACCESS_ERROR, false, {DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED}}; + LogInstance* LogInstance_create(LogicalNode* parentLN, const char* name) { @@ -520,6 +522,19 @@ LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* doma if (logControl == NULL) { return DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT; } + else + { + if (self->lcbAccessHandler) + { + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + + if (self->lcbAccessHandler(self->lcbAccessHandlerParameter, logControl->logControlBlock, clientConnection, LCB_EVENT_SET_PARAMETER) == false) { + retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + + goto exit_function; + } + } + } if (strcmp(varName, "LogEna") == 0) { bool logEna = MmsValue_getBoolean(value); @@ -699,7 +714,7 @@ exit_function: } MmsValue* -LIBIEC61850_LOG_SVC_readAccessControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig) +LIBIEC61850_LOG_SVC_readAccessControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, MmsServerConnection connection) { MmsValue* value = NULL; @@ -723,27 +738,41 @@ LIBIEC61850_LOG_SVC_readAccessControlBlock(MmsMapping* self, MmsDomain* domain, char* varName = MmsMapping_getNextNameElement(objectName); - if (varName != NULL) + if (varName) *(varName - 1) = 0; LogControl* logControl = lookupLogControl(self, domain, lnName, objectName); - if (logControl != NULL) { + if (logControl) + { + bool allowAccess = true; + + if (self->lcbAccessHandler) + { + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); - updateLogStatusInLCB(logControl); + if (self->lcbAccessHandler(self->lcbAccessHandlerParameter, logControl->logControlBlock, clientConnection, LCB_EVENT_GET_PARAMETER) == false) { + allowAccess = false; - if (varName != NULL) { - value = MmsValue_getSubElement(logControl->mmsValue, logControl->mmsType, varName); + value = &objectAccessDenied; + } } - else { - value = logControl->mmsValue; + + if (allowAccess) { + updateLogStatusInLCB(logControl); + + if (varName) { + value = MmsValue_getSubElement(logControl->mmsValue, logControl->mmsType, varName); + } + else { + value = logControl->mmsValue; + } } } return value; } - static char* createDataSetReferenceForDefaultDataSet(LogControlBlock* lcb, LogControl* logControl) { diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index a91ace26..396fcc96 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -3115,7 +3115,7 @@ mmsReadHandler(void* parameter, MmsDomain* domain, char* variableId, MmsServerCo #if (CONFIG_IEC61850_LOG_SERVICE == 1) /* LOG control block - LG */ if (isLogControlBlock(separator)) { - retValue = LIBIEC61850_LOG_SVC_readAccessControlBlock(self, domain, variableId); + retValue = LIBIEC61850_LOG_SVC_readAccessControlBlock(self, domain, variableId, connection); goto exit_function; } #endif @@ -3410,9 +3410,7 @@ checkDataSetAccess(MmsMapping* self, MmsServerConnection connection, MmsVariable StringUtils_appendString(dataSetRef, 129, listName); } - accessGranted = self->dataSetAccessHandler(self->dataSetAccessHandlerParameter, - private_IedServer_getClientConnectionByHandle(self->iedServer, connection), - operation, dataSetRef); + accessGranted = self->dataSetAccessHandler(self->dataSetAccessHandlerParameter, clientConnection, operation, dataSetRef); } return accessGranted; @@ -3596,6 +3594,31 @@ variableListAccessHandler (void* parameter, MmsVariableListAccessType accessType return allow; } +#if (CONFIG_IEC61850_LOG_SERVICE == 1) +static bool +mmsReadJournalHandler(void* parameter, MmsDomain* domain, const char* logName, MmsServerConnection connection) +{ + bool allowAccess = true; + + MmsMapping* self = (MmsMapping*)parameter; + + if (self->logAccessHandler) { + char logReference[130]; + logReference[0] = 0; + + StringUtils_appendString(logReference, 130, MmsDomain_getName(domain)); + StringUtils_appendString(logReference, 130, "/"); + StringUtils_appendString(logReference, 130, logName); + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + + allowAccess = self->logAccessHandler(self->logAccessHandlerParameter, logReference, clientConnection); + } + + return allowAccess; +} +#endif /* (CONFIG_IEC61850_LOG_SERVICE == 1) */ + void MmsMapping_installHandlers(MmsMapping* self) { @@ -3604,6 +3627,10 @@ MmsMapping_installHandlers(MmsMapping* self) MmsServer_installReadAccessHandler(self->mmsServer, mmsReadAccessHandler, (void*) self); MmsServer_installConnectionHandler(self->mmsServer, mmsConnectionHandler, (void*) self); MmsServer_installVariableListAccessHandler(self->mmsServer, variableListAccessHandler, (void*) self); + +#if (CONFIG_IEC61850_LOG_SERVICE == 1) + MmsServer_installReadJournalHandler(self->mmsServer, mmsReadJournalHandler, (void*) self); +#endif /* (CONFIG_IEC61850_LOG_SERVICE == 1) */ } void diff --git a/src/iec61850/server/model/dynamic_model.c b/src/iec61850/server/model/dynamic_model.c index 18933c46..9b0a53fd 100644 --- a/src/iec61850/server/model/dynamic_model.c +++ b/src/iec61850/server/model/dynamic_model.c @@ -347,6 +347,18 @@ LogControlBlock_create(const char* name, LogicalNode* parent, const char* dataSe return self; } +const char* +LogControlBlock_getName(LogControlBlock* self) +{ + return self->name; +} + +LogicalNode* +LogControlBlock_getParent(LogControlBlock* self) +{ + return self->parent; +} + static void LogicalNode_addReportControlBlock(LogicalNode* self, ReportControlBlock* rcb) { diff --git a/src/mms/inc/mms_server.h b/src/mms/inc/mms_server.h index b9c22417..ef4831d1 100644 --- a/src/mms/inc/mms_server.h +++ b/src/mms/inc/mms_server.h @@ -90,6 +90,26 @@ typedef MmsError (*MmsNamedVariableListAccessHandler)(void* parameter, MmsVariab LIB61850_INTERNAL void MmsServer_installVariableListAccessHandler(MmsServer self, MmsNamedVariableListAccessHandler handler, void* parameter); +/** + * \brief callback handler that is called for each received read journal request + * + * \param parameter a user provided parameter + * \param domain the MMS domain the journal is belonging to + * \param logName the name of the journal + * \param connection client connection that is accessing the journal + */ +typedef bool (*MmsReadJournalHandler)(void* parameter, MmsDomain* domain, const char* logName, MmsServerConnection connection); + +/** + * \brief Install callback handler that is called when a journal is accessed by a client + * + * \param self the MmsServer instance to operate on + * \param handler the callback handler function + * \param parameter user provided parameter that is passed to the callback handler + */ +LIB61850_INTERNAL void +MmsServer_installReadJournalHandler(MmsServer self, MmsReadJournalHandler handler, void* parameter); + /** * \brief ObtainFile service callback handler * diff --git a/src/mms/inc_private/mms_server_internal.h b/src/mms/inc_private/mms_server_internal.h index fc875597..087ff42c 100644 --- a/src/mms/inc_private/mms_server_internal.h +++ b/src/mms/inc_private/mms_server_internal.h @@ -126,6 +126,9 @@ struct sMmsServer { MmsNamedVariableListAccessHandler variableListAccessHandler; void* variableListAccessHandlerParameter; + MmsReadJournalHandler readJournalHandler; + void* readJournalHandlerParameter; + AcseAuthenticator authenticator; void* authenticatorParameter; diff --git a/src/mms/iso_mms/server/mms_journal_service.c b/src/mms/iso_mms/server/mms_journal_service.c index 22980f76..0aadde40 100644 --- a/src/mms/iso_mms/server/mms_journal_service.c +++ b/src/mms/iso_mms/server/mms_journal_service.c @@ -462,6 +462,20 @@ mmsServer_handleReadJournalRequest( if (DEBUG_MMS_SERVER) printf("MMS_SERVER: readJournal - read journal %s ...\n", mmsJournal->name); + MmsServer mmsServer = connection->server; + + if (mmsServer->readJournalHandler) + { + if (mmsServer->readJournalHandler(mmsServer->readJournalHandlerParameter, mmsDomain, logName, connection) == false) + { + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED); + + /* TODO log access error */ + + return; + } + } + struct sJournalEncoder encoder; encoder.buffer = response->buffer; diff --git a/src/mms/iso_mms/server/mms_server.c b/src/mms/iso_mms/server/mms_server.c index e6cccfa5..311266c1 100644 --- a/src/mms/iso_mms/server/mms_server.c +++ b/src/mms/iso_mms/server/mms_server.c @@ -365,6 +365,13 @@ MmsServer_installVariableListAccessHandler(MmsServer self, MmsNamedVariableListA self->variableListAccessHandlerParameter = parameter; } +void +MmsServer_installReadJournalHandler(MmsServer self, MmsReadJournalHandler handler, void* parameter) +{ + self->readJournalHandler = handler; + self->readJournalHandlerParameter = parameter; +} + void MmsServer_setClientAuthenticator(MmsServer self, AcseAuthenticator authenticator, void* authenticatorParameter) { From 7e3b7991d53fe9ade1599490335319b2d4ba5b2f Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Fri, 10 Mar 2023 18:34:10 +0000 Subject: [PATCH 7/9] - added doxygen comments for new access callback functions (LIB61850-381) --- src/iec61850/inc/iec61850_server.h | 50 +++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index ec023b4d..f45c68e1 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -1869,15 +1869,46 @@ typedef enum { LCB_EVENT_SET_PARAMETER } IedServer_LCBEventType; +/** + * \brief Callback that is called in case of LCB access to give the user the opportunity to block or allow the operation + * + * + * \param parameter user provided parameter + * \param lcb affected log control block + * \param connection client connection that is involved + * \param operation one of the following operation event types: LCB_EVENT_GET_PARAMETER, LCB_EVENT_SET_PARAMETER + */ typedef bool (*IedServer_LCBAccessHandler) (void* parameter, LogControlBlock* lcb, ClientConnection connection, IedServer_LCBEventType operation); +/** + * \brief Set a handler to control read and write access to log control blocks (LCBs) + * + * \param self the instance of IedServer to operate on. + * \param handler the event handler to be used + * \param parameter a user provided parameter that is passed to the handler. + */ LIB61850_API void IedServer_setLCBAccessHandler(IedServer self, IedServer_LCBAccessHandler handler, void* parameter); +/** + * \brief Callback that is called when the client is trying to read log data + * + * \param parameter user provided parameter + * \param logRef object reference of the log + * \param connection client connection that is involved + * + * \return true to allow read log data, false to deny + */ typedef bool -(*IedServer_LogAccessHandler) (void* parameter, const char* logName, ClientConnection connection); +(*IedServer_LogAccessHandler) (void* parameter, const char* logRef, ClientConnection connection); +/** + * \brief Set a handler control access to a log (read log data) + * + * \param handler the callback handler to be used + * \param parameter a user provided parameter that is passed to the handler. + */ LIB61850_API void IedServer_setLogAccessHandler(IedServer self, IedServer_LogAccessHandler handler, void* parameter); @@ -1889,9 +1920,26 @@ typedef enum { DATASET_GET_DIRECTORY } IedServer_DataSetOperation; +/** + * \brief Callback that is called when the client is calling a dataset operation (create, delete, read, write, list directory) + * + * \note This callback is called before the IedServer_RCBEventHandler and only in case of operations (RCB_EVENT_GET_PARAMETER, RCB_EVENT_SET_PARAMETER, RCB_EVENT_ENABLE + * + * \param parameter user provided parameter + * \param connection client connection that is involved + * \param operation one of the following operation types: DATASET_CREATE, DATASET_DELETE, DATASET_READ, DATASET_WRITE, DATASET_GET_DIRECTORY + * + * \return true to allow operation, false to deny operation + */ typedef bool (*IedServer_DataSetAccessHandler) (void* parameter, ClientConnection connection, IedServer_DataSetOperation operation, const char* datasetRef); +/** + * \brief Set a handler to control access to a dataset (create, delete, read, write, list directory) + * + * \param handler the callback handler to be used + * \param parameter a user provided parameter that is passed to the handler. + */ LIB61850_API void IedServer_setDataSetAccessHandler(IedServer self, IedServer_DataSetAccessHandler handler, void* parameter); From a4a58e42502dcde6d4d2e8e95cd62b965885e85b Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Fri, 17 Mar 2023 07:48:54 +0000 Subject: [PATCH 8/9] - IED server: check user permissions on data set when enabling RCB or changing RCB data sets (LIB61850-393) --- .../server_example_access_control.c | 26 +++++- src/iec61850/server/mms_mapping/reporting.c | 81 +++++++++++++++++-- src/mms/iso_mms/server/mms_read_service.c | 8 +- src/mms/iso_mms/server/mms_server.c | 1 - src/mms/iso_mms/server/mms_server_common.c | 7 +- 5 files changed, 102 insertions(+), 21 deletions(-) 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 7c18fd46..eec313eb 100644 --- a/examples/server_example_access_control/server_example_access_control.c +++ b/examples/server_example_access_control/server_example_access_control.c @@ -87,7 +87,8 @@ rcbAccessHandler(void* parameter, ReportControlBlock* rcb, ClientConnection conn return true; } else { - return false; + /* change to false to disallow write access to control block */ + return true; } } @@ -133,6 +134,18 @@ dataSetAccessHandler(void* parameter, ClientConnection connection, IedServer_Dat return true; } +static MmsDataAccessError +readAccessHandler(LogicalDevice* ld, LogicalNode* ln, DataObject* dataObject, FunctionalConstraint fc, ClientConnection connection, void* parameter) +{ + printf("Read access to %s/%s.%s\n", ld->name, ln->name, dataObject->name); + + if (!strcmp(ln->name, "GGIO1") && !strcmp(dataObject->name, "AnIn1")) { + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + } + + return DATA_ACCESS_ERROR_SUCCESS; +} + int main(int argc, char** argv) { @@ -196,10 +209,13 @@ main(int argc, char** argv) IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL); + /* Install handler to perform access control on RCB */ IedServer_setRCBAccessHandler(iedServer, rcbAccessHandler, NULL); + /* Install handler to perform access control on LCB */ IedServer_setLCBAccessHandler(iedServer, lcbAccessHandler, NULL); + /* Install handler to log RCB events */ IedServer_setRCBEventHandler(iedServer, rcbEventHandler, NULL); /* By default access to variables with FC=DC and FC=CF is not allowed. @@ -208,8 +224,16 @@ main(int argc, char** argv) */ IedServer_setWriteAccessPolicy(iedServer, IEC61850_FC_DC, ACCESS_POLICY_ALLOW); + /* Install handler to perform access control on datasets */ IedServer_setDataSetAccessHandler(iedServer, dataSetAccessHandler, NULL); + /* Install handler to perform read access control on data model elements + * NOTE: when read access to a data model element is blocked this will also prevent the client + * to read the data model element in a data set or enable a RCB instance that uses a dataset + * containing the restricted data model element. + */ + IedServer_setReadAccessHandler(iedServer, readAccessHandler, NULL); + /* MMS server will be instructed to start listening for client connections. */ IedServer_start(iedServer, tcpPort); diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index d0779138..a097a35c 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -1,7 +1,7 @@ /* * reporting.c * - * Copyright 2013-2022 Michael Zillgith + * Copyright 2013-2023 Michael Zillgith * * This file is part of libIEC61850. * @@ -673,6 +673,43 @@ createDataSetValuesShadowBuffer(ReportControl* rc) } } +static bool +checkIfClientHasAccessToDataSetEntries(MmsMapping* mapping, MmsServerConnection connection, MmsNamedVariableList mmsVariableList) +{ + bool accessAllowed = true; + + if (connection) { + + LinkedList entryElem = LinkedList_getNext(mmsVariableList->listOfVariables); + + while (entryElem) { + MmsNamedVariableListEntry entry = (MmsNamedVariableListEntry)LinkedList_getData(entryElem); + + MmsValue* entryValue = mmsServer_getValue(mapping->mmsServer, entry->domain, entry->variableName, connection, true); + + if (entryValue) { + + if (MmsValue_getType(entryValue) == MMS_DATA_ACCESS_ERROR) { + accessAllowed = false; + } + + MmsValue_deleteConditional(entryValue); + } + else { + accessAllowed = false; + } + + if (accessAllowed == false) + break; + + entryElem = LinkedList_getNext(entryElem); + } + + } + + return accessAllowed; +} + static bool updateReportDataset(MmsMapping* mapping, ReportControl* rc, MmsValue* newDatSet, MmsServerConnection connection) { @@ -760,11 +797,32 @@ updateReportDataset(MmsMapping* mapping, ReportControl* rc, MmsValue* newDatSet, } } - if (dataSetValue && dataSetChanged) { + if (dataSetValue) { const char* dataSetName = MmsValue_toString(dataSetValue); DataSet* dataSet = IedModel_lookupDataSet(mapping->model, dataSetName); + if (dataSet) { + + char domainNameBuf[130]; + + MmsMapping_getMmsDomainFromObjectReference(dataSetName, domainNameBuf); + + MmsDomain* dsDomain = MmsDevice_getDomain(mapping->mmsDevice, domainNameBuf); + + if (dsDomain) { + MmsNamedVariableList namedVariableList = MmsDomain_getNamedVariableList(dsDomain, dataSet->name); + + if (namedVariableList) { + if (checkIfClientHasAccessToDataSetEntries(mapping, connection, namedVariableList) == false) { + goto exit_function; + } + } + + } + + } + #if (MMS_DYNAMIC_DATA_SETS == 1) if (dataSet == NULL) { dataSet = MmsMapping_getDomainSpecificDataSet(mapping, dataSetName); @@ -779,19 +837,28 @@ updateReportDataset(MmsMapping* mapping, ReportControl* rc, MmsValue* newDatSet, MmsNamedVariableList mmsVariableList = MmsServerConnection_getNamedVariableList(connection, dataSetName + 1); - if (mmsVariableList != NULL) + if (mmsVariableList) { + if (checkIfClientHasAccessToDataSetEntries(mapping, connection, mmsVariableList) == false) { + goto exit_function; + } + dataSet = MmsMapping_createDataSetByNamedVariableList(mapping, mmsVariableList); + } } } - } /* check for VMD specific data set */ else if (dataSetName[0] == '/') { MmsNamedVariableList mmsVariableList = MmsDevice_getNamedVariableListWithName(mapping->mmsDevice, dataSetName + 1); - if (mmsVariableList != NULL) + if (mmsVariableList) { + if (checkIfClientHasAccessToDataSetEntries(mapping, connection, mmsVariableList) == false) { + goto exit_function; + } + dataSet = MmsMapping_createDataSetByNamedVariableList(mapping, mmsVariableList); + } } } @@ -810,7 +877,7 @@ updateReportDataset(MmsMapping* mapping, ReportControl* rc, MmsValue* newDatSet, #endif /* (MMS_DYNAMIC_DATA_SETS == 1) */ - if (dataSetChanged == true) { + if (dataSetChanged) { /* delete pending event and create buffer for new data set */ deleteDataSetValuesShadowBuffer(rc); @@ -830,7 +897,6 @@ updateReportDataset(MmsMapping* mapping, ReportControl* rc, MmsValue* newDatSet, GLOBAL_FREEMEM(rc->inclusionFlags); rc->inclusionFlags = (uint8_t*) GLOBAL_CALLOC(dataSet->elementCount, sizeof(uint8_t)); - } success = true; @@ -862,7 +928,6 @@ createDataSetReferenceForDefaultDataSet(ReportControlBlock* rcb, ReportControl* return dataSetReference; } - static MmsValue* createOptFlds(ReportControlBlock* reportControlBlock) { diff --git a/src/mms/iso_mms/server/mms_read_service.c b/src/mms/iso_mms/server/mms_read_service.c index 3193c699..2b33dc41 100644 --- a/src/mms/iso_mms/server/mms_read_service.c +++ b/src/mms/iso_mms/server/mms_read_service.c @@ -1,7 +1,7 @@ /* * mms_read_service.c * - * Copyright 2013-2022 Michael Zillgith + * Copyright 2013-2023 Michael Zillgith * * This file is part of libIEC61850. * @@ -695,13 +695,9 @@ createNamedVariableListResponse(MmsServerConnection connection, MmsNamedVariable LinkedList /**/ values = LinkedList_create(); LinkedList variables = MmsNamedVariableList_getVariableList(namedList); - int variableCount = LinkedList_size(variables); - - int i; - LinkedList variable = LinkedList_getNext(variables); - for (i = 0; i < variableCount; i++) { + while (variable) { MmsNamedVariableListEntry variableListEntry = (MmsNamedVariableListEntry) variable->data; diff --git a/src/mms/iso_mms/server/mms_server.c b/src/mms/iso_mms/server/mms_server.c index 311266c1..9a203713 100644 --- a/src/mms/iso_mms/server/mms_server.c +++ b/src/mms/iso_mms/server/mms_server.c @@ -572,7 +572,6 @@ exit_function: return value; } - MmsDevice* MmsServer_getDevice(MmsServer self) { diff --git a/src/mms/iso_mms/server/mms_server_common.c b/src/mms/iso_mms/server/mms_server_common.c index 62f9e0d5..455a26ec 100644 --- a/src/mms/iso_mms/server/mms_server_common.c +++ b/src/mms/iso_mms/server/mms_server_common.c @@ -391,7 +391,7 @@ mmsServer_getNamedVariableListWithName(LinkedList namedVariableLists, const char LinkedList element = LinkedList_getNext(namedVariableLists); - while (element != NULL) { + while (element) { MmsNamedVariableList varList = (MmsNamedVariableList) element->data; if (strcmp(MmsNamedVariableList_getName(varList), variableListName) == 0) { @@ -405,14 +405,13 @@ mmsServer_getNamedVariableListWithName(LinkedList namedVariableLists, const char return variableList; } - void mmsServer_deleteVariableList(LinkedList namedVariableLists, char* variableListName) { LinkedList previousElement = namedVariableLists; LinkedList element = LinkedList_getNext(namedVariableLists); - while (element != NULL ) { + while (element) { MmsNamedVariableList varList = (MmsNamedVariableList) element->data; if (strcmp(MmsNamedVariableList_getName(varList), variableListName) @@ -428,5 +427,3 @@ mmsServer_deleteVariableList(LinkedList namedVariableLists, char* variableListNa element = LinkedList_getNext(element); } } - - From aa863f35f0df1f28f8904077ab28ecb6de4059af Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Fri, 17 Mar 2023 18:58:54 +0000 Subject: [PATCH 9/9] - IED server: added callback to control access to data model directories (get-name-list requests)(LIB61850-396) --- .../server_example_access_control.c | 24 +++ src/iec61850/inc/iec61850_server.h | 13 ++ .../inc_private/mms_mapping_internal.h | 3 + src/iec61850/server/impl/ied_server.c | 7 + src/iec61850/server/mms_mapping/mms_mapping.c | 41 +++++ src/mms/inc/mms_server.h | 12 ++ src/mms/inc_private/mms_server_internal.h | 3 + .../iso_mms/server/mms_get_namelist_service.c | 151 +++++++++++++----- src/mms/iso_mms/server/mms_server.c | 7 + 9 files changed, 220 insertions(+), 41 deletions(-) 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 eec313eb..e0b789af 100644 --- a/examples/server_example_access_control/server_example_access_control.c +++ b/examples/server_example_access_control/server_example_access_control.c @@ -146,6 +146,28 @@ readAccessHandler(LogicalDevice* ld, LogicalNode* ln, DataObject* dataObject, Fu return DATA_ACCESS_ERROR_SUCCESS; } +static bool +directoryAccessHandler(void* parameter, ClientConnection connection, IedServer_DirectoryCategory category, LogicalDevice* logicalDevice) +{ + switch(category) { + case DIRECTORY_CAT_LD_LIST: + printf("Get list of logical devices from %s\n", ClientConnection_getPeerAddress(connection)); + break; + case DIRECTORY_CAT_DATASET_LIST: + printf("Get list of datasets for LD %s from %s\n", ModelNode_getName((ModelNode*)logicalDevice), ClientConnection_getPeerAddress(connection)); + break; + case DIRECTORY_CAT_DATA_LIST: + printf("Get list of data for LD %s from %s\n", ModelNode_getName((ModelNode*)logicalDevice), ClientConnection_getPeerAddress(connection)); + break; + case DIRECTORY_CAT_LOG_LIST: + printf("Get list of logs for LD %s from %s -> reject\n", ModelNode_getName((ModelNode*)logicalDevice), ClientConnection_getPeerAddress(connection)); + return false; + break; + } + + return true; +} + int main(int argc, char** argv) { @@ -234,6 +256,8 @@ main(int argc, char** argv) */ IedServer_setReadAccessHandler(iedServer, readAccessHandler, NULL); + IedServer_setDirectoryAccessHandler(iedServer, directoryAccessHandler, NULL); + /* MMS server will be instructed to start listening for client connections. */ IedServer_start(iedServer, tcpPort); diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index f45c68e1..24f4b776 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -1943,6 +1943,19 @@ typedef bool LIB61850_API void IedServer_setDataSetAccessHandler(IedServer self, IedServer_DataSetAccessHandler handler, void* parameter); +typedef enum { + DIRECTORY_CAT_LD_LIST, + DIRECTORY_CAT_DATA_LIST, + DIRECTORY_CAT_DATASET_LIST, + DIRECTORY_CAT_LOG_LIST +} IedServer_DirectoryCategory; + +typedef bool +(*IedServer_DirectoryAccessHandler) (void* parameter, ClientConnection connection, IedServer_DirectoryCategory category, LogicalDevice* logicalDevice); + +LIB61850_API void +IedServer_setDirectoryAccessHandler(IedServer self, IedServer_DirectoryAccessHandler handler, void* parameter); + /**@}*/ /**@}*/ diff --git a/src/iec61850/inc_private/mms_mapping_internal.h b/src/iec61850/inc_private/mms_mapping_internal.h index 09aba970..a66e815a 100644 --- a/src/iec61850/inc_private/mms_mapping_internal.h +++ b/src/iec61850/inc_private/mms_mapping_internal.h @@ -346,6 +346,9 @@ struct sMmsMapping { IedServer_DataSetAccessHandler dataSetAccessHandler; void* dataSetAccessHandlerParameter; + + IedServer_DirectoryAccessHandler directoryAccessHandler; + void* directoryAccessHandlerParameter; }; #endif /* MMS_MAPPING_INTERNAL_H_ */ diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index fb39ead3..08c555d7 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -1945,3 +1945,10 @@ IedServer_setDataSetAccessHandler(IedServer self, IedServer_DataSetAccessHandler self->mmsMapping->dataSetAccessHandler = handler; self->mmsMapping->dataSetAccessHandlerParameter = parameter; } + +void +IedServer_setDirectoryAccessHandler(IedServer self, IedServer_DirectoryAccessHandler handler, void* parameter) +{ + self->mmsMapping->directoryAccessHandler = handler; + self->mmsMapping->directoryAccessHandlerParameter = parameter; +} diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index 396fcc96..2af5f228 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -3228,6 +3228,46 @@ unselectControlsForConnection(MmsMapping* self, MmsServerConnection connection) } #endif /* (CONFIG_IEC61850_CONTROL_SERVICE == 1) */ +static bool +mmsGetNameListHandler(void* parameter, MmsGetNameListType nameListType, MmsDomain* domain, MmsServerConnection connection) +{ + MmsMapping* self = (MmsMapping*) parameter; + + bool allowAccess = true; + + if (self->directoryAccessHandler) { + + LogicalDevice* ld = NULL; + + IedServer_DirectoryCategory category = DIRECTORY_CAT_DATA_LIST; + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + + if (domain) { + ld = IedModel_getDevice(self->model, MmsDomain_getName(domain)); + + if (ld == NULL) { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: mmsGetNameListHandler -> LD not found!\n"); + } + } + + /* convert type to category */ + if (nameListType == MMS_GETNAMELIST_DATA) + category = DIRECTORY_CAT_DATA_LIST; + else if (nameListType == MMS_GETNAMELIST_DATASETS) + category = DIRECTORY_CAT_DATASET_LIST; + else if (nameListType == MMS_GETNAMELIST_DOMAINS) + category = DIRECTORY_CAT_LD_LIST; + else if (nameListType == MMS_GETNAMELIST_JOURNALS) + category = DIRECTORY_CAT_LOG_LIST; + + allowAccess = self->directoryAccessHandler(self->directoryAccessHandlerParameter, clientConnection, category, ld); + } + + return allowAccess; +} + static void /* is called by MMS server layer and runs in the connection handling thread */ mmsConnectionHandler(void* parameter, MmsServerConnection connection, MmsServerEvent event) { @@ -3627,6 +3667,7 @@ MmsMapping_installHandlers(MmsMapping* self) MmsServer_installReadAccessHandler(self->mmsServer, mmsReadAccessHandler, (void*) self); MmsServer_installConnectionHandler(self->mmsServer, mmsConnectionHandler, (void*) self); MmsServer_installVariableListAccessHandler(self->mmsServer, variableListAccessHandler, (void*) self); + MmsServer_installGetNameListHandler(self->mmsServer, mmsGetNameListHandler, (void*) self); #if (CONFIG_IEC61850_LOG_SERVICE == 1) MmsServer_installReadJournalHandler(self->mmsServer, mmsReadJournalHandler, (void*) self); diff --git a/src/mms/inc/mms_server.h b/src/mms/inc/mms_server.h index ef4831d1..15248789 100644 --- a/src/mms/inc/mms_server.h +++ b/src/mms/inc/mms_server.h @@ -110,6 +110,18 @@ typedef bool (*MmsReadJournalHandler)(void* parameter, MmsDomain* domain, const LIB61850_INTERNAL void MmsServer_installReadJournalHandler(MmsServer self, MmsReadJournalHandler handler, void* parameter); +typedef enum { + MMS_GETNAMELIST_DOMAINS, + MMS_GETNAMELIST_JOURNALS, + MMS_GETNAMELIST_DATASETS, + MMS_GETNAMELIST_DATA +} MmsGetNameListType; + +typedef bool (*MmsGetNameListHandler)(void* parameter, MmsGetNameListType nameListType, MmsDomain* domain, MmsServerConnection connection); + +LIB61850_INTERNAL void +MmsServer_installGetNameListHandler(MmsServer self, MmsGetNameListHandler handler, void* parameter); + /** * \brief ObtainFile service callback handler * diff --git a/src/mms/inc_private/mms_server_internal.h b/src/mms/inc_private/mms_server_internal.h index 087ff42c..ec70d359 100644 --- a/src/mms/inc_private/mms_server_internal.h +++ b/src/mms/inc_private/mms_server_internal.h @@ -129,6 +129,9 @@ struct sMmsServer { MmsReadJournalHandler readJournalHandler; void* readJournalHandlerParameter; + MmsGetNameListHandler getNameListHandler; + void* getNameListHandlerParameter; + AcseAuthenticator authenticator; void* authenticatorParameter; diff --git a/src/mms/iso_mms/server/mms_get_namelist_service.c b/src/mms/iso_mms/server/mms_get_namelist_service.c index 005aa4c6..2170f8c1 100644 --- a/src/mms/iso_mms/server/mms_get_namelist_service.c +++ b/src/mms/iso_mms/server/mms_get_namelist_service.c @@ -1,7 +1,7 @@ /* * mms_get_namelist_service.c * - * Copyright 2013-2022 Michael Zillgith + * Copyright 2013-2023 Michael Zillgith * * This file is part of libIEC61850. * @@ -190,20 +190,29 @@ getJournalListDomainSpecific(MmsServerConnection connection, char* domainName) MmsDomain* domain = MmsDevice_getDomain(device, domainName); - if (domain != NULL) { - nameList = LinkedList_create(); + if (domain) { - if (domain->journals != NULL) { + bool allowAccess = true; - LinkedList journalList = domain->journals; + if (connection->server->getNameListHandler) { + allowAccess = connection->server->getNameListHandler(connection->server->getNameListHandlerParameter, MMS_GETNAMELIST_JOURNALS, domain, connection); + } - while ((journalList = LinkedList_getNext(journalList)) != NULL) { + if (allowAccess) { + nameList = LinkedList_create(); - MmsJournal journal = (MmsJournal) LinkedList_getData(journalList); + if (domain->journals != NULL) { - LinkedList_add(nameList, (void*) journal->name); - } + LinkedList journalList = domain->journals; + + while ((journalList = LinkedList_getNext(journalList)) != NULL) { + + MmsJournal journal = (MmsJournal) LinkedList_getData(journalList); + LinkedList_add(nameList, (void*) journal->name); + } + + } } } @@ -219,46 +228,56 @@ getNameListDomainSpecific(MmsServerConnection connection, char* domainName) MmsDomain* domain = MmsDevice_getDomain(device, domainName); - if (domain != NULL) { - nameList = LinkedList_create(); - MmsVariableSpecification** variables = domain->namedVariables; + if (domain) { - int i; + bool allowAccess = true; - LinkedList element = nameList; + if (connection->server->getNameListHandler) { + allowAccess = connection->server->getNameListHandler(connection->server->getNameListHandlerParameter, MMS_GETNAMELIST_DATASETS, domain, connection); + } + + if (allowAccess) { + nameList = LinkedList_create(); + MmsVariableSpecification** variables = domain->namedVariables; + + int i; + + LinkedList element = nameList; #if (CONFIG_MMS_SORT_NAME_LIST == 1) - int* index = (int*) GLOBAL_MALLOC(sizeof(int) * domain->namedVariablesCount); + int* index = (int*) GLOBAL_MALLOC(sizeof(int) * domain->namedVariablesCount); - for (i = 0; i < domain->namedVariablesCount; i++) - index[i] = i; + for (i = 0; i < domain->namedVariablesCount; i++) + index[i] = i; - sortIndex(index, domain->namedVariablesCount, domain->namedVariables); + sortIndex(index, domain->namedVariablesCount, domain->namedVariables); #endif /* (CONFIG_MMS_SORT_NAME_LIST == 1) */ - for (i = 0; i < domain->namedVariablesCount; i++) { + for (i = 0; i < domain->namedVariablesCount; i++) { #if (CONFIG_MMS_SORT_NAME_LIST == 1) - element = LinkedList_insertAfter(element, StringUtils_copyString(variables[index[i]]->name)); + element = LinkedList_insertAfter(element, StringUtils_copyString(variables[index[i]]->name)); #else - element = LinkedList_insertAfter(element, StringUtils_copyString(variables[i]->name)); + element = LinkedList_insertAfter(element, StringUtils_copyString(variables[i]->name)); #endif #if (CONFIG_MMS_SUPPORT_FLATTED_NAME_SPACE == 1) #if (CONFIG_MMS_SORT_NAME_LIST == 1) - char* prefix = variables[index[i]]->name; - element = addSubNamedVaribleNamesToList(element, prefix, variables[index[i]]); + char* prefix = variables[index[i]]->name; + element = addSubNamedVaribleNamesToList(element, prefix, variables[index[i]]); #else - char* prefix = variables[i]->name; - element = addSubNamedVaribleNamesToList(element, prefix, variables[i]); + char* prefix = variables[i]->name; + element = addSubNamedVaribleNamesToList(element, prefix, variables[i]); #endif /* (CONFIG_MMS_SORT_NAME_LIST == 1) */ #endif /* (CONFIG_MMS_SUPPORT_FLATTED_NAME_SPACE == 1) */ - } + } #if (CONFIG_MMS_SORT_NAME_LIST == 1) - GLOBAL_FREEMEM(index); + GLOBAL_FREEMEM(index); #endif + + } } return nameList; @@ -293,10 +312,19 @@ getNamedVariableListsDomainSpecific(MmsServerConnection connection, char* domain MmsDomain* domain = MmsDevice_getDomain(device, domainName); - if (domain != NULL) { - LinkedList variableLists = MmsDomain_getNamedVariableLists(domain); + if (domain) { + + bool allowAccess = true; - nameList = createStringsFromNamedVariableList(variableLists); + if (connection->server->getNameListHandler) { + allowAccess = connection->server->getNameListHandler(connection->server->getNameListHandlerParameter, MMS_GETNAMELIST_DATASETS, domain, connection); + } + + if (allowAccess) { + LinkedList variableLists = MmsDomain_getNamedVariableLists(domain); + + nameList = createStringsFromNamedVariableList(variableLists); + } } return nameList; @@ -613,38 +641,79 @@ mmsServer_handleGetNameListRequest( if (objectClass == OBJECT_CLASS_DOMAIN) { - LinkedList nameList = getDomainNames(connection); + bool allowAccess = true; + + if (connection->server->getNameListHandler) { + allowAccess = connection->server->getNameListHandler(connection->server->getNameListHandlerParameter, MMS_GETNAMELIST_DOMAINS, NULL, connection); + } + + if (allowAccess) { + LinkedList nameList = getDomainNames(connection); #if (CONFIG_MMS_SORT_NAME_LIST == 1) - StringUtils_sortList(nameList); + StringUtils_sortList(nameList); #endif - createNameListResponse(connection, invokeId, nameList, response, continueAfterId); + createNameListResponse(connection, invokeId, nameList, response, continueAfterId); - LinkedList_destroyStatic(nameList); + LinkedList_destroyStatic(nameList); + } + else { + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED); + } } #if (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) else if (objectClass == OBJECT_CLASS_NAMED_VARIABLE) { - LinkedList nameList = getNameListVMDSpecific(connection); - createNameListResponse(connection, invokeId, nameList, response, continueAfterId); + bool allowAccess = true; + + if (connection->server->getNameListHandler) { + allowAccess = connection->server->getNameListHandler(connection->server->getNameListHandlerParameter, MMS_GETNAMELIST_DATA, NULL, connection); + } + + if (allowAccess) { + LinkedList nameList = getNameListVMDSpecific(connection); + +#if (CONFIG_MMS_SORT_NAME_LIST == 1) + StringUtils_sortList(nameList); +#endif + + createNameListResponse(connection, invokeId, nameList, response, continueAfterId); - LinkedList_destroyStatic(nameList); + LinkedList_destroyStatic(nameList); + } + else { + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED); + } } #endif /* (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) */ #if (MMS_DATA_SET_SERVICE == 1) else if (objectClass == OBJECT_CLASS_NAMED_VARIABLE_LIST) { - LinkedList nameList = getNamedVariableListsVMDSpecific(connection); + + bool allowAccess = true; + + if (connection->server->getNameListHandler) { + allowAccess = connection->server->getNameListHandler(connection->server->getNameListHandlerParameter, MMS_GETNAMELIST_DATASETS, NULL, connection); + } + + if (allowAccess) { + + LinkedList nameList = getNamedVariableListsVMDSpecific(connection); #if (CONFIG_MMS_SORT_NAME_LIST == 1) - StringUtils_sortList(nameList); + StringUtils_sortList(nameList); #endif - createNameListResponse(connection, invokeId, nameList, response, continueAfterId); + createNameListResponse(connection, invokeId, nameList, response, continueAfterId); - LinkedList_destroy(nameList); + LinkedList_destroy(nameList); + + } + else { + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED); + } } #endif /* (MMS_DATA_SET_SERVICE == 1) */ diff --git a/src/mms/iso_mms/server/mms_server.c b/src/mms/iso_mms/server/mms_server.c index 9a203713..b9d4c798 100644 --- a/src/mms/iso_mms/server/mms_server.c +++ b/src/mms/iso_mms/server/mms_server.c @@ -372,6 +372,13 @@ MmsServer_installReadJournalHandler(MmsServer self, MmsReadJournalHandler handle self->readJournalHandlerParameter = parameter; } +void +MmsServer_installGetNameListHandler(MmsServer self, MmsGetNameListHandler handler, void* parameter) +{ + self->getNameListHandler = handler; + self->getNameListHandlerParameter = parameter; +} + void MmsServer_setClientAuthenticator(MmsServer self, AcseAuthenticator authenticator, void* authenticatorParameter) {