diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index 3db3235e..94324a00 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -2007,6 +2007,26 @@ typedef bool LIB61850_API void IedServer_setDirectoryAccessHandler(IedServer self, IedServer_DirectoryAccessHandler handler, void* parameter); +/** + * \brief Callback that is called when a client is invoking a list objects service + * + * \param parameter user provided parameter + * \param connection client connection that is involved + * + * \return true to include the object in the service response, otherwise false + */ +typedef bool +(*IedServer_ListObjectsAccessHandler) (void* parameter, ClientConnection connection, LogicalDevice* ld, LogicalNode* ln, DataObject* dataObject, FunctionalConstraint fc); + +/** + * \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_setListObjectsAccessHandler(IedServer self, IedServer_ListObjectsAccessHandler 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..6e3edb52 100644 --- a/src/iec61850/inc_private/mms_mapping_internal.h +++ b/src/iec61850/inc_private/mms_mapping_internal.h @@ -352,6 +352,9 @@ struct sMmsMapping { IedServer_DirectoryAccessHandler directoryAccessHandler; void* directoryAccessHandlerParameter; + + IedServer_ListObjectsAccessHandler listObjectsAccessHandler; + void* listObjectsAccessHandlerParameter; }; #endif /* MMS_MAPPING_INTERNAL_H_ */ diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index 27d40624..aa8e84cd 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -1967,3 +1967,10 @@ 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; +} diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index 2d76f39c..91e12f62 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -3314,6 +3314,122 @@ mmsConnectionHandler(void* parameter, MmsServerConnection connection, MmsServerE } } +static bool +mmsListObjectsAccessHandler(void* parameter, 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 (self->listObjectsAccessHandler) + { + char* separator = strchr(variableId, '$'); + +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) + + if (separator) { + if (isFunctionalConstraint("SE", separator)) { + goto exit_function; + } + } + +#endif /* (CONFIG_IEC61850_SETTING_GROUPS == 1) */ + + 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) + { + goto exit_function; + } + else + { + char str[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); + } + + if (fc == IEC61850_FC_SP) { + if (!strcmp(str, "SGCB")) + 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); + + allowAccess = self->listObjectsAccessHandler(self->listObjectsAccessHandlerParameter, clientConnection, ld, ln, (DataObject*) dobj, fc); + } + } + } + else { + /* no data object but with FC specified */ + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, + connection); + + allowAccess = self->listObjectsAccessHandler(self->listObjectsAccessHandlerParameter, clientConnection, ld, ln, NULL, fc); + } + } + } + } + else { + LogicalNode* ln = LogicalDevice_getLogicalNode(ld, variableId); + + if (ln) { + /* only LN, no FC specified */ + + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + + allowAccess = self->listObjectsAccessHandler(self->listObjectsAccessHandlerParameter, clientConnection, ld, ln, 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 +3466,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 +3481,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); @@ -3417,6 +3533,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; @@ -3666,6 +3792,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/mms/inc_private/mms_server_internal.h b/src/mms/inc_private/mms_server_internal.h index ec70d359..606e0827 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, 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..da5de7a5 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, 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/server/mms_get_namelist_service.c b/src/mms/iso_mms/server/mms_get_namelist_service.c index 2170f8c1..0a9c6f57 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,20 @@ 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, 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) */ + + } } } @@ -233,7 +239,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 +261,28 @@ getNameListDomainSpecific(MmsServerConnection connection, char* domainName) for (i = 0; i < domain->namedVariablesCount; i++) { + bool accessAllowed = mmsServer_checkListAccess(connection->server, 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) diff --git a/src/mms/iso_mms/server/mms_server.c b/src/mms/iso_mms/server/mms_server.c index b9d4c798..3229b21e 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, MmsDomain* domain, char* itemId, MmsServerConnection connection) +{ + bool allowAccess = true; + + if (self->listAccessHandler) { + allowAccess = self->listAccessHandler(self->listAccessHandlerParameter, domain, itemId, connection); + } + + return allowAccess; +} + MmsDevice* MmsServer_getDevice(MmsServer self) {