diff --git a/Makefile b/Makefile index 6bb5ca4a..b5619d49 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,9 @@ LIB_SOURCE_DIRS += src/mms/iso_common LIB_SOURCE_DIRS += src/mms/iso_mms/common LIB_SOURCE_DIRS += src/mms/iso_mms/asn1c LIB_SOURCE_DIRS += src/mms/iso_server + +LIB_SOURCE_DIRS += src/logging + ifndef EXCLUDE_ETHERNET_WINDOWS LIB_SOURCE_DIRS += src/goose LIB_SOURCE_DIRS += src/sampled_values diff --git a/config/stack_config.h b/config/stack_config.h index e84ac65a..51ae3cfb 100644 --- a/config/stack_config.h +++ b/config/stack_config.h @@ -186,6 +186,7 @@ #define MMS_READ_SERVICE 1 #define MMS_WRITE_SERVICE 1 #define MMS_GET_NAME_LIST 1 +#define MMS_JOURNAL_SERVICE 1 #define MMS_GET_VARIABLE_ACCESS_ATTRIBUTES 1 #define MMS_DATA_SET_SERVICE 1 #define MMS_DYNAMIC_DATA_SETS 1 diff --git a/config/stack_config.h.cmake b/config/stack_config.h.cmake index c7ad4c4c..d1698165 100644 --- a/config/stack_config.h.cmake +++ b/config/stack_config.h.cmake @@ -175,6 +175,7 @@ #define MMS_READ_SERVICE 1 #define MMS_WRITE_SERVICE 1 #define MMS_GET_NAME_LIST 1 +#define MMS_JOURNAL_SERVICE 1 #define MMS_GET_VARIABLE_ACCESS_ATTRIBUTES 1 #define MMS_DATA_SET_SERVICE 1 #define MMS_DYNAMIC_DATA_SETS 1 diff --git a/src/iec61850/server/mms_mapping/logging.c b/src/iec61850/server/mms_mapping/logging.c index 160b3bc5..8a07a524 100644 --- a/src/iec61850/server/mms_mapping/logging.c +++ b/src/iec61850/server/mms_mapping/logging.c @@ -190,8 +190,8 @@ enableLogging(LogControl* logControl) printf(" data set (%s) not found!\n", logControl->dataSetRef); return false; } - - + else + logControl->dataSet = dataSet; return true; } @@ -326,6 +326,7 @@ createLogControlBlock(LogControlBlock* logControlBlock, logControl->mmsType = lcb; logControl->mmsValue = mmsValue; logControl->logControlBlock = logControlBlock; + logControl->triggerOps = logControlBlock->trgOps; logControl->enabled = logControlBlock->logEna; diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index 2560c886..30a1fb59 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -2621,12 +2621,37 @@ MmsMapping_triggerLogging(MmsMapping* self, MmsValue* value, LogInclusionFlag fl LogControl* lc = (LogControl*) element->data; if ((lc->enabled) && (lc->dataSet != NULL)) { - // switch (flag) { + int index; + switch (flag) { + + case LOG_CONTROL_VALUE_UPDATE: + if ((lc->triggerOps & TRG_OPT_DATA_UPDATE) == 0) + continue; + + break; + + case LOG_CONTROL_VALUE_CHANGED: + if (((lc->triggerOps & TRG_OPT_DATA_CHANGED) == 0) && + ((lc->triggerOps & TRG_OPT_DATA_UPDATE) == 0)) + continue; + + break; + + case LOG_CONTROL_QUALITY_CHANGED: + if ((lc->triggerOps & TRG_OPT_QUALITY_CHANGED) == 0) + continue; + + break; + + default: + continue; + } + if (DataSet_isMemberValue(lc->dataSet, value, &index)) { - printf("Log value\n"); + printf("Log value - flag:%i\n", flag); } diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index 8d16731a..b232d0d3 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -1679,7 +1679,7 @@ removeAllGIReportsFromReportBuffer(ReportBuffer* reportBuffer) static void enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_t timeOfEntry) { - // if (DEBUG_IED_SERVER) + if (DEBUG_IED_SERVER) printf("IED_SERVER: enqueueReport: RCB name: %s (SQN:%u) enabled:%i buffered:%i buffering:%i intg:%i GI:%i\n", reportControl->name, (unsigned) reportControl->sqNum, reportControl->enabled, reportControl->isBuffering, reportControl->buffered, isIntegrity, isGI); diff --git a/src/logging/log_storage_sqlite.c b/src/logging/log_storage_sqlite.c new file mode 100644 index 00000000..df766325 --- /dev/null +++ b/src/logging/log_storage_sqlite.c @@ -0,0 +1,67 @@ +/* + * log_storage_sqlite.c + * + */ + + +#include "logging_api.h" + + +static bool +SqLiteLogStorage_initializeLog(const char* logName, int logSize); + +static bool +SqLiteLogStorage_storeEntry(const char* logName, uint64_t entryID, MmsValue* timestamp, + int entrySize, uint8_t* entryData); + +static bool +SqLiteLogStorage_getEntries(const char* logName, MmsValue* timestamp, + LogEntryCallback callback, void* parameter); + +static bool +SqLiteLogStorage_getEntriesAfter(const char* logName, MmsValue* timestamp, uint64_t entryID, + LogEntryCallback callback, void* parameter); + +static struct sLogStorage logStorageInstance = { + SqLiteLogStorage_initializeLog, + SqLiteLogStorage_storeEntry, + SqLiteLogStorage_getEntries, + SqLiteLogStorage_getEntriesAfter +}; + +LogStorage +SqLiteStorage_createInstance() +{ + return &logStorageInstance; +} + +static bool +SqLiteLogStorage_initializeLog(const char* logName, int logSize) +{ + return true; +} + +static bool +SqLiteLogStorage_storeEntry(const char* logName, uint64_t entryID, MmsValue* timestamp, + int entrySize, uint8_t* entryData) +{ + return true; +} + +static bool +SqLiteLogStorage_getEntries(const char* logName, MmsValue* timestamp, + LogEntryCallback callback, void* parameter) +{ + return true; +} + +static bool +SqLiteLogStorage_getEntriesAfter(const char* logName, MmsValue* timestamp, uint64_t entryID, + LogEntryCallback callback, void* parameter) +{ + return true; +} + + + + diff --git a/src/logging/logging_api.h b/src/logging/logging_api.h new file mode 100644 index 00000000..deb0a9c8 --- /dev/null +++ b/src/logging/logging_api.h @@ -0,0 +1,31 @@ +/* + * logging_api.h + * + */ + +#ifndef LIBIEC61850_SRC_LOGGING_LOGGING_API_H_ +#define LIBIEC61850_SRC_LOGGING_LOGGING_API_H_ + +#include +#include +#include "mms_value.h" + +typedef struct sLogStorage* LogStorage; + +typedef void (*LogEntryCallback) (void* parameter, MmsValue* timestamp, uint64_t entryID, int entrySize, + uint8_t* entryData); + +struct sLogStorage { + bool (*initializeLog) (const char* logName, int logSize); + + bool (*storeEntry) (const char* logName, uint64_t entryID, MmsValue* timestamp, int entrySize, + uint8_t* entryData); + + bool (*getEntries) (const char* logName, MmsValue* timestamp, + LogEntryCallback callback, void* parameter); + + bool (*getEntriesAfter) (const char* logName, MmsValue* timestamp, uint64_t entryID, + LogEntryCallback callback, void* parameter); +}; + +#endif /* LIBIEC61850_SRC_LOGGING_LOGGING_API_H_ */ diff --git a/src/mms/inc_private/mms_server_internal.h b/src/mms/inc_private/mms_server_internal.h index 69913375..2ec666de 100644 --- a/src/mms/inc_private/mms_server_internal.h +++ b/src/mms/inc_private/mms_server_internal.h @@ -221,6 +221,14 @@ mmsServer_handleStatusRequest( int invokeId, ByteBuffer* response); +void +mmsServer_handleReadJournalRequest( + MmsServerConnection connection, + uint8_t* requestBuffer, + int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response); + void mmsServer_handleFileDirectoryRequest( MmsServerConnection connection, diff --git a/src/mms/iso_mms/client/mms_client_files.c b/src/mms/iso_mms/client/mms_client_files.c index 2ecf29a1..fcc7de18 100644 --- a/src/mms/iso_mms/client/mms_client_files.c +++ b/src/mms/iso_mms/client/mms_client_files.c @@ -60,7 +60,7 @@ mmsClient_createReadJournalRequest(uint32_t invokeId, ByteBuffer* request, const bufPos = BerEncoder_encodeTL(0x02, invokeIdSize, buffer, bufPos); bufPos = BerEncoder_encodeUInt32(invokeId, buffer, bufPos); - /* Encode FileOpen tag (context | structured ) [65 = 41h] */ + /* Encode read journal tag (context | structured ) [65 = 41h] */ buffer[bufPos++] = 0xbf; buffer[bufPos++] = 0x41; @@ -69,8 +69,6 @@ mmsClient_createReadJournalRequest(uint32_t invokeId, ByteBuffer* request, const bufPos = BerEncoder_encodeTL(0xa1, objectIdSize, buffer, bufPos); -// bufPos = BerEncoder_encodeTL(0xa1, domainIdStringSize, buffer, bufPos); - bufPos = BerEncoder_encodeOctetString(0x1a, (uint8_t*) domainId, domainIdStringSize, buffer, bufPos); bufPos = BerEncoder_encodeOctetString(0x1a, (uint8_t*) itemId, itemIdStringSize, buffer, bufPos); diff --git a/src/mms/iso_mms/server/mms_journal.c b/src/mms/iso_mms/server/mms_journal.c index 2f2f91df..ecb26d19 100644 --- a/src/mms/iso_mms/server/mms_journal.c +++ b/src/mms/iso_mms/server/mms_journal.c @@ -28,6 +28,9 @@ MmsJournal MmsJournal_create(const char* name) { + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: create new journal %s\n", name); + MmsJournal self = (MmsJournal) GLOBAL_MALLOC(sizeof(struct sMmsJournal)); self->name = copyString(name); diff --git a/src/mms/iso_mms/server/mms_journal_service.c b/src/mms/iso_mms/server/mms_journal_service.c new file mode 100644 index 00000000..e10e7e6d --- /dev/null +++ b/src/mms/iso_mms/server/mms_journal_service.c @@ -0,0 +1,131 @@ +/* + * mms_journal_service.c + * + * Copyright 2016 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" +#include "mms_server_internal.h" + +#if (MMS_JOURNAL_SERVICE == 1) + +static bool +parseStringWithMaxLength(char* filename, int maxLength, uint8_t* buffer, int* bufPos, int maxBufPos , uint32_t invokeId, ByteBuffer* response) +{ + uint8_t tag = buffer[(*bufPos)++]; + int length; + + if (tag != 0x19) { + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + return false; + } + + *bufPos = BerDecoder_decodeLength(buffer, &length, *bufPos, maxBufPos); + + if (*bufPos < 0) { + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + return false; + } + + if (length > maxLength) { + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response); + return false; + } + + memcpy(filename, buffer + *bufPos, length); + filename[length] = 0; + *bufPos += length; + + return true; +} + + +void +mmsServer_handleReadJournalRequest( + MmsServerConnection connection, + uint8_t* requestBuffer, + int bufPos, int maxBufPos, + uint32_t invokeId, + ByteBuffer* response) +{ + printf("READ-JOURNAL\n"); + + char domainId[65]; + char logName[65]; + + bool hasNames = false; + + while (bufPos < maxBufPos) { + uint8_t tag = requestBuffer[bufPos++]; + int length; + + bufPos = BerDecoder_decodeLength(requestBuffer, &length, bufPos, maxBufPos); + + if (bufPos < 0) { + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + return; + } + + switch (tag) { + + case 0xa0: + { + + uint8_t objectIdTag = requestBuffer[bufPos++]; + bufPos = BerDecoder_decodeLength(requestBuffer, &length, bufPos, maxBufPos); + + switch (objectIdTag) { + case 0xa1: /* domain-specific */ + printf(" domain-specific-log\n"); + + if (!parseStringWithMaxLength(domainId, 64, requestBuffer, &bufPos, bufPos + length, invokeId, response)) { + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response); + return; + } + + if (!parseStringWithMaxLength(logName, 64, requestBuffer, &bufPos, bufPos + length, invokeId, response)) { + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response); + return; + } + + printf(" domain: %s log: %s\n", domainId, logName); + + break; + + + default: + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_UNRECOGNIZED_MODIFIER, response); + return; + + } + } + + break; + + default: + mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + return; + } + + bufPos += length; + } +} + +#endif /* (MMS_JOURNAL_SERVICE == 1) */ diff --git a/src/mms/iso_mms/server/mms_server_connection.c b/src/mms/iso_mms/server/mms_server_connection.c index c0cf1c20..377d3e71 100644 --- a/src/mms/iso_mms/server/mms_server_connection.c +++ b/src/mms/iso_mms/server/mms_server_connection.c @@ -113,6 +113,12 @@ handleConfirmedRequestPdu( if (extendedTag) { switch(tag) { +#if (MMS_JOURNAL_SERVICE == 1) + case 0x41: /* read-journal */ + mmsServer_handleReadJournalRequest(self, buffer, bufPos, bufPos + length, invokeId, response); + break; +#endif /* (MMS_JOURNAL_SERVICE == 1) */ + #if (MMS_FILE_SERVICE == 1) case 0x48: /* file-open-request */ mmsServer_handleFileOpenRequest(self, buffer, bufPos, bufPos + length, invokeId, response); diff --git a/src/mms/iso_mms/server/mms_status_service.c b/src/mms/iso_mms/server/mms_status_service.c index d0d8f14b..a547b9f0 100644 --- a/src/mms/iso_mms/server/mms_status_service.c +++ b/src/mms/iso_mms/server/mms_status_service.c @@ -24,7 +24,7 @@ #include "libiec61850_platform_includes.h" #include "mms_server_internal.h" -#if MMS_STATUS_SERVICE == 1 +#if (MMS_STATUS_SERVICE == 1) void mmsServer_handleStatusRequest(