Merge branch 'v1.6_develop' into v1.6_develop_rgoose_sntp

v1.6_develop_rgoose_sntp
Michael Zillgith 2 years ago
commit 7faf053e67

@ -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) {
/* allow only read access to LCBs */
if (acsiClass == ACSI_CLASS_LCB) {
if (accessType == IEC61850_CB_ACCESS_TYPE_READ)
return true;
}
else {
/* change to false to disallow write access to control block */
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) {
/* allow only read access to BRCBs */
if (acsiClass == ACSI_CLASS_BRCB) {
if (accessType == IEC61850_CB_ACCESS_TYPE_READ)
return true;
}
else {
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 (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);

@ -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
};

@ -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)
{
switch (acsiClass)
{
printf("%s access to LCB %s from %s\n", operation == LCB_EVENT_GET_PARAMETER ? "read" : "write", LogControlBlock_getName(lcb), ClientConnection_getPeerAddress(connection));
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";
}
}
/* only allow read access */
if (operation == LCB_EVENT_GET_PARAMETER) {
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 {
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);

@ -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

@ -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

@ -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);

@ -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)

@ -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;
}

@ -768,7 +768,6 @@ MmsMapping_ObjectReferenceToVariableAccessSpec(char* objectReference)
return accessSpec;
}
static int
getNumberOfDigits(int value)
{

@ -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 /*<char*>*/
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
*

@ -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)
*/

@ -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)
* \brief Set a handler to control access to a dataset (create, delete, read, write, list directory)
*
* \param self the instance of IedServer to operate on.
* \param handler the event handler to be used
* \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
* \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 allow read log data, false to deny
* \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)
* \brief Callback that is called when a client is invoking a read or write service to a control block or log
*
* \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
* 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
* \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 allow operation, false to deny operation
* \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);
/**@}*/

@ -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_ */

@ -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,

@ -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;
}

@ -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) {
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,16 +761,23 @@ 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) {
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_READ) == false) {
allowAccess = false;
value = &objectAccessDenied;
}
}
}
}
if (allowAccess) {
updateLogStatusInLCB(logControl);

@ -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,8 +3706,19 @@ 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);

@ -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,6 +107,7 @@ MmsSampledValueControlBlock_enable(MmsSampledValueControlBlock self)
if (DEBUG_IED_SERVER)
printf("IED_SERVER: enable SVCB %s\n", self->svcb->name);
if (self->eventHandler)
self->eventHandler(self->svcb, IEC61850_SVCB_EVENT_ENABLE, self->eventHandlerParameter);
}
@ -117,6 +120,7 @@ MmsSampledValueControlBlock_disable(MmsSampledValueControlBlock self)
if (DEBUG_IED_SERVER)
printf("IED_SERVER: disable SVCB %s\n", self->svcb->name);
if (self->eventHandler)
self->eventHandler(self->svcb, IEC61850_SVCB_EVENT_DISABLE, self->eventHandlerParameter);
}
@ -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 {

@ -724,10 +724,24 @@ updateReportDataset(MmsMapping* mapping, ReportControl* rc, MmsValue* newDatSet,
success = true;
dataSetValue = NULL;
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
dataSetValue = newDatSet;
@ -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;

@ -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);

@ -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
*/

@ -436,8 +436,18 @@ convertServiceErrorToMmsError(MmsServiceError serviceError)
break;
case 4: /* class: service */
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 */
mmsError = MMS_ERROR_SERVICE_PREEMPT_OTHER;

@ -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;
@ -159,13 +159,22 @@ addSubNamedVaribleNamesToList(LinkedList nameList, char* prefix, MmsVariableSpec
if (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,8 +218,12 @@ getJournalListDomainSpecific(MmsServerConnection connection, char* domainName)
MmsJournal journal = (MmsJournal) LinkedList_getData(journalList);
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,6 +268,10 @@ 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));
#else
@ -264,15 +281,17 @@ getNameListDomainSpecific(MmsServerConnection connection, char* domainName)
#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]]);
element = addSubNamedVaribleNamesToList(connection, element, domain, prefix, variables[index[i]]);
#else
char* prefix = variables[i]->name;
element = addSubNamedVaribleNamesToList(element, prefix, variables[i]);
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)
GLOBAL_FREEMEM(index);
#endif
@ -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;
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;
}

@ -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.
*
@ -191,7 +191,8 @@ deleteVariableAccessAttributesResponse(
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) {
}
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;
@ -215,8 +216,10 @@ createVariableAccessAttributesResponse(
MmsVariableSpecification* namedVariable = NULL;
MmsDomain* domain = NULL;
if (domainId != NULL) {
MmsDomain* domain = MmsDevice_getDomain(device, domainId);
domain = MmsDevice_getDomain(device, domainId);
if (domain == NULL) {
if (DEBUG_MMS_SERVER) printf("MMS_SERVER: domain %s not known\n", domainId);
@ -233,9 +236,20 @@ createVariableAccessAttributesResponse(
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 not known\n", nameId);
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 (!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);
@ -347,4 +361,3 @@ mmsServer_handleGetVariableAccessAttributesRequest(
}
#endif /* (MMS_GET_VARIABLE_ACCESS_ATTRIBUTES == 1) */

@ -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)
{

@ -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;
#if (CONFIG_MMS_THREADLESS_STACK == 0)
if (self->thread) {
Thread_destroy(self->thread);
self->thread = NULL;
}
#endif /* (CONFIG_MMS_THREADLESS_STACK == 0) */
while (self->stopped == false)
Thread_sleep(1);
SVReceiver_stopThreadless(self);
}
}
void
SVReceiver_destroy(SVReceiver self)
{
SVReceiver_stop(self);
LinkedList_destroyDeep(self->subscriberList,
(LinkedListValueDeleteFunction) SVSubscriber_destroy);
@ -300,6 +314,11 @@ SVReceiver_destroy(SVReceiver self)
GLOBAL_FREEMEM(self->interfaceId);
#if (CONFIG_MMS_THREADLESS_STACK == 0)
if (self->thread) {
Thread_destroy(self->thread);
self->thread = NULL;
}
Semaphore_destroy(self->subscriberListLock);
#endif

Loading…
Cancel
Save