diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index 4e5bee3a..04d95a9c 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -1591,13 +1591,17 @@ MmsGooseControlBlock_getFixedOffs(MmsGooseControlBlock self); * One application can be to allow write access only from a specific client. Another * application could be to check if the value is in the allowed range before the write * is accepted. + * When the callback returns DATA_ACCESS_ERROR_SUCCESS the write access is accepted and the stack will + * update the value automatically. + * When the callback returns DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE the write access is accepted but the + * stack will not update the value automatically. * * \param the data attribute that has been written by an MMS client. * \param the value the client want to write to the data attribute * \param connection the connection object of the client connection that invoked the write operation * \param parameter the user provided parameter * - * \return DATA_ACCESS_ERROR_SUCCESS if access is accepted, DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED if access is denied. + * \return DATA_ACCESS_ERROR_SUCCESS, or DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE if access is accepted, DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED if access is denied. */ typedef MmsDataAccessError (*WriteAccessHandler) (DataAttribute* dataAttribute, MmsValue* value, ClientConnection connection, void* parameter); diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index 7f74d3fc..c03700e7 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -2769,16 +2769,17 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, } #endif /* (CONFIG_IEC61850_SETTING_GROUPS == 1) */ - /* writable data model elements - SP, SV, CF, DC */ + /* writable data model elements - SP, SV, CF, DC, BL */ if (fc != IEC61850_FC_NONE) { MmsValue* cachedValue; cachedValue = MmsServer_getValueFromCache(self->mmsServer, domain, variableId); - if (cachedValue != NULL) { + if (cachedValue) { - if (!MmsValue_equalTypes(cachedValue, value)) + if (!MmsValue_equalTypes(cachedValue, value)) { return DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + } bool handlerFound = false; @@ -2800,6 +2801,8 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, } #endif + bool updateValue = true; + /* Call write access handlers */ LinkedList writeHandlerListElement = LinkedList_getNext(self->attributeAccessHandlers); @@ -2820,12 +2823,16 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, accessHandler->handler(dataAttribute, matchingValue, clientConnection, accessHandler->parameter); - if (handlerResult == DATA_ACCESS_ERROR_SUCCESS) + 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; + } + else return handlerResult; } - } else { /* if ACCESS_POLICY_DENY only allow direct access to handled data attribute */ if (dataAttribute->mmsValue == cachedValue) { @@ -2837,14 +2844,17 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, accessHandler->handler(dataAttribute, value, clientConnection, accessHandler->parameter); - if (handlerResult == DATA_ACCESS_ERROR_SUCCESS) { + 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; } - } writeHandlerListElement = LinkedList_getNext(writeHandlerListElement); @@ -2858,12 +2868,14 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, } - DataAttribute* da = IedModel_lookupDataAttributeByMmsValue(self->model, cachedValue); + if (updateValue) { + DataAttribute* da = IedModel_lookupDataAttributeByMmsValue(self->model, cachedValue); - if (da != NULL) - IedServer_updateAttributeValue(self->iedServer, da, value); - else - return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + if (da) + IedServer_updateAttributeValue(self->iedServer, da, value); + else + return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + } return DATA_ACCESS_ERROR_SUCCESS; } diff --git a/src/mms/inc/mms_value.h b/src/mms/inc/mms_value.h index a322538f..57e2f39e 100644 --- a/src/mms/inc/mms_value.h +++ b/src/mms/inc/mms_value.h @@ -44,6 +44,7 @@ extern "C" { typedef enum { + DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE = -3, DATA_ACCESS_ERROR_NO_RESPONSE = -2, /* for server internal purposes only! */ DATA_ACCESS_ERROR_SUCCESS = -1, DATA_ACCESS_ERROR_OBJECT_INVALIDATED = 0,