From 143bc977c03156cdc9042e932cfc41d534812d1f Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Thu, 26 Jul 2018 06:47:54 +0200 Subject: [PATCH] - IEC 61850 server/MMS server: make file service configurable at runtime with IedServerConfig object (new functions IedServerConfig_enableFileService and IedServerConfig_isFileServiceEnabled) --- config/stack_config.h | 3 + config/stack_config.h.cmake | 3 + src/iec61850/inc/iec61850_server.h | 17 ++ src/iec61850/server/impl/ied_server.c | 5 + src/iec61850/server/impl/ied_server_config.c | 14 ++ src/mms/inc/mms_server.h | 11 ++ src/mms/inc_private/mms_server_internal.h | 4 + .../iso_mms/server/mms_association_service.c | 180 ++++++++++++------ src/mms/iso_mms/server/mms_server.c | 13 ++ .../iso_mms/server/mms_server_connection.c | 70 +++++++ src/vs/libiec61850-wo-goose.def | 2 + src/vs/libiec61850.def | 2 + 12 files changed, 268 insertions(+), 56 deletions(-) diff --git a/config/stack_config.h b/config/stack_config.h index 5332b048..3e79f121 100644 --- a/config/stack_config.h +++ b/config/stack_config.h @@ -232,6 +232,9 @@ */ #define CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME 1 +/* enable to configure MmsServer at runtime */ +#define CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME 1 + /************************************************************************************ * Check configuration for consistency - DO NOT MODIFY THIS PART! ************************************************************************************/ diff --git a/config/stack_config.h.cmake b/config/stack_config.h.cmake index e6766b47..621c359f 100644 --- a/config/stack_config.h.cmake +++ b/config/stack_config.h.cmake @@ -215,6 +215,9 @@ */ #define CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME 1 +/* enable to configure MmsServer at runtime */ +#define CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME 1 + /************************************************************************************ * Check configuration for consistency - DO NOT MODIFY THIS PART! ************************************************************************************/ diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index 39589a64..9ad4507c 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -53,6 +53,9 @@ struct sIedServerConfig /** Base path (directory where the file service serves files */ char* fileServiceBasepath; + + /** when true (default) enable MMS file service */ + bool enableFileService; }; /** @@ -99,7 +102,21 @@ IedServerConfig_setFileServiceBasePath(IedServerConfig self, const char* basepat const char* IedServerConfig_getFileServiceBasePath(IedServerConfig self); +/** + * \brief Enable/disable the MMS file service support + * + * \param[in] enable set true to enable the file services, otherwise false + */ +void +IedServerConfig_enableFileService(IedServerConfig self, bool enable); +/** + * \brief Is the MMS file service enabled or disabled + * + * \return true if enabled, false otherwise + */ +bool +IedServerConfig_isFileServiceEnabled(IedServerConfig self); /** * An opaque handle for an IED server instance diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index 8fa94f6e..c88c7823 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -421,6 +421,11 @@ IedServer_createWithConfig(IedModel* dataModel, TLSConfiguration tlsConfiguratio self->mmsServer = MmsServer_create(self->mmsDevice, tlsConfiguration); +#if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) + if (serverConfiguration) + MmsServer_enableFileService(self->mmsServer, serverConfiguration->enableFileService); +#endif + if (serverConfiguration) MmsServer_setFilestoreBasepath(self->mmsServer, serverConfiguration->fileServiceBasepath); diff --git a/src/iec61850/server/impl/ied_server_config.c b/src/iec61850/server/impl/ied_server_config.c index 2fa5065a..23552f40 100644 --- a/src/iec61850/server/impl/ied_server_config.c +++ b/src/iec61850/server/impl/ied_server_config.c @@ -32,6 +32,7 @@ IedServerConfig_create() if (self) { self->reportBufferSize = CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE; self->fileServiceBasepath = StringUtils_copyString(CONFIG_VIRTUAL_FILESTORE_BASEPATH); + self->enableFileService = true; } return self; @@ -73,3 +74,16 @@ IedServerConfig_getFileServiceBasePath(IedServerConfig self) { return self->fileServiceBasepath; } + +void +IedServerConfig_enableFileService(IedServerConfig self, bool enable) +{ + self->enableFileService = enable; +} + +bool +IedServerConfig_isFileServiceEnabled(IedServerConfig self) +{ + return self->enableFileService; +} + diff --git a/src/mms/inc/mms_server.h b/src/mms/inc/mms_server.h index 553f3355..f47760b1 100644 --- a/src/mms/inc/mms_server.h +++ b/src/mms/inc/mms_server.h @@ -225,6 +225,17 @@ MmsServer_installFileAccessHandler(MmsServer self, MmsFileAccessHandler handler, void MmsServer_setFilestoreBasepath(MmsServer self, const char* basepath); +/** + * \brief Enable/disable MMS file services at runtime + * + * NOTE: requires CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME = 1 in stack configuration + * + * \param[in] self the MmsServer instance + * \param[in] enable true to enable file services, false to disable + */ +void +MmsServer_enableFileService(MmsServer self, bool enable); + /** * \brief lock the cached server data model * diff --git a/src/mms/inc_private/mms_server_internal.h b/src/mms/inc_private/mms_server_internal.h index fdc05de7..bb350fb4 100644 --- a/src/mms/inc_private/mms_server_internal.h +++ b/src/mms/inc_private/mms_server_internal.h @@ -164,6 +164,10 @@ struct sMmsServer { char* filestoreBasepath; #endif +#if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) + bool fileServiceEnabled; +#endif /* (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1) */ + }; struct sMmsServerConnection { diff --git a/src/mms/iso_mms/server/mms_association_service.c b/src/mms/iso_mms/server/mms_association_service.c index 7a5245c7..46b7d191 100644 --- a/src/mms/iso_mms/server/mms_association_service.c +++ b/src/mms/iso_mms/server/mms_association_service.c @@ -1,7 +1,7 @@ /* * mms_association_service.c * - * Copyright 2013, 2014 Michael Zillgith + * Copyright 2013-2018 Michael Zillgith * * This file is part of libIEC61850. * @@ -62,58 +62,6 @@ #define MMS_SERVICE_CONCLUDE 0x10 #define MMS_SERVICE_CANCEL 0x08 -//TODO make dependent on stack configuration! -/* servicesSupported MMS bitstring */ -static uint8_t servicesSupported[] = -{ - 0x00 -#if (MMS_STATUS_SERVICE == 1) - | MMS_SERVICE_STATUS -#endif - | MMS_SERVICE_GET_NAME_LIST -#if (MMS_IDENTIFY_SERVICE == 1) - | MMS_SERVICE_IDENTIFY -#endif - | MMS_SERVICE_READ - | MMS_SERVICE_WRITE - | MMS_SERVICE_GET_VARIABLE_ACCESS_ATTRIBUTES - , - 0x00 - | MMS_SERVICE_DEFINE_NAMED_VARIABLE_LIST - | MMS_SERVICE_DELETE_NAMED_VARIABLE_LIST - | MMS_SERVICE_GET_NAMED_VARIABLE_LIST_ATTRIBUTES - , - 0x00, - 0x00, - 0x00, - 0x00 -#if (MMS_OBTAIN_FILE_SERVICE == 1) - | MMS_SERVICE_OBTAIN_FILE -#endif - , - 0x00, - 0x00, - 0x00 -#if (MMS_JOURNAL_SERVICE == 1) - | MMS_SERVICE_READ_JOURNAL -#endif - , - 0x00 -#if (MMS_FILE_SERVICE == 1) - | MMS_SERVICE_FILE_OPEN - | MMS_SERVICE_FILE_READ - | MMS_SERVICE_FILE_CLOSE - | MMS_SERVICE_FILE_RENAME - | MMS_SERVICE_FILE_DELETE - | MMS_SERVICE_FILE_DIRECTORY -#endif - | MMS_SERVICE_INFORMATION_REPORT - , - 0x00 - | MMS_SERVICE_CONCLUDE - | MMS_SERVICE_CANCEL -}; - /* negotiated parameter CBB */ static uint8_t parameterCBB[] = { @@ -127,7 +75,7 @@ static uint8_t parameterCBB[] = *********************************************************************************************/ static int -encodeInitResponseDetail(uint8_t* buffer, int bufPos, bool encode) +encodeInitResponseDetail(MmsServerConnection self, uint8_t* buffer, int bufPos, bool encode) { int initResponseDetailSize = 14 + 5 + 3; @@ -140,6 +88,126 @@ encodeInitResponseDetail(uint8_t* buffer, int bufPos, bool encode) bufPos = BerEncoder_encodeBitString(0x81, 11, parameterCBB, buffer, bufPos); +#if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) + + uint8_t servicesSupported[] = + { + 0x00 + #if (MMS_STATUS_SERVICE == 1) + | MMS_SERVICE_STATUS + #endif + | MMS_SERVICE_GET_NAME_LIST + #if (MMS_IDENTIFY_SERVICE == 1) + | MMS_SERVICE_IDENTIFY + #endif + | MMS_SERVICE_READ + | MMS_SERVICE_WRITE + | MMS_SERVICE_GET_VARIABLE_ACCESS_ATTRIBUTES + , + 0x00 + #if ((MMS_DATA_SET_SERVICE == 1) && (MMS_DYNAMIC_DATA_SETS == 1)) + | MMS_SERVICE_DEFINE_NAMED_VARIABLE_LIST + | MMS_SERVICE_DELETE_NAMED_VARIABLE_LIST + #endif + #if ((MMS_DATA_SET_SERVICE == 1) && (MMS_GET_DATA_SET_ATTRIBUTES == 1)) + | MMS_SERVICE_GET_NAMED_VARIABLE_LIST_ATTRIBUTES + #endif + , + 0x00, + 0x00, + 0x00, + 0x00 + , + 0x00, + 0x00, + 0x00 + #if (MMS_JOURNAL_SERVICE == 1) + | MMS_SERVICE_READ_JOURNAL + #endif + , + 0x00 + | MMS_SERVICE_INFORMATION_REPORT + , + 0x00 + | MMS_SERVICE_CONCLUDE + | MMS_SERVICE_CANCEL + }; + + + if (self->server->fileServiceEnabled) { + +#if (MMS_OBTAIN_FILE_SERVICE == 1) + servicesSupported[5] |= MMS_SERVICE_OBTAIN_FILE; +#endif + +#if (MMS_FILE_SERVICE == 1) + servicesSupported[9] |= MMS_SERVICE_FILE_OPEN; + servicesSupported[9] |= MMS_SERVICE_FILE_READ; + servicesSupported[9] |= MMS_SERVICE_FILE_CLOSE; + servicesSupported[9] |= MMS_SERVICE_FILE_RENAME; + servicesSupported[9] |= MMS_SERVICE_FILE_DELETE; + servicesSupported[9] |= MMS_SERVICE_FILE_DIRECTORY; +#endif /* (MMS_FILE_SERVICE == 1) */ + + } + + +#else + uint8_t servicesSupported[] = + { + 0x00 + #if (MMS_STATUS_SERVICE == 1) + | MMS_SERVICE_STATUS + #endif + | MMS_SERVICE_GET_NAME_LIST + #if (MMS_IDENTIFY_SERVICE == 1) + | MMS_SERVICE_IDENTIFY + #endif + | MMS_SERVICE_READ + | MMS_SERVICE_WRITE + | MMS_SERVICE_GET_VARIABLE_ACCESS_ATTRIBUTES + , + 0x00 + #if ((MMS_DATA_SET_SERVICE == 1) && (MMS_DYNAMIC_DATA_SETS == 1)) + | MMS_SERVICE_DEFINE_NAMED_VARIABLE_LIST + | MMS_SERVICE_DELETE_NAMED_VARIABLE_LIST + #endif + #if ((MMS_DATA_SET_SERVICE == 1) && (MMS_GET_DATA_SET_ATTRIBUTES == 1)) + | MMS_SERVICE_GET_NAMED_VARIABLE_LIST_ATTRIBUTES + #endif + , + 0x00, + 0x00, + 0x00, + 0x00 + #if (MMS_OBTAIN_FILE_SERVICE == 1) + | MMS_SERVICE_OBTAIN_FILE + #endif + , + 0x00, + 0x00, + 0x00 + #if (MMS_JOURNAL_SERVICE == 1) + | MMS_SERVICE_READ_JOURNAL + #endif + , + 0x00 + #if (MMS_FILE_SERVICE == 1) + | MMS_SERVICE_FILE_OPEN + | MMS_SERVICE_FILE_READ + | MMS_SERVICE_FILE_CLOSE + | MMS_SERVICE_FILE_RENAME + | MMS_SERVICE_FILE_DELETE + | MMS_SERVICE_FILE_DIRECTORY + #endif + | MMS_SERVICE_INFORMATION_REPORT + , + 0x00 + | MMS_SERVICE_CONCLUDE + | MMS_SERVICE_CANCEL + }; +#endif /* (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) */ + bufPos = BerEncoder_encodeBitString(0x82, 85, servicesSupported, buffer, bufPos); return bufPos; @@ -159,7 +227,7 @@ createInitiateResponse(MmsServerConnection self, ByteBuffer* writeBuffer) initiateResponseLength += 2 + BerEncoder_UInt32determineEncodedSize(self->maxServOutstandingCalled); initiateResponseLength += 2 + BerEncoder_UInt32determineEncodedSize(self->dataStructureNestingLevel); - initiateResponseLength += encodeInitResponseDetail(NULL, 0, false); + initiateResponseLength += encodeInitResponseDetail(self, NULL, 0, false); /* Initiate response pdu */ bufPos = BerEncoder_encodeTL(0xa9, initiateResponseLength, buffer, bufPos); @@ -172,7 +240,7 @@ createInitiateResponse(MmsServerConnection self, ByteBuffer* writeBuffer) bufPos = BerEncoder_encodeUInt32WithTL(0x83, self->dataStructureNestingLevel, buffer, bufPos); - bufPos = encodeInitResponseDetail(buffer, bufPos, true); + bufPos = encodeInitResponseDetail(self, buffer, bufPos, true); writeBuffer->size = bufPos; diff --git a/src/mms/iso_mms/server/mms_server.c b/src/mms/iso_mms/server/mms_server.c index 5781812c..46d08ad5 100644 --- a/src/mms/iso_mms/server/mms_server.c +++ b/src/mms/iso_mms/server/mms_server.c @@ -67,6 +67,10 @@ MmsServer_create(MmsDevice* device, TLSConfiguration tlsConfiguration) IsoServer_setUserLock(self->isoServer, self->modelMutex); #endif +#if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) + self->fileServiceEnabled = true; +#endif /* (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) */ + return self; } @@ -99,6 +103,15 @@ MmsServer_setFilestoreBasepath(MmsServer self, const char* basepath) #endif /* (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1) */ } +#if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) + +void +MmsServer_enableFileService(MmsServer self, bool enable) +{ + self->fileServiceEnabled = enable; +} + +#endif /* (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) */ void MmsServer_lockModel(MmsServer self) diff --git a/src/mms/iso_mms/server/mms_server_connection.c b/src/mms/iso_mms/server/mms_server_connection.c index 6297ea55..4767ca7e 100644 --- a/src/mms/iso_mms/server/mms_server_connection.c +++ b/src/mms/iso_mms/server/mms_server_connection.c @@ -171,9 +171,22 @@ handleConfirmedRequestPdu( { #if (MMS_OBTAIN_FILE_SERVICE == 1) + + +#if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) + case 0x2e: /* obtain-file */ + if (self->server->fileServiceEnabled) + mmsServer_handleObtainFileRequest(self, buffer, bufPos, bufPos + length, invokeId, response); + else + mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE, response); + break; +#else case 0x2e: /* obtain-file */ mmsServer_handleObtainFileRequest(self, buffer, bufPos, bufPos + length, invokeId, response); break; +#endif /* (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) */ + + #endif /* MMS_OBTAIN_FILE_SERVICE == 1 */ #if (MMS_JOURNAL_SERVICE == 1) @@ -183,29 +196,86 @@ handleConfirmedRequestPdu( #endif /* (MMS_JOURNAL_SERVICE == 1) */ #if (MMS_FILE_SERVICE == 1) + +#if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) + case 0x48: /* file-open-request */ + if (self->server->fileServiceEnabled) + mmsServer_handleFileOpenRequest(self, buffer, bufPos, bufPos + length, invokeId, response); + else + mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE, response); + break; + +#else case 0x48: /* file-open-request */ mmsServer_handleFileOpenRequest(self, buffer, bufPos, bufPos + length, invokeId, response); break; +#endif /* (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) */ +#if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) + case 0x49: /* file-read-request */ + if (self->server->fileServiceEnabled) + mmsServer_handleFileReadRequest(self, buffer, bufPos, bufPos + length, invokeId, response); + else + mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE, response); + break; +#else case 0x49: /* file-read-request */ mmsServer_handleFileReadRequest(self, buffer, bufPos, bufPos + length, invokeId, response); break; +#endif /* (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) */ +#if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) + case 0x4a: /* file-close-request */ + if (self->server->fileServiceEnabled) + mmsServer_handleFileCloseRequest(self, buffer, bufPos, bufPos + length, invokeId, response); + else + mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE, response); + break; +#else case 0x4a: /* file-close-request */ mmsServer_handleFileCloseRequest(self, buffer, bufPos, bufPos + length, invokeId, response); break; +#endif /* (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) */ +#if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) + case 0x4b: /* file-rename-request */ + if (self->server->fileServiceEnabled) + mmsServer_handleFileRenameRequest(self, buffer, bufPos, bufPos + length, invokeId, response); + else + mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE, response); + break; +#else case 0x4b: /* file-rename-request */ mmsServer_handleFileRenameRequest(self, buffer, bufPos, bufPos + length, invokeId, response); break; +#endif /* (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) */ +#if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) + case 0x4c: /* file-delete-request */ + if (self->server->fileServiceEnabled) + mmsServer_handleFileDeleteRequest(self, buffer, bufPos, bufPos + length, invokeId, response); + else + mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE, response); + break; +#else case 0x4c: /* file-delete-request */ mmsServer_handleFileDeleteRequest(self, buffer, bufPos, bufPos + length, invokeId, response); break; +#endif /* (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) */ +#if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) + case 0x4d: /* file-directory-request */ + if (self->server->fileServiceEnabled) + mmsServer_handleFileDirectoryRequest(self, buffer, bufPos, bufPos + length, invokeId, response); + else + mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE, response); + break; +#else case 0x4d: /* file-directory-request */ mmsServer_handleFileDirectoryRequest(self, buffer, bufPos, bufPos + length, invokeId, response); break; +#endif /* (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) */ + #endif /* MMS_FILE_SERVICE == 1 */ default: diff --git a/src/vs/libiec61850-wo-goose.def b/src/vs/libiec61850-wo-goose.def index af416b2c..092b3051 100644 --- a/src/vs/libiec61850-wo-goose.def +++ b/src/vs/libiec61850-wo-goose.def @@ -604,3 +604,5 @@ EXPORTS ClientGooseControlBlock_getMaxTime ClientGooseControlBlock_getFixedOffs ControlObjectClient_getCtlValType + IedServerConfig_enableFileService + IedServerConfig_isFileServiceEnabled diff --git a/src/vs/libiec61850.def b/src/vs/libiec61850.def index 7faa74db..991b2f8c 100644 --- a/src/vs/libiec61850.def +++ b/src/vs/libiec61850.def @@ -732,3 +732,5 @@ EXPORTS ClientGooseControlBlock_getFixedOffs ControlObjectClient_getCtlValType SVPublisher_ASDU_setSmpCntWrap + IedServerConfig_enableFileService + IedServerConfig_isFileServiceEnabled