diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index 04d95a9c..4d111d4e 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -1615,6 +1615,10 @@ typedef MmsDataAccessError * or denied. If a WriteAccessHandler is set for a specific data attribute - the * default write access policy will not be performed for that data attribute. * + * NOTE: If the data attribute has sub data attributes, the WriteAccessHandler is not + * set for the sub data attributes and will not be called when the sub data attribute is + * written directly! + * * \param self the instance of IedServer to operate on. * \param dataAttribute the data attribute to monitor * \param handler the callback function that is invoked if a client tries to write to @@ -1625,6 +1629,29 @@ LIB61850_API void IedServer_handleWriteAccess(IedServer self, DataAttribute* dataAttribute, WriteAccessHandler handler, void* parameter); +/** + * \brief Install a WriteAccessHandler for a data attribute and for all sub data attributes + * + * This instructs the server to monitor write attempts by MMS clients to specific + * data attributes. If a client tries to write to the monitored data attribute the + * handler is invoked. The handler can decide if the write access will be allowed + * or denied. If a WriteAccessHandler is set for a specific data attribute - the + * default write access policy will not be performed for that data attribute. + * + * When the data attribute is a complex attribute then the handler will also be installed + * for all sub data attributes. When the data attribute is a basic data attribute then + * this function behaves like \ref IedServer_handleWriteAccess. + * + * \param self the instance of IedServer to operate on. + * \param dataAttribute the data attribute to monitor + * \param handler the callback function that is invoked if a client tries to write to + * the monitored data attribute. + * \param parameter a user provided parameter that is passed to the WriteAccessHandler when called. + */ +LIB61850_API void +IedServer_handleWriteAccessForComplexAttribute(IedServer self, DataAttribute* dataAttribute, + WriteAccessHandler handler, void* parameter); + typedef enum { ACCESS_POLICY_ALLOW, ACCESS_POLICY_DENY diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index d8d0100c..d2199c2c 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -1512,6 +1512,26 @@ IedServer_handleWriteAccess(IedServer self, DataAttribute* dataAttribute, WriteA } } +void +IedServer_handleWriteAccessForComplexAttribute(IedServer self, DataAttribute* dataAttribute, WriteAccessHandler handler, void* parameter) +{ + if (dataAttribute == NULL) { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: IedServer_handleWriteAccessForComplexAttribute - dataAttribute == NULL!\n"); + } + else { + MmsMapping_installWriteAccessHandler(self->mmsMapping, dataAttribute, handler, parameter); + + DataAttribute* subDa = (DataAttribute*) dataAttribute->firstChild; + + while (subDa) { + IedServer_handleWriteAccessForComplexAttribute(self, subDa, handler, parameter); + + subDa = (DataAttribute*) subDa->sibling; + } + } +} + void IedServer_setReadAccessHandler(IedServer self, ReadAccessHandler handler, void* parameter) { diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index 8fa84487..01898f18 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -1,7 +1,7 @@ /* * mms_mapping.c * - * Copyright 2013-2019 Michael Zillgith + * Copyright 2013-2021 Michael Zillgith * * This file is part of libIEC61850. * @@ -2374,6 +2374,7 @@ writeAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variable #endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */ +#if 0 static MmsValue* checkIfValueBelongsToModelNode(DataAttribute* dataAttribute, MmsValue* value, MmsValue* newValue) { @@ -2408,6 +2409,7 @@ checkIfValueBelongsToModelNode(DataAttribute* dataAttribute, MmsValue* value, Mm return NULL; } +#endif static FunctionalConstraint getFunctionalConstraintForWritableNode(char* separator) @@ -2813,51 +2815,25 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, AttributeAccessHandler* accessHandler = (AttributeAccessHandler*) writeHandlerListElement->data; DataAttribute* dataAttribute = accessHandler->attribute; - if (nodeAccessPolicy == ACCESS_POLICY_ALLOW) { - - MmsValue* matchingValue = checkIfValueBelongsToModelNode(dataAttribute, cachedValue, value); + if (dataAttribute->mmsValue == cachedValue) { - if (matchingValue != NULL) { + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, + connection); - ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, - connection); + MmsDataAccessError handlerResult = + accessHandler->handler(dataAttribute, value, clientConnection, + accessHandler->parameter); - MmsDataAccessError handlerResult = - accessHandler->handler(dataAttribute, matchingValue, clientConnection, - accessHandler->parameter); + if ((handlerResult == DATA_ACCESS_ERROR_SUCCESS) || (handlerResult == DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE)) { + handlerFound = true; - if ((handlerResult == DATA_ACCESS_ERROR_SUCCESS) || (handlerResult == DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE)) { - handlerFound = true; - - if (handlerResult == DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE) - updateValue = false; - } + if (handlerResult == DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE) + updateValue = false; - else - return handlerResult; - } - } - else { /* if ACCESS_POLICY_DENY only allow direct access to handled data attribute */ - if (dataAttribute->mmsValue == cachedValue) { - - ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, - connection); - - MmsDataAccessError handlerResult = - accessHandler->handler(dataAttribute, value, clientConnection, - accessHandler->parameter); - - if ((handlerResult == DATA_ACCESS_ERROR_SUCCESS) || (handlerResult == DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE)) { - handlerFound = true; - - if (handlerResult == DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE) - updateValue = false; - - break; - } - else - return handlerResult; + break; } + else + return handlerResult; } writeHandlerListElement = LinkedList_getNext(writeHandlerListElement);