From 76dbcb4496d46ceb5b981788c4520dedb7438b25 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Sat, 4 Mar 2023 08:43:14 +0000 Subject: [PATCH] - IED server: Implemented read/write access control to RCBs (LIB61850-391) --- .../server_example_access_control.c | 13 +++++++ src/iec61850/inc/iec61850_server.h | 24 +++++++++++++ .../inc_private/mms_mapping_internal.h | 3 ++ src/iec61850/inc_private/reporting.h | 2 +- src/iec61850/server/impl/ied_server.c | 7 ++++ src/iec61850/server/mms_mapping/reporting.c | 35 ++++++++++++++++--- 6 files changed, 78 insertions(+), 6 deletions(-) diff --git a/examples/server_example_access_control/server_example_access_control.c b/examples/server_example_access_control/server_example_access_control.c index 024bf77a..dcb93d0f 100644 --- a/examples/server_example_access_control/server_example_access_control.c +++ b/examples/server_example_access_control/server_example_access_control.c @@ -75,6 +75,17 @@ connectionHandler (IedServer self, ClientConnection connection, bool connected, printf("Connection closed\n"); } +/* + * This handler is called before the rcbEventHandler and can be use to allow or permit read or write access to the RCB + */ +bool +rcbAccessHandler(void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType operation) +{ + printf("RCB: %s access: %s\n", ReportControlBlock_getName(rcb), operation == RCB_EVENT_GET_PARAMETER ? "READ" : "WRITE"); + + return false; +} + static void rcbEventHandler(void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType event, const char* parameterName, MmsDataAccessError serviceError) { @@ -167,6 +178,8 @@ main(int argc, char** argv) IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL); + IedServer_setRCBAccessHandler(iedServer, rcbAccessHandler, NULL); + IedServer_setRCBEventHandler(iedServer, rcbEventHandler, NULL); /* By default access to variables with FC=DC and FC=CF is not allowed. diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index 9d34084c..93bb02e2 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -1622,6 +1622,30 @@ typedef void (*IedServer_RCBEventHandler) (void* parameter, ReportControlBlock* LIB61850_API void IedServer_setRCBEventHandler(IedServer self, IedServer_RCBEventHandler handler, void* parameter); + +/** + * \brief Callback that is called in case of RCB access to give the user the opportunity to block or allow the operation + * + * \note This callback is called before the IedServer_RCBEventHandler and only in case of operations (RCB_EVENT_GET_PARAMETER, RCB_EVENT_SET_PARAMETER, RCB_EVENT_ENABLE + * + * \param parameter user provided parameter + * \param rcb affected report control block + * \param connection client connection that is involved + * \param operation one of the following operation event types: RCB_EVENT_GET_PARAMETER, RCB_EVENT_SET_PARAMETER + */ +typedef bool +(*IedServer_RCBAccessHandler) (void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType operation); + +/** + * \brief Set a handler to control read and write access to report control blocks (RCBs) + * + * \param self the instance of IedServer to operate on. + * \param handler the event handler to be used + * \param parameter a user provided parameter that is passed to the handler. + */ +LIB61850_API void +IedServer_setRCBAccessHandler(IedServer self, IedServer_RCBAccessHandler handler, void* parameter); + /**@}*/ /** diff --git a/src/iec61850/inc_private/mms_mapping_internal.h b/src/iec61850/inc_private/mms_mapping_internal.h index c22311f6..c42df272 100644 --- a/src/iec61850/inc_private/mms_mapping_internal.h +++ b/src/iec61850/inc_private/mms_mapping_internal.h @@ -335,6 +335,9 @@ struct sMmsMapping { IedServer_RCBEventHandler rcbEventHandler; void* rcbEventHandlerParameter; + IedServer_RCBAccessHandler rcbAccessHandler; + void* rcbAccessHandlerParameter; + IedServer_DataSetAccessHandler dataSetAccessHandler; void* dataSetAccessHandlerParameter; }; diff --git a/src/iec61850/inc_private/reporting.h b/src/iec61850/inc_private/reporting.h index a4e3433f..558343c2 100644 --- a/src/iec61850/inc_private/reporting.h +++ b/src/iec61850/inc_private/reporting.h @@ -140,7 +140,7 @@ LIB61850_INTERNAL MmsDataAccessError Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* elementName, MmsValue* value, MmsServerConnection connection); -LIB61850_INTERNAL void +LIB61850_INTERNAL bool ReportControl_readAccess(ReportControl* rc, MmsMapping* mmsMapping, MmsServerConnection connection, char* elementName); LIB61850_INTERNAL void diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index d748bf5a..c398e143 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -689,6 +689,13 @@ IedServer_setRCBEventHandler(IedServer self, IedServer_RCBEventHandler handler, self->mmsMapping->rcbEventHandlerParameter = parameter; } +void +IedServer_setRCBAccessHandler(IedServer self, IedServer_RCBAccessHandler handler, void* parameter) +{ + self->mmsMapping->rcbAccessHandler = handler; + self->mmsMapping->rcbAccessHandlerParameter = parameter; +} + void IedServer_destroy(IedServer self) { diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index 3b170a54..d0779138 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -1697,21 +1697,35 @@ checkReservationTimeout(MmsMapping* self, ReportControl* rc) } } -void +bool ReportControl_readAccess(ReportControl* rc, MmsMapping* mmsMapping, MmsServerConnection connection, char* elementName) { - (void)elementName; + bool accessAllowed = true; + MmsDataAccessError accessError = DATA_ACCESS_ERROR_SUCCESS; /* check reservation timeout */ if (rc->buffered) { checkReservationTimeout(mmsMapping, rc); } - if (mmsMapping->rcbEventHandler) { - ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(mmsMapping->iedServer, connection); + ClientConnection clientConnection = NULL; + + if (mmsMapping->rcbAccessHandler || mmsMapping->rcbEventHandler) { + clientConnection = private_IedServer_getClientConnectionByHandle(mmsMapping->iedServer, connection); + } + + if (mmsMapping->rcbAccessHandler) { + if (mmsMapping->rcbAccessHandler(mmsMapping->rcbAccessHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_GET_PARAMETER) == false) { + accessError = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + accessAllowed = false; + } + } - mmsMapping->rcbEventHandler(mmsMapping->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_GET_PARAMETER, elementName, DATA_ACCESS_ERROR_SUCCESS); + if (mmsMapping->rcbEventHandler) { + mmsMapping->rcbEventHandler(mmsMapping->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_GET_PARAMETER, elementName, accessError); } + + return accessAllowed; } static bool @@ -1809,6 +1823,15 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + /* check if write access to RCB is allowed on this connection */ + if (self->rcbAccessHandler) { + if (self->rcbAccessHandler(self->rcbAccessHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_SET_PARAMETER) == false) { + retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + + goto exit_function_only_tracking; + } + } + /* check reservation timeout for buffered RCBs */ if (rc->buffered) { @@ -2491,6 +2514,8 @@ exit_function: ReportControl_unlockNotify(rc); +exit_function_only_tracking: + #if (CONFIG_IEC61850_SERVICE_TRACKING == 1) if (rc->buffered) updateGenericTrackingObjectValues(self, rc, IEC61850_SERVICE_TYPE_SET_BRCB_VALUES, retVal);