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 e0b789af..6b13ca7b 100644 --- a/examples/server_example_access_control/server_example_access_control.c +++ b/examples/server_example_access_control/server_example_access_control.c @@ -23,6 +23,38 @@ sigint_handler(int signalId) running = 0; } +static const char* +ACSIClassToStr(ACSIClass acsiClass) +{ + switch (acsiClass) + { + case ACSI_CLASS_BRCB: + return "BRCB"; + case ACSI_CLASS_URCB: + return "URCB"; + case ACSI_CLASS_GoCB: + return "GoCB"; + case ACSI_CLASS_SGCB: + return "SGCB"; + case ACSI_CLASS_LCB: + return "LCB"; + case ACSI_CLASS_GsCB: + return "GsCB"; + case ACSI_CLASS_LOG: + return "log"; + case ACSI_CLASS_DATA_SET: + return "dataset"; + case ACSI_CLASS_DATA_OBJECT: + return "data-object"; + case ACSI_CLASS_MSVCB: + return "MSVCB"; + case ACSI_CLASS_USVCB: + return "USVCB"; + default: + return "unknown"; + } +} + static ControlHandlerResult controlHandlerForBinaryOutput(ControlAction action, void* parameter, MmsValue* value, bool test) { @@ -65,7 +97,6 @@ controlHandlerForBinaryOutput(ControlAction action, void* parameter, MmsValue* v return CONTROL_RESULT_OK; } - static void connectionHandler (IedServer self, ClientConnection connection, bool connected, void* parameter) { @@ -79,43 +110,41 @@ 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 */ static bool -rcbAccessHandler(void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType operation) +controlBlockAccessHandler(void* parameter, ClientConnection connection, ACSIClass acsiClass, LogicalDevice* ld, LogicalNode* ln, const char* objectName, const char* subObjectName, IedServer_ControlBlockAccessType accessType) { - printf("RCB: %s access: %s\n", ReportControlBlock_getName(rcb), operation == RCB_EVENT_GET_PARAMETER ? "READ" : "WRITE"); + printf("%s %s access %s/%s.%s.%s\n", ACSIClassToStr(acsiClass), accessType == IEC61850_CB_ACCESS_TYPE_WRITE ? "write" : "read", ld->name, ln->name, objectName, subObjectName); - if (operation == RCB_EVENT_GET_PARAMETER) { - return true; + /* allow only read access to LCBs */ + if (acsiClass == ACSI_CLASS_LCB) { + if (accessType == IEC61850_CB_ACCESS_TYPE_READ) + return true; + else + return false; } - else { - /* change to false to disallow write access to control block */ - return true; + + /* allow only read access to BRCBs */ + if (acsiClass == ACSI_CLASS_BRCB) { + if (accessType == IEC61850_CB_ACCESS_TYPE_READ) + return true; + else + return false; } -} - -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; - } + /* to all other control blocks allow read and write access */ + return true; } 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("RCB: %s event: %i\n", ReportControlBlock_getName(rcb), event); printf(" param: %s\n", parameterName); printf(" result: %i\n", serviceError); } if (event == RCB_EVENT_ENABLE) { + printf("RCB: %s event: %i\n", ReportControlBlock_getName(rcb), event); char* rptId = ReportControlBlock_getRptID(rcb); printf(" rptID: %s\n", rptId); char* dataSet = ReportControlBlock_getDataSet(rcb); @@ -137,15 +166,39 @@ dataSetAccessHandler(void* parameter, ClientConnection connection, IedServer_Dat 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); + printf("Read access to %s/%s.%s\n", ld->name, ln->name, dataObject ? dataObject->name : "-"); - if (!strcmp(ln->name, "GGIO1") && !strcmp(dataObject->name, "AnIn1")) { - return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + if (dataObject == NULL) { + if (!strcmp(ln->name, "GGIO1")) { + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + } + } + else { + if (!strcmp(ln->name, "GGIO1") && !strcmp(dataObject->name, "AnIn1")) { + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + } } return DATA_ACCESS_ERROR_SUCCESS; } +static bool +listObjectsAccessHandler(void* parameter, ClientConnection connection, ACSIClass acsiClass, LogicalDevice* ld, LogicalNode* ln, const char* objectName, const char* subObjectName, FunctionalConstraint fc) +{ + if (subObjectName) + printf("list objects access[2] to %s/%s.%s.%s [acsi-class: %s(%i)] [FC=%s]\n", ld->name, ln ? ln->name : "-", objectName, subObjectName, ACSIClassToStr(acsiClass), acsiClass, FunctionalConstraint_toString(fc)); + else + printf("list objects access[2] to %s/%s.%s [acsi-class: %s(%i)] [FC=%s]\n", ld->name, ln ? ln->name : "-", objectName, ACSIClassToStr(acsiClass), acsiClass, FunctionalConstraint_toString(fc)); + + // if (acsiClass == ACSI_CLASS_BRCB) { + // return true; + // } + + // return false; + + return true; +} + static bool directoryAccessHandler(void* parameter, ClientConnection connection, IedServer_DirectoryCategory category, LogicalDevice* logicalDevice) { @@ -231,15 +284,12 @@ 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); + /* Install handler to control access to control blocks (RCBs, LCBs, GoCBs, SVCBs, SGCBs)*/ + IedServer_setControlBlockAccessHandler(iedServer, controlBlockAccessHandler, 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. @@ -258,6 +308,9 @@ main(int argc, char** argv) IedServer_setDirectoryAccessHandler(iedServer, directoryAccessHandler, NULL); + /* control visibility of data objects in directory (get-name-list) and variable description (get-variable-access-attributes) services */ + IedServer_setListObjectsAccessHandler(iedServer, listObjectsAccessHandler, NULL); + /* MMS server will be instructed to start listening for client connections. */ IedServer_start(iedServer, tcpPort); diff --git a/examples/server_example_access_control/static_model.c b/examples/server_example_access_control/static_model.c index 26f5f4fc..f38f886e 100644 --- a/examples/server_example_access_control/static_model.c +++ b/examples/server_example_access_control/static_model.c @@ -1,7 +1,7 @@ /* * static_model.c * - * automatically generated from simpleIO_direct_control.cid + * automatically generated from ../../examples/server_example_basic_io/simpleIO_direct_control.cid */ #include "static_model.h" @@ -2169,7 +2169,15 @@ ReportControlBlock iedModel_GenericIO_LLN0_report9 = {&iedModel_GenericIO_LLN0, +extern LogControlBlock iedModel_GenericIO_LLN0_lcb0; +extern LogControlBlock iedModel_GenericIO_LLN0_lcb1; +LogControlBlock iedModel_GenericIO_LLN0_lcb0 = {&iedModel_GenericIO_LLN0, "EventLog", "Events", "GenericIO/LLN0$EventLog", 3, 0, true, true, &iedModel_GenericIO_LLN0_lcb1}; +LogControlBlock iedModel_GenericIO_LLN0_lcb1 = {&iedModel_GenericIO_LLN0, "GeneralLog", NULL, NULL, 3, 0, true, true, NULL}; +extern Log iedModel_GenericIO_LLN0_log0; +extern Log iedModel_GenericIO_LLN0_log1; +Log iedModel_GenericIO_LLN0_log0 = {&iedModel_GenericIO_LLN0, "GeneralLog", &iedModel_GenericIO_LLN0_log1}; +Log iedModel_GenericIO_LLN0_log1 = {&iedModel_GenericIO_LLN0, "EventLog", NULL}; IedModel iedModel = { @@ -2180,8 +2188,8 @@ IedModel iedModel = { NULL, NULL, NULL, - NULL, - NULL, + &iedModel_GenericIO_LLN0_lcb0, + &iedModel_GenericIO_LLN0_log0, initializeValues }; diff --git a/examples/server_example_logging/server_example_logging.c b/examples/server_example_logging/server_example_logging.c index ee388be8..e086d52a 100644 --- a/examples/server_example_logging/server_example_logging.c +++ b/examples/server_example_logging/server_example_logging.c @@ -115,26 +115,62 @@ 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) +static const char* +ACSIClassToStr(ACSIClass acsiClass) { - 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; + switch (acsiClass) + { + case ACSI_CLASS_BRCB: + return "BRCB"; + case ACSI_CLASS_URCB: + return "URCB"; + case ACSI_CLASS_GoCB: + return "GoCB"; + case ACSI_CLASS_SGCB: + return "SGCB"; + case ACSI_CLASS_LCB: + return "LCB"; + case ACSI_CLASS_GsCB: + return "GsCB"; + case ACSI_CLASS_LOG: + return "log"; + case ACSI_CLASS_DATA_SET: + return "dataset"; + case ACSI_CLASS_DATA_OBJECT: + return "data-object"; + case ACSI_CLASS_MSVCB: + return "MSVCB"; + case ACSI_CLASS_USVCB: + return "USVCB"; + default: + return "unknown"; } - else { - return false; +} + +bool +controlBlockAccessHandler(void* parameter, ClientConnection connection, ACSIClass acsiClass, LogicalDevice* ld, LogicalNode* ln, const char* objectName, const char* subObjectName, IedServer_ControlBlockAccessType accessType) +{ + printf("Access to %s %s/%s.%s\n", ACSIClassToStr(acsiClass), ld->name, ln ? ln->name : "-", objectName); + + if (acsiClass == ACSI_CLASS_LCB) { + if (accessType == IEC61850_CB_ACCESS_TYPE_READ) + return true; + else + return false; } + + return true; } static bool -logAccessHandler(void* parameter, const char* logName, ClientConnection connection) +listObjectsAccessHandler(void* parameter, ClientConnection connection, ACSIClass acsiClass, LogicalDevice* ld, LogicalNode* ln, const char* objectName, const char* subObjectName, FunctionalConstraint fc) { - printf("Access to log %s from %s\n", logName, ClientConnection_getPeerAddress(connection)); + if (subObjectName) + printf("list objects access[2] to %s/%s.%s.%s [acsi-class: %s(%i)] [FC=%s]\n", ld->name, ln ? ln->name : "-", objectName, subObjectName, ACSIClassToStr(acsiClass), acsiClass, FunctionalConstraint_toString(fc)); + else + printf("list objects access[2] to %s/%s.%s [acsi-class: %s(%i)] [FC=%s]\n", ld->name, ln ? ln->name : "-", objectName, ACSIClassToStr(acsiClass), acsiClass, FunctionalConstraint_toString(fc)); - return false; + return true; } int @@ -169,9 +205,7 @@ main(int argc, char** argv) IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL); - IedServer_setLCBAccessHandler(iedServer, lcbAccessHandler, NULL); - - IedServer_setLogAccessHandler(iedServer, logAccessHandler, NULL); + IedServer_setControlBlockAccessHandler(iedServer, controlBlockAccessHandler, NULL); LogStorage statusLog = SqliteLogStorage_createInstance("log_status.db"); @@ -204,6 +238,7 @@ main(int argc, char** argv) LogStorage_getEntries(statusLog, 0, Hal_getTimeInMs(), entryCallback, (LogEntryDataCallback) entryDataCallback, NULL); #endif + IedServer_setListObjectsAccessHandler(iedServer, listObjectsAccessHandler, NULL); /* MMS server will be instructed to start listening to client connections. */ IedServer_start(iedServer, tcpPort); diff --git a/hal/filesystem/linux/file_provider_linux.c b/hal/filesystem/linux/file_provider_linux.c index 7b501f00..d37a7db1 100644 --- a/hal/filesystem/linux/file_provider_linux.c +++ b/hal/filesystem/linux/file_provider_linux.c @@ -53,13 +53,13 @@ FileSystem_openFile(char* fileName, bool readWrite) int FileSystem_readFile(FileHandle handle, uint8_t* buffer, int maxSize) { - return fread(buffer, maxSize, 1, (FILE*) handle); + return fread(buffer, 1, maxSize, (FILE*) handle); } int FileSystem_writeFile(FileHandle handle, uint8_t* buffer, int size) { - return fwrite(buffer, size, 1, (FILE*) handle); + return fwrite(buffer, 1, size, (FILE*) handle); } void diff --git a/hal/filesystem/win32/file_provider_win32.c b/hal/filesystem/win32/file_provider_win32.c index 1a08e8d1..b51a1a45 100644 --- a/hal/filesystem/win32/file_provider_win32.c +++ b/hal/filesystem/win32/file_provider_win32.c @@ -62,13 +62,13 @@ FileSystem_openFile(char* fileName, bool readWrite) int FileSystem_readFile(FileHandle handle, uint8_t* buffer, int maxSize) { - return fread(buffer, maxSize, 1, (FILE*) handle); + return fread(buffer, 1, maxSize, (FILE*) handle); } int FileSystem_writeFile(FileHandle handle, uint8_t* buffer, int size) { - return fwrite(buffer, size, 1, (FILE*) handle); + return fwrite(buffer, 1, size, (FILE*) handle); } void diff --git a/src/common/inc/string_utilities.h b/src/common/inc/string_utilities.h index b6b238ff..404aec3e 100644 --- a/src/common/inc/string_utilities.h +++ b/src/common/inc/string_utilities.h @@ -40,6 +40,19 @@ StringUtils_copyStringMax(char* dest, int maxBufferSize, const char* str1); LIB61850_INTERNAL char* StringUtils_copyStringToBuffer(const char* string, char* buffer); +/** + * \brief Copy string to buffer and replace characters + * + * NOTE: str should be a 0 terminated string. The terminating 0 is also copied. + * + * \param str the source string to copy + * \param buffer the destination buffer + * \param oldChar the character that has to be replaced while copying + * \param newChar the replacement character + */ +LIB61850_INTERNAL char* +StringUtils_copyStringToBufferAndReplace(const char* str, char* buffer, char oldChar, char newChar); + LIB61850_INTERNAL char* StringUtils_copySubString(char* startPos, char* endPos); diff --git a/src/common/string_utilities.c b/src/common/string_utilities.c index abf9a04c..2f659e6f 100644 --- a/src/common/string_utilities.c +++ b/src/common/string_utilities.c @@ -1,7 +1,7 @@ /* * string_utilities.c * - * Copyright 2013 Michael Zillgith + * Copyright 2013-2023 Michael Zillgith * * This file is part of libIEC61850. * @@ -65,6 +65,27 @@ StringUtils_copyStringToBuffer(const char* string, char* buffer) return buffer; } +char* +StringUtils_copyStringToBufferAndReplace(const char* str, char* buffer, char oldChar, char newChar) +{ + int i = 0; + + while (true) + { + if (str[i] == oldChar) + buffer[i] = newChar; + else + buffer[i] = str[i]; + + if (str[i] == 0) + break; + + i++; + } + + return buffer; +} + char* StringUtils_createStringFromBuffer(const uint8_t* buf, int size) diff --git a/src/iec61850/client/ied_connection.c b/src/iec61850/client/ied_connection.c index bc8e9ff6..d64fc595 100644 --- a/src/iec61850/client/ied_connection.c +++ b/src/iec61850/client/ied_connection.c @@ -1,7 +1,7 @@ /* * ied_connection.c * - * Copyright 2013-2022 Michael Zillgith + * Copyright 2013-2023 Michael Zillgith * * This file is part of libIEC61850. * @@ -108,6 +108,9 @@ iedConnection_mapMmsErrorToIedError(MmsError mmsError) case MMS_ERROR_ACCESS_TEMPORARILY_UNAVAILABLE: return IED_ERROR_TEMPORARILY_UNAVAILABLE; + case MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT: + return IED_ERROR_OBJECT_CONSTRAINT_CONFLICT; + default: return IED_ERROR_UNKNOWN; } diff --git a/src/iec61850/common/iec61850_common.c b/src/iec61850/common/iec61850_common.c index fa9a13c0..2ba1d3f7 100644 --- a/src/iec61850/common/iec61850_common.c +++ b/src/iec61850/common/iec61850_common.c @@ -768,7 +768,6 @@ MmsMapping_ObjectReferenceToVariableAccessSpec(char* objectReference) return accessSpec; } - static int getNumberOfDigits(int value) { diff --git a/src/iec61850/inc/iec61850_client.h b/src/iec61850/inc/iec61850_client.h index c3a174fe..5e53efe2 100644 --- a/src/iec61850/inc/iec61850_client.h +++ b/src/iec61850/inc/iec61850_client.h @@ -162,6 +162,9 @@ typedef enum { /** Received an invalid response message from the server */ IED_ERROR_MALFORMED_MESSAGE = 34, + /** Service was not executed because required resource is still in use */ + IED_ERROR_OBJECT_CONSTRAINT_CONFLICT = 35, + /** Service not implemented */ IED_ERROR_SERVICE_NOT_IMPLEMENTED = 98, @@ -2467,20 +2470,6 @@ IedConnection_getServerDirectory(IedConnection self, IedClientError* error, bool LIB61850_API LinkedList /**/ IedConnection_getLogicalDeviceDirectory(IedConnection self, IedClientError* error, const char* logicalDeviceName); -typedef enum { - ACSI_CLASS_DATA_OBJECT, - ACSI_CLASS_DATA_SET, - ACSI_CLASS_BRCB, - ACSI_CLASS_URCB, - ACSI_CLASS_LCB, - ACSI_CLASS_LOG, - ACSI_CLASS_SGCB, - ACSI_CLASS_GoCB, - ACSI_CLASS_GsCB, - ACSI_CLASS_MSVCB, - ACSI_CLASS_USVCB -} ACSIClass; - /** * \brief returns a list of all MMS variables that are children of the given logical node * diff --git a/src/iec61850/inc/iec61850_common.h b/src/iec61850/inc/iec61850_common.h index 9a364656..53aa6e86 100644 --- a/src/iec61850/inc/iec61850_common.h +++ b/src/iec61850/inc/iec61850_common.h @@ -55,6 +55,21 @@ typedef struct { uint8_t dstAddress[6]; } PhyComAddress; +/** IEC 61850 ACSI classes */ +typedef enum { + ACSI_CLASS_DATA_OBJECT, + ACSI_CLASS_DATA_SET, + ACSI_CLASS_BRCB, + ACSI_CLASS_URCB, + ACSI_CLASS_LCB, + ACSI_CLASS_LOG, + ACSI_CLASS_SGCB, + ACSI_CLASS_GoCB, + ACSI_CLASS_GsCB, + ACSI_CLASS_MSVCB, + ACSI_CLASS_USVCB +} ACSIClass; + /** * \brief Control model (represented by "ctlModel" attribute) */ diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index 3db3235e..b14bb6cb 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -1892,120 +1892,110 @@ 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; + /** - * \brief Callback that is called in case of RCB access to give the user the opportunity to block or allow the operation + * \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 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 + * \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_RCBAccessHandler) (void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType operation); +(*IedServer_DataSetAccessHandler) (void* parameter, ClientConnection connection, IedServer_DataSetOperation operation, const char* datasetRef); /** - * \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 + * \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_setRCBAccessHandler(IedServer self, IedServer_RCBAccessHandler handler, void* parameter); +IedServer_setDataSetAccessHandler(IedServer self, IedServer_DataSetAccessHandler handler, void* parameter); typedef enum { - LCB_EVENT_GET_PARAMETER, - LCB_EVENT_SET_PARAMETER -} IedServer_LCBEventType; + DIRECTORY_CAT_LD_LIST, + DIRECTORY_CAT_DATA_LIST, + DIRECTORY_CAT_DATASET_LIST, + DIRECTORY_CAT_LOG_LIST +} IedServer_DirectoryCategory; -/** - * \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); +(*IedServer_DirectoryAccessHandler) (void* parameter, ClientConnection connection, IedServer_DirectoryCategory category, LogicalDevice* logicalDevice); -/** - * \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); +IedServer_setDirectoryAccessHandler(IedServer self, IedServer_DirectoryAccessHandler handler, void* parameter); /** - * \brief Callback that is called when the client is trying to read log data - * + * \brief Callback that is called when a client is invoking a list objects service + * + * This callback can be used to control the list object access to specific objects and is called for each object that are subject to a client request. + * * \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 + * \param acsiClass the ACSI class of the object + * \param ld the logical device of the object + * \param ln the logical node of the object + * \param objectName the name of the object (e.g. data object name, data set name, log name, RCB name, ...) + * \param subObjectName the name of a sub element of an object or NULL + * \param fc the functional constraint of the object of IEC61850_FC_NONE when the object has no FC. + * + * \return true to include the object in the service response, otherwise false */ typedef bool -(*IedServer_LogAccessHandler) (void* parameter, const char* logRef, ClientConnection connection); +(*IedServer_ListObjectsAccessHandler)(void* parameter, ClientConnection connection, ACSIClass acsiClass, LogicalDevice* ld, LogicalNode* ln, const char* objectName, const char* subObjectName, FunctionalConstraint fc); /** - * \brief Set a handler control access to a log (read log data) - * + * \brief Set a handler to control which objects are return by the list objects services + * * \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); +IedServer_setListObjectsAccessHandler(IedServer self, IedServer_ListObjectsAccessHandler handler, void* parameter); typedef enum { - DATASET_CREATE, - DATASET_DELETE, - DATASET_READ, - DATASET_WRITE, - DATASET_GET_DIRECTORY -} IedServer_DataSetOperation; + IEC61850_CB_ACCESS_TYPE_READ, + IEC61850_CB_ACCESS_TYPE_WRITE +} IedServer_ControlBlockAccessType; /** - * \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 - * + * \brief Callback that is called when a client is invoking a read or write service to a control block or log + * + * This callback can be used to control the read and write access to control blocks and logs (SGCB, LCBs, URCBs, BRCBs, GoCBs, SVCBs, logs) + * * \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 + * \param acsiClass the ACSI class of the object + * \param ld the logical device of the object + * \param ln the logical node of the object + * \param objectName the name of the object (e.g. data object name, data set name, log name, RCB name, ...) + * \param subObjectName the name of a sub element of an object or NULL + * \param accessType access type (read=IEC61850_CB_ACCESS_TYPE_READ or write=IEC61850_CB_ACCESS_TYPE_WRITE) + * + * \return true to include the object in the service response, otherwise false */ typedef bool -(*IedServer_DataSetAccessHandler) (void* parameter, ClientConnection connection, IedServer_DataSetOperation operation, const char* datasetRef); +(*IedServer_ControlBlockAccessHandler)(void* parameter, ClientConnection connection, ACSIClass acsiClass, LogicalDevice* ld, LogicalNode* ln, const char* objectName, const char* subObjectName, IedServer_ControlBlockAccessType accessType); /** - * \brief Set a handler to control access to a dataset (create, delete, read, write, list directory) - * + * \brief Set a handler to control read and write access to control blocks and logs + * * \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); - -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); +IedServer_setControlBlockAccessHandler(IedServer self, IedServer_ControlBlockAccessHandler handler, void* parameter); /**@}*/ diff --git a/src/iec61850/inc_private/mms_mapping_internal.h b/src/iec61850/inc_private/mms_mapping_internal.h index 51714f11..1830b87c 100644 --- a/src/iec61850/inc_private/mms_mapping_internal.h +++ b/src/iec61850/inc_private/mms_mapping_internal.h @@ -338,20 +338,17 @@ struct sMmsMapping { IedServer_RCBEventHandler rcbEventHandler; void* rcbEventHandlerParameter; - IedServer_RCBAccessHandler rcbAccessHandler; - void* rcbAccessHandlerParameter; - - IedServer_LCBAccessHandler lcbAccessHandler; - void* lcbAccessHandlerParameter; - - IedServer_LogAccessHandler logAccessHandler; - void* logAccessHandlerParameter; - IedServer_DataSetAccessHandler dataSetAccessHandler; void* dataSetAccessHandlerParameter; IedServer_DirectoryAccessHandler directoryAccessHandler; void* directoryAccessHandlerParameter; + + IedServer_ListObjectsAccessHandler listObjectsAccessHandler; + void* listObjectsAccessHandlerParameter; + + IedServer_ControlBlockAccessHandler controlBlockAccessHandler; + void* controlBlockAccessHandlerParameter; }; #endif /* MMS_MAPPING_INTERNAL_H_ */ diff --git a/src/iec61850/inc_private/mms_sv.h b/src/iec61850/inc_private/mms_sv.h index c150a641..6f8663bf 100644 --- a/src/iec61850/inc_private/mms_sv.h +++ b/src/iec61850/inc_private/mms_sv.h @@ -38,7 +38,7 @@ LIBIEC61850_SV_createSVControlBlocks(MmsMapping* self, MmsDomain* domain, LogicalNode* logicalNode, int svCount, bool unicast); LIB61850_INTERNAL MmsValue* -LIBIEC61850_SV_readAccessSampledValueControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig); +LIBIEC61850_SV_readAccessSampledValueControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig , MmsServerConnection connection); LIB61850_INTERNAL MmsDataAccessError LIBIEC61850_SV_writeAccessSVControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index 27d40624..8a5c4baa 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -696,27 +696,6 @@ 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_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) { @@ -1967,3 +1946,17 @@ IedServer_setDirectoryAccessHandler(IedServer self, IedServer_DirectoryAccessHan self->mmsMapping->directoryAccessHandler = handler; self->mmsMapping->directoryAccessHandlerParameter = parameter; } + +void +IedServer_setListObjectsAccessHandler(IedServer self, IedServer_ListObjectsAccessHandler handler, void* parameter) +{ + self->mmsMapping->listObjectsAccessHandler = handler; + self->mmsMapping->listObjectsAccessHandlerParameter = parameter; +} + +void +IedServer_setControlBlockAccessHandler(IedServer self, IedServer_ControlBlockAccessHandler handler, void* parameter) +{ + self->mmsMapping->controlBlockAccessHandler = handler; + self->mmsMapping->controlBlockAccessHandlerParameter = parameter; +} diff --git a/src/iec61850/server/mms_mapping/logging.c b/src/iec61850/server/mms_mapping/logging.c index c55a1ff4..7fcb78f1 100644 --- a/src/iec61850/server/mms_mapping/logging.c +++ b/src/iec61850/server/mms_mapping/logging.c @@ -395,7 +395,6 @@ updateLogStatusInLCB(LogControl* self) } } - static void freeDynamicDataSet(LogControl* self) { @@ -524,13 +523,28 @@ LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* doma } else { - if (self->lcbAccessHandler) - { + if (self->controlBlockAccessHandler) { 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; + LogicalDevice* ld = IedModel_getDevice(self->model, domain->domainName); + + if (ld) { + LogicalNode* ln = LogicalDevice_getLogicalNode(ld, lnName); + if (ln) { + if (self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, ACSI_CLASS_LCB, ld, ln, logControl->logControlBlock->name, varName, IEC61850_CB_ACCESS_TYPE_WRITE) == false) { + retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + } + } + else { + retVal = DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT; + } + } + else { + retVal = DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT; + } + + if (retVal != DATA_ACCESS_ERROR_SUCCESS) { goto exit_function; } } @@ -747,14 +761,21 @@ LIBIEC61850_LOG_SVC_readAccessControlBlock(MmsMapping* self, MmsDomain* domain, { bool allowAccess = true; - if (self->lcbAccessHandler) - { + if (self->controlBlockAccessHandler) { ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); - if (self->lcbAccessHandler(self->lcbAccessHandlerParameter, logControl->logControlBlock, clientConnection, LCB_EVENT_GET_PARAMETER) == false) { - allowAccess = false; + LogicalDevice* ld = IedModel_getDevice(self->model, domain->domainName); + + if (ld) { + LogicalNode* ln = LogicalDevice_getLogicalNode(ld, lnName); - value = &objectAccessDenied; + if (ln) { + if (self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, ACSI_CLASS_LCB, ld, ln, logControl->logControlBlock->name, varName, IEC61850_CB_ACCESS_TYPE_READ) == false) { + allowAccess = false; + + value = &objectAccessDenied; + } + } } } diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index 2d76f39c..27471a58 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -2345,7 +2345,7 @@ lookupGCB(MmsMapping* self, MmsDomain* domain, char* lnName, char* objectName) static MmsDataAccessError writeAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, - MmsValue* value) + MmsValue* value, MmsServerConnection connection) { char variableId[130]; @@ -2377,6 +2377,20 @@ writeAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variable if (mmsGCB == NULL) return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + /* check if write access to GoCB is allowed on this connection */ + if (self->controlBlockAccessHandler) + { + LogicalNode* ln = MmsGooseControlBlock_getLogicalNode(mmsGCB); + + LogicalDevice* ld = (LogicalDevice*)ln->parent; + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + + if (self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, ACSI_CLASS_GoCB, ld, ln, MmsGooseControlBlock_getName(mmsGCB), varName, IEC61850_CB_ACCESS_TYPE_WRITE) == false) { + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + } + } + if (strcmp(varName, "GoEna") == 0) { if (MmsValue_getType(value) != MMS_BOOLEAN) return DATA_ACCESS_ERROR_TYPE_INCONSISTENT; @@ -2619,7 +2633,7 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, /* Goose control block - GO */ if (isGooseControlBlock(separator)) - return writeAccessGooseControlBlock(self, domain, variableId, value); + return writeAccessGooseControlBlock(self, domain, variableId, value, connection); #endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */ @@ -2701,6 +2715,42 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, char* nameId = nextSep + 1; + /* check access permissions */ + if (self->controlBlockAccessHandler) + { + MmsDataAccessError retVal = DATA_ACCESS_ERROR_SUCCESS; + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, + connection); + + LogicalDevice* ld = IedModel_getDevice(self->model, domain->domainName); + + if (ld) { + char lnName[65]; + strncpy(lnName, variableId, 64); + lnName[64] = 0; + lnName[lnNameLength] = 0; + + LogicalNode* ln = LogicalDevice_getLogicalNode(ld, lnName); + + if (ln) { + if (self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, ACSI_CLASS_SGCB, ld, ln, "SGCB", nameId, IEC61850_CB_ACCESS_TYPE_WRITE) == false) { + retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + } + } + else { + retVal = DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT; + } + } + else { + retVal = DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT; + } + + if (retVal != DATA_ACCESS_ERROR_SUCCESS) { + return retVal; + } + } + if (strcmp(nameId, "ActSG") == 0) { SettingGroup* sg = getSettingGroupByMmsDomain(self, domain); MmsDataAccessError retVal = DATA_ACCESS_ERROR_SUCCESS; @@ -2709,6 +2759,7 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, uint32_t val = MmsValue_toUint32(value); if ((val > 0) && (val <= sg->sgcb->numOfSGs)) { + if (val != sg->sgcb->actSG) { if (sg->actSgChangedHandler) { @@ -3026,7 +3077,7 @@ MmsMapping_installReadAccessHandler(MmsMapping* self, ReadAccessHandler handler, #if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) static MmsValue* -readAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig) +readAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, MmsServerConnection connection) { MmsValue* value = NULL; @@ -3050,13 +3101,28 @@ readAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variableI char* varName = MmsMapping_getNextNameElement(objectName); - if (varName != NULL) + if (varName) *(varName - 1) = 0; MmsGooseControlBlock mmsGCB = lookupGCB(self, domain, lnName, objectName); - if (mmsGCB != NULL) { - if (varName != NULL) { + if (mmsGCB) { + + /* check if read access to GoCB is allowed on this connection */ + if (self->controlBlockAccessHandler) + { + LogicalNode* ln = MmsGooseControlBlock_getLogicalNode(mmsGCB); + + LogicalDevice* ld = (LogicalDevice*)ln->parent; + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + + if (self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, ACSI_CLASS_GoCB, ld, ln, MmsGooseControlBlock_getName(mmsGCB), varName, IEC61850_CB_ACCESS_TYPE_READ) == false) { + return &objectAccessDenied; + } + } + + if (varName) { value = MmsValue_getSubElement(MmsGooseControlBlock_getMmsValues(mmsGCB), MmsGooseControlBlock_getVariableSpecification(mmsGCB), varName); } @@ -3070,7 +3136,6 @@ readAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variableI #endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */ - static MmsValue* mmsReadHandler(void* parameter, MmsDomain* domain, char* variableId, MmsServerConnection connection, bool isDirectAccess) { @@ -3100,7 +3165,7 @@ mmsReadHandler(void* parameter, MmsDomain* domain, char* variableId, MmsServerCo #if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) /* GOOSE control blocks - GO */ if (isGooseControlBlock(separator)) { - retValue = readAccessGooseControlBlock(self, domain, variableId); + retValue = readAccessGooseControlBlock(self, domain, variableId, connection); goto exit_function; } #endif @@ -3108,7 +3173,7 @@ mmsReadHandler(void* parameter, MmsDomain* domain, char* variableId, MmsServerCo #if (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1) /* Sampled Value control blocks - MS/US */ if (isSampledValueControlBlock(separator)) { - retValue = LIBIEC61850_SV_readAccessSampledValueControlBlock(self, domain, variableId); + retValue = LIBIEC61850_SV_readAccessSampledValueControlBlock(self, domain, variableId, connection); goto exit_function; } #endif @@ -3314,6 +3379,257 @@ mmsConnectionHandler(void* parameter, MmsServerConnection connection, MmsServerE } } +static bool +mmsListObjectsAccessHandler(void* parameter, MmsGetNameListType listType, MmsDomain* domain, char* variableId, MmsServerConnection connection) +{ + MmsMapping* self = (MmsMapping*) parameter; + + if (DEBUG_IED_SERVER) + printf("IED_SERVER: mmsListObjectsAccessHandler: Requested %s\n", variableId); + + bool allowAccess = true; + + if (listType == MMS_GETNAMELIST_DATASETS) + { + if (self->listObjectsAccessHandler) { + + char str[65]; + + char* ldName = MmsDomain_getName(domain); + + LogicalDevice* ld = IedModel_getDevice(self->model, ldName); + + LogicalNode* ln = NULL; + + char* objectName = variableId; + + char* separator = strchr(variableId, '$'); + + if (separator) { + StringUtils_createStringFromBufferInBuffer(str, (uint8_t*) variableId, separator - variableId); + + ln = LogicalDevice_getLogicalNode(ld, str); + + if (ln) { + objectName = separator + 1; + } + } + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + + allowAccess = self->listObjectsAccessHandler(self->listObjectsAccessHandlerParameter, clientConnection, ACSI_CLASS_DATA_SET, ld, ln, objectName, NULL, IEC61850_FC_NONE); + } + + return allowAccess; + } + else if (listType == MMS_GETNAMELIST_JOURNALS) + { + if (self->listObjectsAccessHandler) { + char str[65]; + + char* ldName = MmsDomain_getName(domain); + + char* objectName = variableId; + + LogicalDevice* ld = IedModel_getDevice(self->model, ldName); + + LogicalNode* ln = NULL; + + char* separator = strchr(variableId, '$'); + + if (separator) { + StringUtils_createStringFromBufferInBuffer(str, (uint8_t*) variableId, separator - variableId); + + ln = LogicalDevice_getLogicalNode(ld, str); + + if (ln) { + objectName = separator + 1; + } + } + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + + allowAccess = self->listObjectsAccessHandler(self->listObjectsAccessHandlerParameter, clientConnection, ACSI_CLASS_LOG, ld, ln, objectName, NULL, IEC61850_FC_NONE); + } + + return allowAccess; + } + + if (self->listObjectsAccessHandler) + { + char* separator = strchr(variableId, '$'); + char* ldName = MmsDomain_getName(domain); + + LogicalDevice* ld = IedModel_getDevice(self->model, ldName); + + if (ld) + { + FunctionalConstraint fc = IEC61850_FC_NONE; + + if (separator) { + fc = FunctionalConstraint_fromString(separator + 1); + + if (fc == IEC61850_FC_BR || fc == IEC61850_FC_US || + fc == IEC61850_FC_MS || fc == IEC61850_FC_RP || + fc == IEC61850_FC_LG || fc == IEC61850_FC_GO) + { + char* subObjectName = NULL; + + char str[65]; + char subObjectBuf[65]; + + StringUtils_createStringFromBufferInBuffer(str, (uint8_t*) variableId, separator - variableId); + + LogicalNode* ln = LogicalDevice_getLogicalNode(ld, str); + + if (ln) { + char* doStart = strchr(separator + 1, '$'); + + if (doStart != NULL) { + + char* doEnd = strchr(doStart + 1, '$'); + + if (doEnd == NULL) { + StringUtils_copyStringToBuffer(doStart + 1, str); + } + else { + doEnd--; + + StringUtils_createStringFromBufferInBuffer(str, (uint8_t*) (doStart + 1), doEnd - doStart); + + subObjectName = StringUtils_copyStringToBufferAndReplace(doEnd + 2, subObjectBuf, '$', '.'); + } + } + } + + ACSIClass acsiClass = ACSI_CLASS_USVCB; + + switch (fc) + { + case IEC61850_FC_BR: + acsiClass = ACSI_CLASS_BRCB; + break; + + case IEC61850_FC_RP: + acsiClass = ACSI_CLASS_URCB; + break; + + case IEC61850_FC_GO: + acsiClass = ACSI_CLASS_GoCB; + break; + + case IEC61850_FC_LG: + acsiClass = ACSI_CLASS_LCB; + break; + + case IEC61850_FC_MS: + acsiClass = ACSI_CLASS_MSVCB; + break; + + default: + break; + } + + if (self->listObjectsAccessHandler) { + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + + allowAccess = self->listObjectsAccessHandler(self->listObjectsAccessHandlerParameter, clientConnection, acsiClass, ld, ln, str, subObjectName, fc); + } + + goto exit_function; + } + else + { + char str[65]; + char* subObjectName = NULL; + char subObjectBuf[65]; + + StringUtils_createStringFromBufferInBuffer(str, (uint8_t*) variableId, separator - variableId); + + LogicalNode* ln = LogicalDevice_getLogicalNode(ld, str); + + if (ln != NULL) + { + char* doStart = strchr(separator + 1, '$'); + + if (doStart != NULL) { + + char* doEnd = strchr(doStart + 1, '$'); + + if (doEnd == NULL) { + StringUtils_copyStringToBuffer(doStart + 1, str); + } + else { + doEnd--; + + StringUtils_createStringFromBufferInBuffer(str, (uint8_t*) (doStart + 1), doEnd - doStart); + + subObjectName = StringUtils_copyStringToBufferAndReplace(doEnd + 2, subObjectBuf, '$', '.'); + } + + if (fc == IEC61850_FC_SP) { + if (!strcmp(str, "SGCB")) { + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, + connection); + + allowAccess = self->listObjectsAccessHandler(self->listObjectsAccessHandlerParameter, clientConnection, ACSI_CLASS_SGCB, ld, ln, str, subObjectName, fc); + + goto exit_function; + } + } + + ModelNode* dobj = ModelNode_getChild((ModelNode*) ln, str); + + if (dobj != NULL) { + + if (dobj->modelType == DataObjectModelType) { + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, + connection); + + if (self->listObjectsAccessHandler) { + allowAccess = self->listObjectsAccessHandler(self->listObjectsAccessHandlerParameter, clientConnection, ACSI_CLASS_DATA_OBJECT, ld, ln, dobj->name, subObjectName, fc); + } + } + } + } + else { + /* no data object but with FC specified */ + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, + connection); + + if (self->listObjectsAccessHandler) { + allowAccess = self->listObjectsAccessHandler(self->listObjectsAccessHandlerParameter, clientConnection, ACSI_CLASS_DATA_OBJECT, ld, ln, NULL, NULL, fc); + } + } + } + } + } + else { + LogicalNode* ln = LogicalDevice_getLogicalNode(ld, variableId); + + if (ln) { + /* only LN, no FC specified */ + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + + if (self->listObjectsAccessHandler) { + allowAccess = self->listObjectsAccessHandler(self->listObjectsAccessHandlerParameter, clientConnection, ACSI_CLASS_DATA_OBJECT, ld, ln, NULL, NULL, fc); + } + } + } + } + else { + /* internal error ? - we should not end up here! */ + } + } + +exit_function: + return allowAccess; +} + static MmsDataAccessError mmsReadAccessHandler (void* parameter, MmsDomain* domain, char* variableId, MmsServerConnection connection, bool isDirectAccess) { @@ -3350,11 +3666,9 @@ mmsReadAccessHandler (void* parameter, MmsDomain* domain, char* variableId, MmsS LogicalDevice* ld = IedModel_getDevice(self->model, ldName); - if (ld != NULL) { - - char str[65]; - - FunctionalConstraint fc; + if (ld != NULL) + { + FunctionalConstraint fc = IEC61850_FC_NONE; if (separator != NULL) { fc = FunctionalConstraint_fromString(separator + 1); @@ -3367,6 +3681,8 @@ mmsReadAccessHandler (void* parameter, MmsDomain* domain, char* variableId, MmsS } else { + char str[65]; + StringUtils_createStringFromBufferInBuffer(str, (uint8_t*) variableId, separator - variableId); LogicalNode* ln = LogicalDevice_getLogicalNode(ld, str); @@ -3390,7 +3706,18 @@ mmsReadAccessHandler (void* parameter, MmsDomain* domain, char* variableId, MmsS if (fc == IEC61850_FC_SP) { if (!strcmp(str, "SGCB")) + { + if (self->controlBlockAccessHandler) { + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, + connection); + + if (self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, ACSI_CLASS_SGCB, ld, ln, str, "", IEC61850_CB_ACCESS_TYPE_READ) == false) { + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + } + } + return DATA_ACCESS_ERROR_SUCCESS; + } } ModelNode* dobj = ModelNode_getChild((ModelNode*) ln, str); @@ -3417,6 +3744,16 @@ mmsReadAccessHandler (void* parameter, MmsDomain* domain, char* variableId, MmsS } } } + else { + LogicalNode* ln = LogicalDevice_getLogicalNode(ld, variableId); + + if (ln != NULL) { + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + + return self->readAccessHandler(ld, ln, NULL, fc, clientConnection, + self->readAccessHandlerParameter); + } + } } return DATA_ACCESS_ERROR_OBJECT_ACCESS_UNSUPPORTED; @@ -3643,17 +3980,29 @@ mmsReadJournalHandler(void* parameter, MmsDomain* domain, const char* logName, M MmsMapping* self = (MmsMapping*)parameter; - if (self->logAccessHandler) { - char logReference[130]; - logReference[0] = 0; + if (self->controlBlockAccessHandler) { + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); - StringUtils_appendString(logReference, 130, MmsDomain_getName(domain)); - StringUtils_appendString(logReference, 130, "/"); - StringUtils_appendString(logReference, 130, logName); + LogicalDevice* ld = IedModel_getDevice(self->model, domain->domainName); - ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + LogicalNode* ln = NULL; + + char str[65]; + + StringUtils_copyStringMax(str, 65, logName); + + char* name = str; + + char* separator = strchr(str, '$'); + + if (separator) { + name = separator + 1; + *separator = 0; + + ln = LogicalDevice_getLogicalNode(ld, str); + } - allowAccess = self->logAccessHandler(self->logAccessHandlerParameter, logReference, clientConnection); + allowAccess = self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, ACSI_CLASS_LOG, ld, ln, name, NULL, IEC61850_CB_ACCESS_TYPE_READ); } return allowAccess; @@ -3666,6 +4015,7 @@ MmsMapping_installHandlers(MmsMapping* self) MmsServer_installReadHandler(self->mmsServer, mmsReadHandler, (void*) self); MmsServer_installWriteHandler(self->mmsServer, mmsWriteHandler, (void*) self); MmsServer_installReadAccessHandler(self->mmsServer, mmsReadAccessHandler, (void*) self); + MmsServer_installListAccessHandler(self->mmsServer, mmsListObjectsAccessHandler, (void*) self); MmsServer_installConnectionHandler(self->mmsServer, mmsConnectionHandler, (void*) self); MmsServer_installVariableListAccessHandler(self->mmsServer, variableListAccessHandler, (void*) self); MmsServer_installGetNameListHandler(self->mmsServer, mmsGetNameListHandler, (void*) self); diff --git a/src/iec61850/server/mms_mapping/mms_sv.c b/src/iec61850/server/mms_mapping/mms_sv.c index a03652f1..ef2ad775 100644 --- a/src/iec61850/server/mms_mapping/mms_sv.c +++ b/src/iec61850/server/mms_mapping/mms_sv.c @@ -1,7 +1,7 @@ /* * mms_sv.c * - * Copyright 2015-2022 Michael Zillgith + * Copyright 2015-2023 Michael Zillgith * * This file is part of libIEC61850. * @@ -32,6 +32,8 @@ #include "mms_sv.h" #include "mms_mapping_internal.h" +#include "ied_server_private.h" +#include "mms_value_internal.h" struct sMmsSampledValueControlBlock { SVControlBlock* svcb; @@ -50,11 +52,12 @@ struct sMmsSampledValueControlBlock { MmsValue* svEnaValue; MmsValue* resvValue; - SVCBEventHandler eventHandler; void* eventHandlerParameter; }; +static MmsValue objectAccessDenied = {MMS_DATA_ACCESS_ERROR, false, {DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED}}; + MmsSampledValueControlBlock MmsSampledValueControlBlock_create() { @@ -63,7 +66,6 @@ MmsSampledValueControlBlock_create() return self; } - void MmsSampledValueControlBlock_destroy(MmsSampledValueControlBlock self) { @@ -105,7 +107,8 @@ MmsSampledValueControlBlock_enable(MmsSampledValueControlBlock self) if (DEBUG_IED_SERVER) printf("IED_SERVER: enable SVCB %s\n", self->svcb->name); - self->eventHandler(self->svcb, IEC61850_SVCB_EVENT_ENABLE, self->eventHandlerParameter); + if (self->eventHandler) + self->eventHandler(self->svcb, IEC61850_SVCB_EVENT_ENABLE, self->eventHandlerParameter); } static void @@ -117,7 +120,8 @@ MmsSampledValueControlBlock_disable(MmsSampledValueControlBlock self) if (DEBUG_IED_SERVER) printf("IED_SERVER: disable SVCB %s\n", self->svcb->name); - self->eventHandler(self->svcb, IEC61850_SVCB_EVENT_DISABLE, self->eventHandlerParameter); + if (self->eventHandler) + self->eventHandler(self->svcb, IEC61850_SVCB_EVENT_DISABLE, self->eventHandlerParameter); } static bool @@ -150,7 +154,7 @@ LIBIEC61850_SV_writeAccessSVControlBlock(MmsMapping* self, MmsDomain* domain, ch char* varName = MmsMapping_getNextNameElement(objectName); - if (varName != NULL) + if (varName) *(varName - 1) = 0; else return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; @@ -160,7 +164,28 @@ LIBIEC61850_SV_writeAccessSVControlBlock(MmsMapping* self, MmsDomain* domain, ch if (mmsSVCB == NULL) return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; - if (mmsSVCB->reservedByClient != NULL) { + /* check if write access to SVCB is allowed on this connection */ + if (self->controlBlockAccessHandler) + { + ACSIClass acsiClass; + + if (mmsSVCB->svcb->isUnicast) + acsiClass = ACSI_CLASS_USVCB; + else + acsiClass = ACSI_CLASS_MSVCB; + + LogicalNode* ln = mmsSVCB->logicalNode; + + LogicalDevice* ld = (LogicalDevice*)ln->parent; + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + + if (self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, acsiClass, ld, ln, mmsSVCB->svcb->name, varName, IEC61850_CB_ACCESS_TYPE_WRITE) == false) { + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + } + } + + if (mmsSVCB->reservedByClient) { if (mmsSVCB->reservedByClient != connection) return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; } @@ -209,7 +234,7 @@ LIBIEC61850_SV_writeAccessSVControlBlock(MmsMapping* self, MmsDomain* domain, ch } MmsValue* -LIBIEC61850_SV_readAccessSampledValueControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig) +LIBIEC61850_SV_readAccessSampledValueControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, MmsServerConnection connection) { MmsValue* value = NULL; @@ -233,13 +258,35 @@ LIBIEC61850_SV_readAccessSampledValueControlBlock(MmsMapping* self, MmsDomain* d char* varName = MmsMapping_getNextNameElement(objectName); - if (varName != NULL) + if (varName) *(varName - 1) = 0; MmsSampledValueControlBlock mmsSVCB = lookupSVCB(self, domain, lnName, objectName); - if (mmsSVCB != NULL) { - if (varName != NULL) { + if (mmsSVCB) { + + /* check if read access to SVCB is allowed on this connection */ + if (self->controlBlockAccessHandler) + { + ACSIClass acsiClass; + + if (mmsSVCB->svcb->isUnicast) + acsiClass = ACSI_CLASS_USVCB; + else + acsiClass = ACSI_CLASS_MSVCB; + + LogicalNode* ln = mmsSVCB->logicalNode; + + LogicalDevice* ld = (LogicalDevice*)ln->parent; + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + + if (self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, acsiClass, ld, ln, mmsSVCB->svcb->name, varName, IEC61850_CB_ACCESS_TYPE_READ) == false) { + return &objectAccessDenied; + } + } + + if (varName) { value = MmsValue_getSubElement(mmsSVCB->mmsValue, mmsSVCB->mmsType, varName); } else { diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index 9cbbb4f2..493d5e48 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -724,9 +724,23 @@ updateReportDataset(MmsMapping* mapping, ReportControl* rc, MmsValue* newDatSet, success = true; dataSetValue = NULL; - if (rc->buffered) { - rc->isBuffering = false; - purgeBuf(rc); + if (rc->dataSet) { + if (rc->buffered) { + rc->isBuffering = false; + purgeBuf(rc); + } + + /* delete pending events */ + deleteDataSetValuesShadowBuffer(rc); + + if (isUsedDataSetDynamic) { + if (rc->dataSet) { + MmsMapping_freeDynamicallyCreatedDataSet(rc->dataSet); + } + } + + /* release used data set */ + rc->dataSet = NULL; } } else @@ -739,7 +753,6 @@ updateReportDataset(MmsMapping* mapping, ReportControl* rc, MmsValue* newDatSet, /* check if old and new data sets are the same */ if (rc->dataSet && dataSetValue) { - const char* dataSetLdName = rc->dataSet->logicalDeviceName; const char* dataSetName = rc->dataSet->name; const char* newDataSetName = MmsValue_toString(dataSetValue); @@ -790,7 +803,8 @@ updateReportDataset(MmsMapping* mapping, ReportControl* rc, MmsValue* newDatSet, } } - if (dataSetValue) { + if (dataSetValue) + { const char* dataSetName = MmsValue_toString(dataSetValue); DataSet* dataSet = IedModel_lookupDataSet(mapping->model, dataSetName); @@ -1777,12 +1791,24 @@ ReportControl_readAccess(ReportControl* rc, MmsMapping* mmsMapping, MmsServerCon ClientConnection clientConnection = NULL; - if (mmsMapping->rcbAccessHandler || mmsMapping->rcbEventHandler) { + if (mmsMapping->controlBlockAccessHandler || 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) { + if (mmsMapping->controlBlockAccessHandler) + { + ACSIClass acsiClass; + + if (rc->rcb->buffered) + acsiClass = ACSI_CLASS_BRCB; + else + acsiClass = ACSI_CLASS_URCB; + + LogicalNode* ln = rc->rcb->parent; + + LogicalDevice* ld = (LogicalDevice*)ln->parent; + + if (mmsMapping->controlBlockAccessHandler(mmsMapping->controlBlockAccessHandlerParameter, clientConnection, acsiClass, ld, ln, rc->rcb->name, elementName, IEC61850_CB_ACCESS_TYPE_READ) == false) { accessError = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; accessAllowed = false; } @@ -1891,8 +1917,20 @@ 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) { + if (self->controlBlockAccessHandler) + { + ACSIClass acsiClass; + + if (rc->rcb->buffered) + acsiClass = ACSI_CLASS_BRCB; + else + acsiClass = ACSI_CLASS_URCB; + + LogicalNode* ln = rc->rcb->parent; + + LogicalDevice* ld = (LogicalDevice*)ln->parent; + + if (self->controlBlockAccessHandler(self->controlBlockAccessHandlerParameter, clientConnection, acsiClass, ld, ln, rc->rcb->name, elementName, IEC61850_CB_ACCESS_TYPE_WRITE) == false) { retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; goto exit_function_only_tracking; diff --git a/src/mms/inc_private/mms_server_internal.h b/src/mms/inc_private/mms_server_internal.h index ec70d359..08d0988a 100644 --- a/src/mms/inc_private/mms_server_internal.h +++ b/src/mms/inc_private/mms_server_internal.h @@ -120,6 +120,9 @@ struct sMmsServer { MmsWriteVariableHandler writeHandler; void* writeHandlerParameter; + MmsListAccessHandler listAccessHandler; + void* listAccessHandlerParameter; + MmsConnectionHandler connectionHandler; void* connectionHandlerParameter; @@ -422,6 +425,9 @@ mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* va LIB61850_INTERNAL MmsValue* mmsServer_getValue(MmsServer self, MmsDomain* domain, char* itemId, MmsServerConnection connection, bool isDirectAccess); +LIB61850_INTERNAL bool +mmsServer_checkListAccess(MmsServer self, MmsGetNameListType listType, MmsDomain* domain, char* itemId, MmsServerConnection connection); + LIB61850_INTERNAL void mmsServer_createMmsWriteResponse(MmsServerConnection connection, uint32_t invokeId, ByteBuffer* response, int numberOfItems, MmsDataAccessError* accessResults); diff --git a/src/mms/inc_private/mms_server_libinternal.h b/src/mms/inc_private/mms_server_libinternal.h index 444989c9..bdaf4b68 100644 --- a/src/mms/inc_private/mms_server_libinternal.h +++ b/src/mms/inc_private/mms_server_libinternal.h @@ -37,6 +37,9 @@ typedef MmsDataAccessError (*MmsWriteVariableHandler)(void* parameter, MmsDomain* domain, char* variableId, MmsValue* value, MmsServerConnection connection); +typedef bool (*MmsListAccessHandler) (void* parameter, MmsGetNameListType listType, MmsDomain* domain, + char* variableId, MmsServerConnection connection); + typedef void (*MmsConnectionHandler)(void* parameter, MmsServerConnection connection, MmsServerEvent event); @@ -63,6 +66,9 @@ LIB61850_INTERNAL void MmsServer_installWriteHandler(MmsServer self, MmsWriteVariableHandler, void* parameter); +LIB61850_INTERNAL void +MmsServer_installListAccessHandler(MmsServer self, MmsListAccessHandler listAccessHandler, void* parameter); + /** * A connection handler will be invoked whenever a new client connection is opened or closed */ diff --git a/src/mms/iso_mms/client/mms_client_connection.c b/src/mms/iso_mms/client/mms_client_connection.c index a9763c08..6f743b0b 100644 --- a/src/mms/iso_mms/client/mms_client_connection.c +++ b/src/mms/iso_mms/client/mms_client_connection.c @@ -436,7 +436,17 @@ convertServiceErrorToMmsError(MmsServiceError serviceError) break; case 4: /* class: service */ - mmsError = MMS_ERROR_SERVICE_OTHER; + + switch (serviceError.errorCode) + { + case 5: + mmsError = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT; + break; + + default: + mmsError = MMS_ERROR_SERVICE_OTHER; + break; + } break; case 5: /* class: service-preempt */ 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 2170f8c1..e42dd25a 100644 --- a/src/mms/iso_mms/server/mms_get_namelist_service.c +++ b/src/mms/iso_mms/server/mms_get_namelist_service.c @@ -129,7 +129,7 @@ appendMmsSubVariable(char* name, char* child) } static LinkedList -addSubNamedVaribleNamesToList(LinkedList nameList, char* prefix, MmsVariableSpecification* variable) +addSubNamedVaribleNamesToList(MmsServerConnection connection, LinkedList nameList, MmsDomain* domain, char* prefix, MmsVariableSpecification* variable) { LinkedList listElement = nameList; @@ -158,14 +158,23 @@ addSubNamedVaribleNamesToList(LinkedList nameList, char* prefix, MmsVariableSpec #endif /* (CONFIG_MMS_SORT_NAME_LIST == 1) */ if (variableName) - { - listElement = LinkedList_insertAfter(listElement, variableName); + { + bool accessAllowed = mmsServer_checkListAccess(connection->server, MMS_GETNAMELIST_DATA, domain, variableName, connection); + + if (accessAllowed) { + + listElement = LinkedList_insertAfter(listElement, variableName); #if (CONFIG_MMS_SORT_NAME_LIST == 1) - listElement = addSubNamedVaribleNamesToList(listElement, variableName, variables[index[i]]); + listElement = addSubNamedVaribleNamesToList(connection, listElement, domain, variableName, variables[index[i]]); #else - listElement = addSubNamedVaribleNamesToList(listElement, variableName, variables[i]); + listElement = addSubNamedVaribleNamesToList(connection, listElement, domain, variableName, variables[i]); #endif /* (CONFIG_MMS_SORT_NAME_LIST == 1) */ + + } + else { + GLOBAL_FREEMEM(variableName); + } } } @@ -209,7 +218,11 @@ getJournalListDomainSpecific(MmsServerConnection connection, char* domainName) MmsJournal journal = (MmsJournal) LinkedList_getData(journalList); - LinkedList_add(nameList, (void*) journal->name); + allowAccess = mmsServer_checkListAccess(connection->server, MMS_GETNAMELIST_JOURNALS, domain, journal->name, connection); + + if (allowAccess) { + LinkedList_add(nameList, (void*) journal->name); + } } } @@ -233,7 +246,7 @@ getNameListDomainSpecific(MmsServerConnection connection, char* domainName) bool allowAccess = true; if (connection->server->getNameListHandler) { - allowAccess = connection->server->getNameListHandler(connection->server->getNameListHandlerParameter, MMS_GETNAMELIST_DATASETS, domain, connection); + allowAccess = connection->server->getNameListHandler(connection->server->getNameListHandlerParameter, MMS_GETNAMELIST_DATA, domain, connection); } if (allowAccess) { @@ -255,22 +268,28 @@ getNameListDomainSpecific(MmsServerConnection connection, char* domainName) for (i = 0; i < domain->namedVariablesCount; i++) { + bool accessAllowed = mmsServer_checkListAccess(connection->server, MMS_GETNAMELIST_DATA, domain, variables[index[i]]->name, connection); + + if (accessAllowed) { + #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(connection, element, domain, prefix, variables[index[i]]); #else - char* prefix = variables[i]->name; - element = addSubNamedVaribleNamesToList(element, prefix, variables[i]); + char* prefix = variables[i]->name; + element = addSubNamedVaribleNamesToList(connection, element, domain, 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) @@ -286,7 +305,7 @@ getNameListDomainSpecific(MmsServerConnection connection, char* domainName) #if (MMS_DATA_SET_SERVICE == 1) static LinkedList -createStringsFromNamedVariableList(LinkedList variableLists) +createStringsFromNamedVariableList(LinkedList variableLists, MmsServerConnection connection, MmsDomain* domain) { LinkedList nameList = LinkedList_create(); LinkedList variableListsElement = LinkedList_getNext(variableLists); @@ -295,8 +314,12 @@ createStringsFromNamedVariableList(LinkedList variableLists) MmsNamedVariableList variableList = (MmsNamedVariableList) variableListsElement->data; - LinkedList_add(nameList, - StringUtils_copyString(MmsNamedVariableList_getName(variableList))); + bool accessAllowed = mmsServer_checkListAccess(connection->server, MMS_GETNAMELIST_DATASETS, domain, variableList->name, connection); + + if (accessAllowed) { + LinkedList_add(nameList, + StringUtils_copyString(MmsNamedVariableList_getName(variableList))); + } variableListsElement = LinkedList_getNext(variableListsElement); } @@ -323,7 +346,7 @@ getNamedVariableListsDomainSpecific(MmsServerConnection connection, char* domain if (allowAccess) { LinkedList variableLists = MmsDomain_getNamedVariableLists(domain); - nameList = createStringsFromNamedVariableList(variableLists); + nameList = createStringsFromNamedVariableList(variableLists, connection, domain); } } @@ -339,7 +362,7 @@ getNamedVariableListsVMDSpecific(MmsServerConnection connection) LinkedList variableLists = MmsDevice_getNamedVariableLists(device); - nameList = createStringsFromNamedVariableList(variableLists); + nameList = createStringsFromNamedVariableList(variableLists, connection, NULL); return nameList; } @@ -352,7 +375,7 @@ getNamedVariableListAssociationSpecific(MmsServerConnection connection) LinkedList variableLists = MmsServerConnection_getNamedVariableLists(connection); - nameList = createStringsFromNamedVariableList(variableLists); + nameList = createStringsFromNamedVariableList(variableLists, connection, NULL); return nameList; } diff --git a/src/mms/iso_mms/server/mms_get_var_access_service.c b/src/mms/iso_mms/server/mms_get_var_access_service.c index abdf6d02..c27ff76b 100644 --- a/src/mms/iso_mms/server/mms_get_var_access_service.c +++ b/src/mms/iso_mms/server/mms_get_var_access_service.c @@ -1,7 +1,7 @@ /* * mms_get_var_access_service.c * - * Copyright 2013 Michael Zillgith + * Copyright 2013-2023 Michael Zillgith * * This file is part of libIEC61850. * @@ -32,236 +32,250 @@ static int createTypeSpecification ( - MmsVariableSpecification* namedVariable, - TypeSpecification_t* typeSpec) + MmsVariableSpecification* namedVariable, + TypeSpecification_t* typeSpec) { - if (namedVariable->type == MMS_ARRAY) { - typeSpec->present = TypeSpecification_PR_array; - - asn_long2INTEGER(&(typeSpec->choice.array.numberOfElements), - (long) namedVariable->typeSpec.array.elementCount); - - typeSpec->choice.array.packed = NULL; - typeSpec->choice.array.elementType = (TypeSpecification_t*) GLOBAL_CALLOC(1, sizeof(TypeSpecification_t)); - - createTypeSpecification(namedVariable->typeSpec.array.elementTypeSpec, - typeSpec->choice.array.elementType); - } - else if (namedVariable->type == MMS_STRUCTURE) { - - typeSpec->present = TypeSpecification_PR_structure; - - int componentCount = namedVariable->typeSpec.structure.elementCount; - - typeSpec->choice.structure.components.list.count = componentCount; - typeSpec->choice.structure.components.list.size = componentCount; - - typeSpec->choice.structure.components.list.array - = (StructComponent_t**) GLOBAL_CALLOC(componentCount, sizeof(StructComponent_t*)); - - int i; - - for (i = 0; i < componentCount; i++) { - - typeSpec->choice.structure.components.list.array[i] = - (StructComponent_t*) GLOBAL_CALLOC(1, sizeof(StructComponent_t)); - - typeSpec->choice.structure.components.list.array[i]->componentName = - (Identifier_t*) GLOBAL_CALLOC(1, sizeof(Identifier_t)); - - typeSpec->choice.structure.components.list.array[i]->componentName->buf = - (uint8_t*) StringUtils_copyString(namedVariable->typeSpec.structure.elements[i]->name); - - typeSpec->choice.structure.components.list.array[i]->componentName->size = - strlen(namedVariable->typeSpec.structure.elements[i]->name); - - typeSpec->choice.structure.components.list.array[i]->componentType = - (TypeSpecification_t*) GLOBAL_CALLOC(1, sizeof(TypeSpecification_t)); - - createTypeSpecification(namedVariable->typeSpec.structure.elements[i], - typeSpec->choice.structure.components.list.array[i]->componentType); - } - } - else { - - switch (namedVariable->type) { - case MMS_BOOLEAN: - typeSpec->present = TypeSpecification_PR_boolean; - break; - case MMS_BIT_STRING: - typeSpec->present = TypeSpecification_PR_bitstring; - typeSpec->choice.bitstring = namedVariable->typeSpec.bitString; - break; - case MMS_INTEGER: - typeSpec->present = TypeSpecification_PR_integer; - typeSpec->choice.integer = namedVariable->typeSpec.integer; - break; - case MMS_UNSIGNED: - typeSpec->present = TypeSpecification_PR_unsigned; - typeSpec->choice.Unsigned = namedVariable->typeSpec.unsignedInteger; - break; - case MMS_FLOAT: - typeSpec->present = TypeSpecification_PR_floatingpoint; - typeSpec->choice.floatingpoint.exponentwidth = - namedVariable->typeSpec.floatingpoint.exponentWidth; - typeSpec->choice.floatingpoint.formatwidth = - namedVariable->typeSpec.floatingpoint.formatWidth; - break; - case MMS_OCTET_STRING: - typeSpec->present = TypeSpecification_PR_octetstring; - typeSpec->choice.octetstring = namedVariable->typeSpec.octetString; - break; - case MMS_VISIBLE_STRING: - typeSpec->present = TypeSpecification_PR_visiblestring; - typeSpec->choice.visiblestring = namedVariable->typeSpec.visibleString; - break; - case MMS_STRING: - typeSpec->present = TypeSpecification_PR_mMSString; - typeSpec->choice.mMSString = namedVariable->typeSpec.mmsString; - break; - case MMS_UTC_TIME: - typeSpec->present = TypeSpecification_PR_utctime; - break; - case MMS_BINARY_TIME: - typeSpec->present = TypeSpecification_PR_binarytime; - - if (namedVariable->typeSpec.binaryTime == 6) - typeSpec->choice.binarytime = 1; - else - typeSpec->choice.binarytime = 0; - - break; - default: - if (DEBUG_MMS_SERVER) - printf("MMS-SERVER: Unsupported type %i!\n", namedVariable->type); - return -1; - break; - } - } - - return 1; + if (namedVariable->type == MMS_ARRAY) { + typeSpec->present = TypeSpecification_PR_array; + + asn_long2INTEGER(&(typeSpec->choice.array.numberOfElements), + (long) namedVariable->typeSpec.array.elementCount); + + typeSpec->choice.array.packed = NULL; + typeSpec->choice.array.elementType = (TypeSpecification_t*) GLOBAL_CALLOC(1, sizeof(TypeSpecification_t)); + + createTypeSpecification(namedVariable->typeSpec.array.elementTypeSpec, + typeSpec->choice.array.elementType); + } + else if (namedVariable->type == MMS_STRUCTURE) { + + typeSpec->present = TypeSpecification_PR_structure; + + int componentCount = namedVariable->typeSpec.structure.elementCount; + + typeSpec->choice.structure.components.list.count = componentCount; + typeSpec->choice.structure.components.list.size = componentCount; + + typeSpec->choice.structure.components.list.array + = (StructComponent_t**) GLOBAL_CALLOC(componentCount, sizeof(StructComponent_t*)); + + int i; + + for (i = 0; i < componentCount; i++) { + + typeSpec->choice.structure.components.list.array[i] = + (StructComponent_t*) GLOBAL_CALLOC(1, sizeof(StructComponent_t)); + + typeSpec->choice.structure.components.list.array[i]->componentName = + (Identifier_t*) GLOBAL_CALLOC(1, sizeof(Identifier_t)); + + typeSpec->choice.structure.components.list.array[i]->componentName->buf = + (uint8_t*) StringUtils_copyString(namedVariable->typeSpec.structure.elements[i]->name); + + typeSpec->choice.structure.components.list.array[i]->componentName->size = + strlen(namedVariable->typeSpec.structure.elements[i]->name); + + typeSpec->choice.structure.components.list.array[i]->componentType = + (TypeSpecification_t*) GLOBAL_CALLOC(1, sizeof(TypeSpecification_t)); + + createTypeSpecification(namedVariable->typeSpec.structure.elements[i], + typeSpec->choice.structure.components.list.array[i]->componentType); + } + } + else { + + switch (namedVariable->type) { + case MMS_BOOLEAN: + typeSpec->present = TypeSpecification_PR_boolean; + break; + case MMS_BIT_STRING: + typeSpec->present = TypeSpecification_PR_bitstring; + typeSpec->choice.bitstring = namedVariable->typeSpec.bitString; + break; + case MMS_INTEGER: + typeSpec->present = TypeSpecification_PR_integer; + typeSpec->choice.integer = namedVariable->typeSpec.integer; + break; + case MMS_UNSIGNED: + typeSpec->present = TypeSpecification_PR_unsigned; + typeSpec->choice.Unsigned = namedVariable->typeSpec.unsignedInteger; + break; + case MMS_FLOAT: + typeSpec->present = TypeSpecification_PR_floatingpoint; + typeSpec->choice.floatingpoint.exponentwidth = + namedVariable->typeSpec.floatingpoint.exponentWidth; + typeSpec->choice.floatingpoint.formatwidth = + namedVariable->typeSpec.floatingpoint.formatWidth; + break; + case MMS_OCTET_STRING: + typeSpec->present = TypeSpecification_PR_octetstring; + typeSpec->choice.octetstring = namedVariable->typeSpec.octetString; + break; + case MMS_VISIBLE_STRING: + typeSpec->present = TypeSpecification_PR_visiblestring; + typeSpec->choice.visiblestring = namedVariable->typeSpec.visibleString; + break; + case MMS_STRING: + typeSpec->present = TypeSpecification_PR_mMSString; + typeSpec->choice.mMSString = namedVariable->typeSpec.mmsString; + break; + case MMS_UTC_TIME: + typeSpec->present = TypeSpecification_PR_utctime; + break; + case MMS_BINARY_TIME: + typeSpec->present = TypeSpecification_PR_binarytime; + + if (namedVariable->typeSpec.binaryTime == 6) + typeSpec->choice.binarytime = 1; + else + typeSpec->choice.binarytime = 0; + + break; + default: + if (DEBUG_MMS_SERVER) + printf("MMS-SERVER: Unsupported type %i!\n", namedVariable->type); + return -1; + break; + } + } + + return 1; } static void freeTypeSpecRecursive(TypeSpecification_t* typeSpec) { - if (typeSpec->present == TypeSpecification_PR_structure) { - int elementCount = - typeSpec->choice.structure.components.list.count; - - int i; - - for (i = 0; i < elementCount; i++) { - GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array[i]->componentName->buf); - GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array[i]->componentName); - freeTypeSpecRecursive(typeSpec->choice.structure.components.list.array[i]->componentType); - GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array[i]->componentType); - GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array[i]); - } - - GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array); - } - else if (typeSpec->present == TypeSpecification_PR_array) { - GLOBAL_FREEMEM(typeSpec->choice.array.numberOfElements.buf); - freeTypeSpecRecursive(typeSpec->choice.array.elementType); - GLOBAL_FREEMEM(typeSpec->choice.array.elementType); - } + if (typeSpec->present == TypeSpecification_PR_structure) { + int elementCount = + typeSpec->choice.structure.components.list.count; + + int i; + + for (i = 0; i < elementCount; i++) { + GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array[i]->componentName->buf); + GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array[i]->componentName); + freeTypeSpecRecursive(typeSpec->choice.structure.components.list.array[i]->componentType); + GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array[i]->componentType); + GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array[i]); + } + + GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array); + } + else if (typeSpec->present == TypeSpecification_PR_array) { + GLOBAL_FREEMEM(typeSpec->choice.array.numberOfElements.buf); + freeTypeSpecRecursive(typeSpec->choice.array.elementType); + GLOBAL_FREEMEM(typeSpec->choice.array.elementType); + } } static void deleteVariableAccessAttributesResponse( - GetVariableAccessAttributesResponse_t* getVarAccessAttr) + GetVariableAccessAttributesResponse_t* getVarAccessAttr) { - if (getVarAccessAttr->typeSpecification.present == TypeSpecification_PR_structure) { - int count = getVarAccessAttr->typeSpecification.choice.structure.components.list.count; - - int i; - for (i = 0; i < count; i++) { - GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]->componentName->buf); - GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]->componentName); - TypeSpecification_t* typeSpec = - getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]->componentType; - freeTypeSpecRecursive(typeSpec); - GLOBAL_FREEMEM(typeSpec); - GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]); - } - - GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.structure.components.list.array); - - getVarAccessAttr->typeSpecification.choice.structure.components.list.array = NULL; - getVarAccessAttr->typeSpecification.choice.structure.components.list.count = 0; - getVarAccessAttr->typeSpecification.choice.structure.components.list.size = 0; - } else if (getVarAccessAttr->typeSpecification.present == TypeSpecification_PR_array) { - GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.array.numberOfElements.buf); - getVarAccessAttr->typeSpecification.choice.array.numberOfElements.buf = NULL; - getVarAccessAttr->typeSpecification.choice.array.numberOfElements.size = 0; - freeTypeSpecRecursive(getVarAccessAttr->typeSpecification.choice.array.elementType); - - GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.array.elementType); - - getVarAccessAttr->typeSpecification.choice.array.elementType = NULL; - } + if (getVarAccessAttr->typeSpecification.present == TypeSpecification_PR_structure) { + int count = getVarAccessAttr->typeSpecification.choice.structure.components.list.count; + + int i; + for (i = 0; i < count; i++) { + GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]->componentName->buf); + GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]->componentName); + TypeSpecification_t* typeSpec = + getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]->componentType; + freeTypeSpecRecursive(typeSpec); + GLOBAL_FREEMEM(typeSpec); + GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]); + } + + GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.structure.components.list.array); + + getVarAccessAttr->typeSpecification.choice.structure.components.list.array = NULL; + getVarAccessAttr->typeSpecification.choice.structure.components.list.count = 0; + getVarAccessAttr->typeSpecification.choice.structure.components.list.size = 0; + } + else if (getVarAccessAttr->typeSpecification.present == TypeSpecification_PR_array) { + GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.array.numberOfElements.buf); + getVarAccessAttr->typeSpecification.choice.array.numberOfElements.buf = NULL; + getVarAccessAttr->typeSpecification.choice.array.numberOfElements.size = 0; + freeTypeSpecRecursive(getVarAccessAttr->typeSpecification.choice.array.elementType); + + GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.array.elementType); + + getVarAccessAttr->typeSpecification.choice.array.elementType = NULL; + } } static void createVariableAccessAttributesResponse( - MmsServerConnection connection, - char* domainId, - char* nameId, - int invokeId, - ByteBuffer* response) + MmsServerConnection connection, + char* domainId, + char* nameId, + int invokeId, + ByteBuffer* response) { - MmsDevice* device = MmsServer_getDevice(connection->server); + MmsDevice* device = MmsServer_getDevice(connection->server); - MmsVariableSpecification* namedVariable = NULL; + MmsVariableSpecification* namedVariable = NULL; - if (domainId != NULL) { - MmsDomain* domain = MmsDevice_getDomain(device, domainId); + MmsDomain* domain = NULL; - if (domain == NULL) { - if (DEBUG_MMS_SERVER) printf("MMS_SERVER: domain %s not known\n", domainId); + if (domainId != NULL) { + domain = MmsDevice_getDomain(device, domainId); - mmsMsg_createServiceErrorPdu(invokeId, response, - MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); - goto exit_function; - } + if (domain == NULL) { + if (DEBUG_MMS_SERVER) printf("MMS_SERVER: domain %s not known\n", domainId); - namedVariable = MmsDomain_getNamedVariable(domain, nameId); - } + mmsMsg_createServiceErrorPdu(invokeId, response, + MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + goto exit_function; + } + + namedVariable = MmsDomain_getNamedVariable(domain, nameId); + } #if (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) - else - namedVariable = MmsDevice_getNamedVariable(device, nameId); + else + namedVariable = MmsDevice_getNamedVariable(device, nameId); #endif /* (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) */ + if (namedVariable == NULL) { + if (DEBUG_MMS_SERVER) printf("MMS_SERVER: named variable %s.%s not known\n", domainId, nameId); + + mmsMsg_createServiceErrorPdu(invokeId, response, + MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + + goto exit_function; + } + + bool accessAllowed = mmsServer_checkListAccess(connection->server, MMS_GETNAMELIST_DATA, domain, nameId, connection); - if (namedVariable == NULL) { - if (DEBUG_MMS_SERVER) printf("MMS_SERVER: named variable %s not known\n", nameId); + if (!accessAllowed) { + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: named variable %s/%s not visible due to access restrictions\n", domainId, nameId); - mmsMsg_createServiceErrorPdu(invokeId, response, - MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); + mmsMsg_createServiceErrorPdu(invokeId, response, + MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); - goto exit_function; - } + goto exit_function; + } - MmsPdu_t* mmsPdu = mmsServer_createConfirmedResponse(invokeId); + MmsPdu_t* mmsPdu = mmsServer_createConfirmedResponse(invokeId); - mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present = - ConfirmedServiceResponse_PR_getVariableAccessAttributes; + mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present = + ConfirmedServiceResponse_PR_getVariableAccessAttributes; - GetVariableAccessAttributesResponse_t* getVarAccessAttr; + GetVariableAccessAttributesResponse_t* getVarAccessAttr; - getVarAccessAttr = &(mmsPdu->choice.confirmedResponsePdu. - confirmedServiceResponse.choice.getVariableAccessAttributes); + getVarAccessAttr = &(mmsPdu->choice.confirmedResponsePdu. + confirmedServiceResponse.choice.getVariableAccessAttributes); - getVarAccessAttr->mmsDeletable = 0; + getVarAccessAttr->mmsDeletable = 0; - createTypeSpecification(namedVariable, &getVarAccessAttr->typeSpecification); + createTypeSpecification(namedVariable, &getVarAccessAttr->typeSpecification); - asn_enc_rval_t rval = - der_encode(&asn_DEF_MmsPdu, mmsPdu, mmsServer_write_out, (void*) response); + asn_enc_rval_t rval = + der_encode(&asn_DEF_MmsPdu, mmsPdu, mmsServer_write_out, (void*) response); - if (rval.encoded == -1) { - response->size = 0; + if (rval.encoded == -1) { + response->size = 0; if (DEBUG_MMS_SERVER) printf("MMS getVariableAccessAttributes: message to large! send error PDU!\n"); @@ -270,81 +284,80 @@ createVariableAccessAttributesResponse( MMS_ERROR_SERVICE_OTHER); goto exit_function; - } + } - deleteVariableAccessAttributesResponse(getVarAccessAttr); + deleteVariableAccessAttributesResponse(getVarAccessAttr); - asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); exit_function: - return; + return; } int mmsServer_handleGetVariableAccessAttributesRequest( - MmsServerConnection connection, - uint8_t* buffer, int bufPos, int maxBufPos, - uint32_t invokeId, - ByteBuffer* response) + MmsServerConnection connection, + uint8_t* buffer, int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response) { - int retVal = 0; + int retVal = 0; - GetVariableAccessAttributesRequest_t* request = 0; + GetVariableAccessAttributesRequest_t* request = 0; - asn_dec_rval_t rval; /* Decoder return value */ + asn_dec_rval_t rval; /* Decoder return value */ - rval = ber_decode(NULL, &asn_DEF_GetVariableAccessAttributesRequest, - (void**) &request, buffer + bufPos, maxBufPos - bufPos); + rval = ber_decode(NULL, &asn_DEF_GetVariableAccessAttributesRequest, + (void**) &request, buffer + bufPos, maxBufPos - bufPos); - if (rval.code == RC_OK) { - if (request->present == GetVariableAccessAttributesRequest_PR_name) { - if (request->choice.name.present == ObjectName_PR_domainspecific) { - Identifier_t domainId = request->choice.name.choice.domainspecific.domainId; - Identifier_t nameId = request->choice.name.choice.domainspecific.itemId; + if (rval.code == RC_OK) { + if (request->present == GetVariableAccessAttributesRequest_PR_name) { + if (request->choice.name.present == ObjectName_PR_domainspecific) { + Identifier_t domainId = request->choice.name.choice.domainspecific.domainId; + Identifier_t nameId = request->choice.name.choice.domainspecific.itemId; - char* domainIdStr = StringUtils_createStringFromBuffer(domainId.buf, domainId.size); - char* nameIdStr = StringUtils_createStringFromBuffer(nameId.buf, nameId.size); + char* domainIdStr = StringUtils_createStringFromBuffer(domainId.buf, domainId.size); + char* nameIdStr = StringUtils_createStringFromBuffer(nameId.buf, nameId.size); - if (DEBUG_MMS_SERVER) - printf("MMS_SERVER: getVariableAccessAttributes domainId: %s nameId: %s\n", domainIdStr, nameIdStr); + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: getVariableAccessAttributes domainId: %s nameId: %s\n", domainIdStr, nameIdStr); - createVariableAccessAttributesResponse(connection, domainIdStr, nameIdStr, invokeId, response); + createVariableAccessAttributesResponse(connection, domainIdStr, nameIdStr, invokeId, response); - GLOBAL_FREEMEM(domainIdStr); - GLOBAL_FREEMEM(nameIdStr); - } + GLOBAL_FREEMEM(domainIdStr); + GLOBAL_FREEMEM(nameIdStr); + } #if (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) - else if (request->choice.name.present == ObjectName_PR_vmdspecific) { - Identifier_t nameId = request->choice.name.choice.vmdspecific; + else if (request->choice.name.present == ObjectName_PR_vmdspecific) { + Identifier_t nameId = request->choice.name.choice.vmdspecific; - char* nameIdStr = StringUtils_createStringFromBuffer(nameId.buf, nameId.size); + char* nameIdStr = StringUtils_createStringFromBuffer(nameId.buf, nameId.size); - if (DEBUG_MMS_SERVER) printf("MMS_SERVER: getVariableAccessAttributes (VMD specific) nameId: %s\n", nameIdStr); + if (DEBUG_MMS_SERVER) printf("MMS_SERVER: getVariableAccessAttributes (VMD specific) nameId: %s\n", nameIdStr); - createVariableAccessAttributesResponse(connection, NULL, nameIdStr, invokeId, response); + createVariableAccessAttributesResponse(connection, NULL, nameIdStr, invokeId, response); - GLOBAL_FREEMEM(nameIdStr); - } + GLOBAL_FREEMEM(nameIdStr); + } #endif /* (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) */ - else { - if (DEBUG_MMS_SERVER) printf("GetVariableAccessAttributesRequest with name other than domainspecific is not supported!\n"); - retVal = -1; - } - } - else { - if (DEBUG_MMS_SERVER) printf("GetVariableAccessAttributesRequest with address not supported!\n"); - retVal = -1; - } - } - else { - if (DEBUG_MMS_SERVER) printf("GetVariableAccessAttributesRequest parsing request failed!\n"); - retVal = -1; - } - - asn_DEF_GetVariableAccessAttributesRequest.free_struct(&asn_DEF_GetVariableAccessAttributesRequest, request, 0); - - return retVal; + else { + if (DEBUG_MMS_SERVER) printf("GetVariableAccessAttributesRequest with name other than domainspecific is not supported!\n"); + retVal = -1; + } + } + else { + if (DEBUG_MMS_SERVER) printf("GetVariableAccessAttributesRequest with address not supported!\n"); + retVal = -1; + } + } + else { + if (DEBUG_MMS_SERVER) printf("GetVariableAccessAttributesRequest parsing request failed!\n"); + retVal = -1; + } + + asn_DEF_GetVariableAccessAttributesRequest.free_struct(&asn_DEF_GetVariableAccessAttributesRequest, request, 0); + + return retVal; } #endif /* (MMS_GET_VARIABLE_ACCESS_ATTRIBUTES == 1) */ - diff --git a/src/mms/iso_mms/server/mms_server.c b/src/mms/iso_mms/server/mms_server.c index b9d4c798..18b95464 100644 --- a/src/mms/iso_mms/server/mms_server.c +++ b/src/mms/iso_mms/server/mms_server.c @@ -351,6 +351,13 @@ MmsServer_installWriteHandler(MmsServer self, MmsWriteVariableHandler writeHandl self->writeHandlerParameter = parameter; } +void +MmsServer_installListAccessHandler(MmsServer self, MmsListAccessHandler listAccessHandler, void* parameter) +{ + self->listAccessHandler = listAccessHandler; + self->listAccessHandlerParameter = parameter; +} + void MmsServer_installConnectionHandler(MmsServer self, MmsConnectionHandler connectionHandler, void* parameter) { @@ -579,6 +586,34 @@ exit_function: return value; } +MmsDataAccessError +mmsServer_checkReadAccess(MmsServer self, MmsDomain* domain, char* itemId, MmsServerConnection connection, bool isDirectAccess) +{ + MmsDataAccessError accessError = DATA_ACCESS_ERROR_SUCCESS; + + printf("mmsServer_checkReadAccess(%s/%s)\n", domain->domainName, itemId); + + if (self->readAccessHandler) { + accessError = + self->readAccessHandler(self->readAccessHandlerParameter, (domain == (MmsDomain*) self->device) ? NULL : domain, + itemId, connection, isDirectAccess); + } + + return accessError; +} + +bool +mmsServer_checkListAccess(MmsServer self, MmsGetNameListType listType, MmsDomain* domain, char* itemId, MmsServerConnection connection) +{ + bool allowAccess = true; + + if (self->listAccessHandler) { + allowAccess = self->listAccessHandler(self->listAccessHandlerParameter, listType, domain, itemId, connection); + } + + return allowAccess; +} + MmsDevice* MmsServer_getDevice(MmsServer self) { diff --git a/src/sampled_values/sv_subscriber.c b/src/sampled_values/sv_subscriber.c index 9ece29e5..0d86a69c 100644 --- a/src/sampled_values/sv_subscriber.c +++ b/src/sampled_values/sv_subscriber.c @@ -64,6 +64,7 @@ struct sSVReceiver { #if (CONFIG_MMS_THREADLESS_STACK == 0) Semaphore subscriberListLock; + Thread thread; #endif }; @@ -106,6 +107,7 @@ SVReceiver_create(void) #if (CONFIG_MMS_THREADLESS_STACK == 0) self->subscriberListLock = Semaphore_create(1); + self->thread = NULL; #endif } @@ -256,15 +258,19 @@ SVReceiver_start(SVReceiver self) printf("SV_SUBSCRIBER: R-SV receiver started\n"); } - Thread thread = Thread_create((ThreadExecutionFunction) svReceiverLoop, (void*) self, true); +#if (CONFIG_MMS_THREADLESS_STACK == 0) + + self->thread = Thread_create((ThreadExecutionFunction) svReceiverLoop, (void*) self, false); - if (thread) { - Thread_start(thread); + if (self->thread) { + Thread_start(self->thread); } else { if (DEBUG_SV_SUBSCRIBER) printf("SV_SUBSCRIBER: Failed to start thread\n"); } + +#endif /* (CONFIG_MMS_THREADLESS_STACK == 0) */ } else { if (DEBUG_SV_SUBSCRIBER) @@ -283,16 +289,24 @@ void SVReceiver_stop(SVReceiver self) { if (self->running) { - SVReceiver_stopThreadless(self); + self->running = false; - while (self->stopped == false) - Thread_sleep(1); +#if (CONFIG_MMS_THREADLESS_STACK == 0) + if (self->thread) { + Thread_destroy(self->thread); + self->thread = NULL; + } +#endif /* (CONFIG_MMS_THREADLESS_STACK == 0) */ + + SVReceiver_stopThreadless(self); } } void SVReceiver_destroy(SVReceiver self) { + SVReceiver_stop(self); + LinkedList_destroyDeep(self->subscriberList, (LinkedListValueDeleteFunction) SVSubscriber_destroy); @@ -300,7 +314,12 @@ SVReceiver_destroy(SVReceiver self) GLOBAL_FREEMEM(self->interfaceId); #if (CONFIG_MMS_THREADLESS_STACK == 0) - Semaphore_destroy(self->subscriberListLock); + if (self->thread) { + Thread_destroy(self->thread); + self->thread = NULL; + } + + Semaphore_destroy(self->subscriberListLock); #endif GLOBAL_FREEMEM(self->buffer);