Merge branch 'v1.6_develop_rgoose_sntp__merge_develop' into v1.6_develop

pull/521/head
Michael Zillgith 1 year ago
commit 92c0fea9e8

@ -17,11 +17,13 @@ Other changes:
- Ethernet(Linux): Set to promisc mode by default
- removed legacy defines for report reasons (#449)
- removed legacy compatibility functions for SV subscriner ("SVClientaSDU_")
Fixed bugs and vulnerabilities:
- fixed out-of-bound read in parseAarePdu function (LIB61850-442)(#513)
- ACSE: fixed out-of-bounds read in parseAarqPdu function (LIB61850-441)(#512)
- Vulnerability: fixed potential stack buffer overflow in MMS client identity service and other services (LIB61850-447)
- Vulnerability: fixed out-of-bound read in parseAarePdu function (LIB61850-442)(#513)
- Vulnerability: ACSE: fixed out-of-bounds read in parseAarqPdu function (LIB61850-441)(#512)
- GOOSE receiver: added additional length and plausibility checks to fix #509
- MmsValue_decodeMmsData: add support for empty visible-string, mms-string, and octet-string values (#506)
- MMS client: fixed - getNameList task can get stuck in while loop when message cannot be sent (LIB61850-347)
@ -32,7 +34,7 @@ Fixed bugs and vulnerabilities:
- MMS server: fixed - server is sending data set response larger than negotiated MMS PDU size (LIB61850-435)
- fixed - potential race condition when using IedConnection_installReportHandler and IedConnection_uninstallReportHandler
- fixed - IEC 61580 server: dataset is not released when RCB.Datset is set to empty string by client (LIB61850-425)
- MMS client: fixed - parsing of servicecsSupported in MMS init response is off by one (LIB61850-419)(#469)
- Vulnerability: MMS client: fixed - parsing of servicecsSupported in MMS init response is off by one (LIB61850-419)(#469)

@ -52,6 +52,8 @@ option(CONFIG_IEC61850_SERVICE_TRACKING "Build with support for IEC 61850 servic
option(CONFIG_IEC61850_SETTING_GROUPS "Build with support for IEC 61850 setting group services" ON)
option(CONFIG_IEC61850_SUPPORT_USER_READ_ACCESS_CONTROL "Allow user provided callback to control read access" ON)
option(CONFIG_IEC61850_RCB_ALLOW_ONLY_PRECONFIGURED_CLIENT "allow only configured clients (when pre-configured by ClientLN)" OFF)
option(CONFIG_IEC61850_L2_GOOSE "Build with support for L2 GOOSE (winpcap required on windows)" ON)
option(CONFIG_IEC61850_L2_SMV "Build with support for L2 SMV (winpcap required on windows)" ON)
option(CONFIG_IEC61850_R_GOOSE "Build with support for R-GOOSE (mbedtls required)" ON)
option(CONFIG_IEC61850_R_SMV "Build with support for R-SMV (mbedtls required)" ON)
option(CONFIG_IEC61850_SNTP_CLIENT "Build with SNTP client code" ON)
@ -142,12 +144,17 @@ set(FOUND_SQLITE3_SOURCE 1)
message("Found sqlite3 source in third_party folder -> can compile with log service support")
endif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/sqlite/sqlite3.h)
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-3.6.0)
set(WITH_MBEDTLS3 1)
set(MBEDTLS_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-3.6.0/include")
else()
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28)
set(WITH_MBEDTLS 1)
set(MBEDTLS_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28/include")
endif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28)
endif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-3.6.0)
if(WITH_MBEDTLS)
if(WITH_MBEDTLS OR WITH_MBEDTLS3)
add_definitions(-DCONFIG_MMS_SUPPORT_TLS=1)
@ -163,7 +170,12 @@ if (CONFIG_IEC61850_SNTP_CLIENT)
set(BUILD_SNTP_CLIENT_EXAMPLES 1)
endif (CONFIG_IEC61850_SNTP_CLIENT)
endif(WITH_MBEDTLS)
else(WITH_MBEDTLS OR WITH_MBEDTLS3)
set(CONFIG_IEC61850_R_GOOSE 0)
set(CONFIG_IEC61850_R_SMV 0)
endif(WITH_MBEDTLS OR WITH_MBEDTLS3)
include(CheckCCompilerFlag)

@ -72,6 +72,7 @@ LIB_INCLUDE_DIRS += src/sampled_values
LIB_INCLUDE_DIRS += src/iec61850/inc
LIB_INCLUDE_DIRS += src/iec61850/inc_private
LIB_INCLUDE_DIRS += src/logging
LIB_INCLUDE_DIRS += src/r_session
LIB_INCLUDE_DIRS += src/tls
ifeq ($(HAL_IMPL), WIN32)
LIB_INCLUDE_DIRS += third_party/winpcap/Include
@ -84,6 +85,8 @@ LIB_INCLUDE_DIRS += third_party/mbedtls/mbedtls-2.28/include
LIB_INCLUDE_DIRS += hal/tls/mbedtls
CFLAGS += -D'MBEDTLS_CONFIG_FILE="mbedtls_config.h"'
CFLAGS += -D'CONFIG_MMS_SUPPORT_TLS=1'
CFLAGS += -D'CONFIG_IEC61850_R_GOOSE=1'
CFLAGS += -D'CONFIG_IEC61850_R_SMV=1'
endif
LIB_INCLUDES = $(addprefix -I,$(LIB_INCLUDE_DIRS))
@ -120,6 +123,7 @@ LIB_API_HEADER_FILES += src/goose/goose_publisher.h
LIB_API_HEADER_FILES += src/sampled_values/sv_subscriber.h
LIB_API_HEADER_FILES += src/sampled_values/sv_publisher.h
LIB_API_HEADER_FILES += src/logging/logging_api.h
LIB_API_HEADER_FILES += src/r_session/r_session.h
get_sources_from_directory = $(wildcard $1/*.c)
get_sources = $(foreach dir, $1, $(call get_sources_from_directory,$(dir)))
@ -137,13 +141,13 @@ ifneq ($(HAL_IMPL), WIN32)
CFLAGS += -Wuninitialized
endif
CFLAGS += -Wsign-compare
CFLAGS += -Wpointer-arith
CFLAGS += -Wnested-externs
CFLAGS += -Wmissing-declarations
CFLAGS += -Wshadow
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Wno-sign-compare
CFLAGS += -Wno-format
#CFLAGS += -Wconditional-uninitialized
#CFLAGS += -Werror

@ -53,8 +53,8 @@ The library support the following IEC 61850 protocol features:
* Setting group handling
* Support for service tracking
* GOOSE and SV control block handling
* Support for R-session protocol/R-GOOSE/R-SMV
* Simple SNTP client code
* Support for R-session protocol/R-GOOSE/R-SMV (BETA)
* Simple SNTP client code (BETA)
* TLS support
* C and C#/.NET API

@ -68,36 +68,20 @@
/* maximum COTP (ISO 8073) TPDU size - valid range is 1024 - 8192 */
#define CONFIG_COTP_MAX_TPDU_SIZE 8192
/* Ethernet interface ID for GOOSE and SV */
/* Ethernet interface ID for L2 GOOSE and SV */
#define CONFIG_ETHERNET_INTERFACE_ID "eth0"
/* #define CONFIG_ETHERNET_INTERFACE_ID "vboxnet0" */
/* #define CONFIG_ETHERNET_INTERFACE_ID "en0" // OS X uses enX in place of ethX as ethernet NIC names. */
/* Set to 1 to include GOOSE support in the build. Otherwise set to 0 */
/* Set to 1 to include generic GOOSE support in the build. Otherwise set to 0 */
#define CONFIG_INCLUDE_GOOSE_SUPPORT 1
/* Set to 1 to include Sampled Values support in the build. Otherwise set to 0 */
/* Set to 1 to include generic Sampled Values support in the build. Otherwise set to 0 */
#define CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT 1
/* Set to 1 to compile for edition 1 server - default is 0 to compile for edition 2 */
#define CONFIG_IEC61850_EDITION_1 0
#ifdef _WIN32
/* GOOSE will be disabled for Windows if ethernet support (winpcap) is not available */
#ifdef EXCLUDE_ETHERNET_WINDOWS
#ifdef CONFIG_INCLUDE_GOOSE_SUPPORT
#undef CONFIG_INCLUDE_GOOSE_SUPPORT
#endif
#define CONFIG_INCLUDE_GOOSE_SUPPORT 0
#define CONFIG_INCUDE_ETHERNET_WINDOWS 0
#else
#define CONFIG_INCLUDE_ETHERNET_WINDOWS 1
#undef CONFIG_ETHERNET_INTERFACE_ID
#define CONFIG_ETHERNET_INTERFACE_ID "0"
#endif
#endif
/* The GOOSE retransmission interval in ms for the stable condition - i.e. no monitored value changed */
#define CONFIG_GOOSE_STABLE_STATE_TRANSMISSION_INTERVAL 5000
@ -179,9 +163,36 @@
/* compile with support for R-SMV (mbedtls required) */
#define CONFIG_IEC61850_R_SMV 0
/* compile with support for L2 GOOSE */
#define CONFIG_IEC61850_L2_GOOSE 0
/* compile with support for L2 SMV */
#define CONFIG_IEC61850_L2_SMV 0
/* compile SNTP client code */
#define CONFIG_IEC61850_SNTP_CLIENT 0
#ifdef _WIN32
/* L2 GOOSE/SMV will be disabled for Windows if ethernet support (winpcap) is not available */
#ifdef EXCLUDE_ETHERNET_WINDOWS
#ifdef CONFIG_IEC61850_L2_GOOSE
#undef CONFIG_IEC61850_L2_GOOSE
#endif
#ifdef CONFIG_IEC61850_L2_SMV
#undef CONFIG_IEC61850_L2_SMV
#endif
#define CONFIG_IEC61850_L2_GOOSE 0
#define CONFIG_IEC61850_L2_SMV 0
#define CONFIG_INCUDE_ETHERNET_WINDOWS 0
#else
#define CONFIG_INCLUDE_ETHERNET_WINDOWS 1
#undef CONFIG_ETHERNET_INTERFACE_ID
#define CONFIG_ETHERNET_INTERFACE_ID "0"
#endif
#endif
/* overwrite default results for MMS identify service */
/* #define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com" */
/* #define CONFIG_DEFAULT_MMS_MODEL_NAME "LIBIEC61850" */

@ -68,10 +68,10 @@
/* #define CONFIG_ETHERNET_INTERFACE_ID "vboxnet0" */
/* #define CONFIG_ETHERNET_INTERFACE_ID "en0" // OS X uses enX in place of ethX as ethernet NIC names. */
/* Set to 1 to include GOOSE support in the build. Otherwise set to 0 */
/* Set to 1 to include generic GOOSE support in the build. Otherwise set to 0 */
#cmakedefine01 CONFIG_INCLUDE_GOOSE_SUPPORT
/* Set to 1 to include Sampled Values support in the build. Otherwise set to 0 */
/* Set to 1 to include generic Sampled Values support in the build. Otherwise set to 0 */
#define CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT 1
/* compile with support for R-GOOSE (mbedtls requried) */
@ -80,6 +80,12 @@
/* compile with support for R-SMV (mbedtls required) */
#cmakedefine01 CONFIG_IEC61850_R_SMV
/* compile with support for L2 GOOSE */
#cmakedefine01 CONFIG_IEC61850_L2_GOOSE
/* compile with support for L2 SMV */
#cmakedefine01 CONFIG_IEC61850_L2_SMV
/* compile SNTP client code */
#cmakedefine01 CONFIG_IEC61850_SNTP_CLIENT
@ -88,12 +94,16 @@
#ifdef _WIN32
/* GOOSE will be disabled for Windows if ethernet support (winpcap) is not available */
/* L2 GOOSE/SMV will be disabled for Windows if ethernet support (winpcap) is not available */
#ifdef EXCLUDE_ETHERNET_WINDOWS
#ifdef CONFIG_INCLUDE_GOOSE_SUPPORT
#undef CONFIG_INCLUDE_GOOSE_SUPPORT
#ifdef CONFIG_IEC61850_L2_GOOSE
#undef CONFIG_IEC61850_L2_GOOSE
#endif
#ifdef CONFIG_IEC61850_L2_SMV
#undef CONFIG_IEC61850_L2_SMV
#endif
#define CONFIG_INCLUDE_GOOSE_SUPPORT 0
#define CONFIG_IEC61850_L2_GOOSE 0
#define CONFIG_IEC61850_L2_SMV 0
#define CONFIG_INCUDE_ETHERNET_WINDOWS 0
#else
#define CONFIG_INCLUDE_ETHERNET_WINDOWS 1

@ -55,10 +55,10 @@ else()
set(BUILD_SV_GOOSE_EXAMPLES ON)
endif()
if(WITH_MBEDTLS)
if(WITH_MBEDTLS OR WITH_MBEDTLS3)
add_subdirectory(tls_client_example)
add_subdirectory(tls_server_example)
endif(WITH_MBEDTLS)
endif(WITH_MBEDTLS OR WITH_MBEDTLS3)
if(${BUILD_SV_GOOSE_EXAMPLES})
add_subdirectory(server_example_goose)

@ -129,7 +129,8 @@ int main(int argc, char** argv)
int c;
while ((c = getopt(argc, argv, "mifdh:p:l:t:a:r:g:j:x:v:c:y:z:")) != -1) {
while ((c = getopt(argc, argv, "mifdh:p:l:t:a:r:g:j:x:v:c:y:z:")) != -1)
{
switch (c) {
case 'm':
printRawMmsMessages = 1;
@ -212,7 +213,8 @@ int main(int argc, char** argv)
if (printRawMmsMessages)
MmsConnection_setRawMessageHandler(con, (MmsRawMessageHandler) printRawMmsMessage, NULL);
if (!MmsConnection_connect(con, &error, hostname, tcpPort)) {
if (!MmsConnection_connect(con, &error, hostname, tcpPort))
{
printf("MMS connect failed!\n");
if (error != MMS_ERROR_NONE)
@ -223,14 +225,16 @@ int main(int argc, char** argv)
else
printf("MMS connected.\n");
if (identifyDevice) {
if (identifyDevice)
{
MmsServerIdentity* identity =
MmsConnection_identify(con, &error);
if (error != MMS_ERROR_NONE)
returnCode = error;
if (identity != NULL) {
if (identity != NULL)
{
printf("\nServer identity:\n----------------\n");
printf(" vendor:\t%s\n", identity->vendorName);
printf(" model:\t%s\n", identity->modelName);
@ -240,32 +244,37 @@ int main(int argc, char** argv)
printf("Reading server identity failed!\n");
}
if (readDeviceList) {
if (readDeviceList)
{
printf("\nDomains present on server:\n--------------------------\n");
LinkedList nameList = MmsConnection_getDomainNames(con, &error);
if (error != MMS_ERROR_NONE)
returnCode = error;
if (nameList) {
if (nameList)
{
LinkedList_printStringList(nameList);
LinkedList_destroy(nameList);
}
}
if (getDeviceDirectory) {
if (getDeviceDirectory)
{
LinkedList variableList = MmsConnection_getDomainVariableNames(con, &error,
domainName);
if (error != MMS_ERROR_NONE)
returnCode = error;
if (variableList) {
if (variableList)
{
LinkedList element = LinkedList_getNext(variableList);
printf("\nMMS domain variables for domain %s\n", domainName);
while (element != NULL) {
while (element != NULL)
{
char* name = (char*) element->data;
printf(" %s\n", name);
@ -284,8 +293,8 @@ int main(int argc, char** argv)
if (error != MMS_ERROR_NONE)
returnCode = error;
if (variableList) {
if (variableList)
{
LinkedList element = variableList;
printf("\nMMS journals for domain %s\n", domainName);
@ -301,18 +310,17 @@ int main(int argc, char** argv)
else {
printf("\nFailed to read domain journals (error=%d)\n", error);
}
}
if (readJournal) {
if (readJournal)
{
printf(" read journal %s...\n", journalName);
char* logDomain = journalName;
char* logName = strchr(journalName, '/');
if (logName != NULL) {
if (logName != NULL)
{
logName[0] = 0;
logName++;
@ -335,11 +343,12 @@ int main(int argc, char** argv)
MmsValue_delete(startTime);
MmsValue_delete(endTime);
if (journalEntries != NULL) {
if (journalEntries != NULL)
{
bool readNext;
do {
do
{
readNext = false;
LinkedList lastEntry = LinkedList_getLastElement(journalEntries);
@ -353,7 +362,8 @@ int main(int argc, char** argv)
LinkedList_destroyDeep(journalEntries, (LinkedListValueDeleteFunction)
MmsJournalEntry_destroy);
if (moreFollows) {
if (moreFollows)
{
char buf[100];
MmsValue_printToBuffer(nextEntryId, buf, 100);
@ -374,12 +384,14 @@ int main(int argc, char** argv)
printf(" Invalid log name!\n");
}
if (readVariable) {
if (readWriteHasDomain) {
if (readVariable)
{
if (readWriteHasDomain)
{
MmsValue* result;
if (componentName == NULL) {
if (componentName == NULL)
{
if (arrayIndex == -1) {
result = MmsConnection_readVariable(con, &error, domainName, variableName);
}
@ -396,15 +408,18 @@ int main(int argc, char** argv)
}
}
if (error != MMS_ERROR_NONE) {
if (error != MMS_ERROR_NONE)
{
printf("Reading variable failed: (ERROR %i)\n", error);
returnCode = error;
}
else {
else
{
printf("Read SUCCESS\n");
if (result != NULL) {
if (result != NULL)
{
char outbuf[1024];
MmsValue_printToBuffer(result, outbuf, 1024);
@ -416,22 +431,27 @@ int main(int argc, char** argv)
else
printf("result: NULL\n");
}
}
else
{
printf("Reading VMD scope variable not yet supported!\n");
}
}
if (readVariableList) {
if (readWriteHasDomain) {
if (readVariableList)
{
if (readWriteHasDomain)
{
MmsValue* variables = MmsConnection_readNamedVariableListValues(con, &error, domainName, variableName, true);
if (error != MMS_ERROR_NONE) {
if (error != MMS_ERROR_NONE)
{
printf("Reading variable failed: (ERROR %i)\n", error);
returnCode = error;
}
else {
else
{
printf("Read SUCCESS\n");
}
}
@ -439,24 +459,28 @@ int main(int argc, char** argv)
printf("Reading VMD scope variable list not yet supported!\n");
}
if (readDataSetDirectory) {
if (readWriteHasDomain) {
if (readDataSetDirectory)
{
if (readWriteHasDomain)
{
bool deletable = false;
LinkedList varListDir = MmsConnection_readNamedVariableListDirectory(con, &error, domainName, variableName, &deletable);
if (error != MMS_ERROR_NONE) {
if (error != MMS_ERROR_NONE)
{
printf("Reading variable list directory failed: (ERROR %i)\n", error);
returnCode = error;
}
else {
else
{
LinkedList varListElem = LinkedList_getNext(varListDir);
int listIdx = 0;
while (varListElem) {
while (varListElem)
{
MmsVariableAccessSpecification* varAccessSpec = (MmsVariableAccessSpecification*)LinkedList_getData(varListElem);
if (varAccessSpec->arrayIndex)
@ -476,14 +500,15 @@ int main(int argc, char** argv)
printf("Reading VMD scope variable list not yet supported!\n");
}
if (showFileList) {
if (showFileList)
{
char lastName[300];
lastName[0] = 0;
char* continueAfter = NULL;
while (MmsConnection_getFileDirectory(con, &error, "", continueAfter, mmsFileDirectoryHandler, lastName)) {
while (MmsConnection_getFileDirectory(con, &error, "", continueAfter, mmsFileDirectoryHandler, lastName))
{
if (error != MMS_ERROR_NONE)
returnCode = error;
@ -491,21 +516,25 @@ int main(int argc, char** argv)
}
}
if (getFileAttributes) {
if (getFileAttributes)
{
MmsConnection_getFileDirectory(con, &error, filename, NULL, mmsGetFileAttributeHandler, NULL);
if (error != MMS_ERROR_NONE)
returnCode = error;
}
if (deleteFile) {
if (deleteFile)
{
MmsConnection_fileDelete(con, &error, filename);
if (error != MMS_ERROR_NONE) {
if (error != MMS_ERROR_NONE)
{
printf("Delete file failed: (ERROR %i)\n", error);
returnCode = error;
}
else {
else
{
printf("File deleted\n");
}
}
@ -521,4 +550,3 @@ exit:
return returnCode;
}

@ -21,8 +21,8 @@ main(int argc, char** argv)
{
RSession rSession = RSession_create();
if (rSession) {
if (rSession)
{
/* Call RSession_setLocalAddress to use a particular interface to send the R-GOOSE messages */
//RSession_setLocalAddress(rSession, "169.254.110.126", -1);
RSession_setRemoteAddress(rSession, "230.0.10.10", 102);
@ -32,8 +32,8 @@ main(int argc, char** argv)
uint32_t activeKeyId = 1;
uint64_t nextKeyChangeTime = Hal_getTimeInMs() + 5000;
if (svPublisher) {
if (svPublisher)
{
signal(SIGINT, sigint_handler);
char* key1 = "0123456789ABCDEF";
@ -63,7 +63,8 @@ main(int argc, char** argv)
RSession_start(rSession);
while (running) {
while (running)
{
Timestamp ts;
Timestamp_clearFlags(&ts);
Timestamp_setTimeInMilliseconds(&ts, Hal_getTimeInMs());
@ -84,7 +85,8 @@ main(int argc, char** argv)
SVPublisher_publish(svPublisher);
if (Hal_getTimeInMs() >= nextKeyChangeTime) {
if (Hal_getTimeInMs() >= nextKeyChangeTime)
{
/* change key */
if (activeKeyId == 1)
@ -101,14 +103,15 @@ main(int argc, char** argv)
SVPublisher_destroy(svPublisher);
}
else {
else
{
printf("Failed to create SV publisher\n");
}
RSession_destroy(rSession);
}
else {
else
{
printf("Failed to create remote session instance\n");
}
}

@ -50,8 +50,8 @@ main(int argc, char** argv)
{
RSession rSession = RSession_create();
if (rSession) {
if (rSession)
{
RSession_setLocalAddress(rSession, "0.0.0.0", 102);
RSession_addMulticastGroup(rSession, "230.0.10.10");
@ -64,7 +64,8 @@ main(int argc, char** argv)
SVReceiver receiver = SVReceiver_createRemote(rSession);
if (receiver) {
if (receiver)
{
/* Create a subscriber listening to SV messages with APPID 4000h */
SVSubscriber subscriber = SVSubscriber_create(NULL, 0x4000);
@ -77,7 +78,8 @@ main(int argc, char** argv)
/* Start listening to SV messages - starts a new receiver background thread */
SVReceiver_start(receiver);
if (SVReceiver_isRunning(receiver)) {
if (SVReceiver_isRunning(receiver))
{
signal(SIGINT, sigint_handler);
while (running)
@ -86,21 +88,23 @@ main(int argc, char** argv)
/* Stop listening to SV messages */
SVReceiver_stop(receiver);
}
else {
else
{
printf("Failed to start SV subscriber. Reason can be that the Ethernet interface doesn't exist or root permission are required.\n");
}
/* Cleanup and free resources */
SVReceiver_destroy(receiver);
}
else {
else
{
printf("Failed to create SV receiver\n");
}
RSession_destroy(rSession);
}
else {
else
{
printf("Failed to create remote session protocol\n");
}
}

@ -10,7 +10,7 @@ endif()
project(hal)
set(LIBHAL_VERSION_MAJOR "2")
set(LIBHAL_VERSION_MINOR "1")
set(LIBHAL_VERSION_MINOR "2")
set(LIBHAL_VERSION_PATCH "0")
# feature checks
@ -28,7 +28,7 @@ message("Found winpcap -> compile ethernet HAL layer (required for GOOSE/SV supp
set(WITH_WPCAP 1)
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/Include")
else()
message("winpcap not found -> skip ethernet HAL layer (no GOOSE/SV support)")
message("winpcap not found -> skip ethernet HAL layer (no L2 GOOSE/SV support)")
endif()
endif(WIN32)
@ -116,10 +116,15 @@ ENDIF(WIN32)
#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC" )
if(WITH_MBEDTLS)
message("Found mbedtls -> can compile HAL with TLS support")
message("Found mbedtls 2.28 -> can compile HAL with TLS 1.2 support")
set(WITH_MBEDTLS 1)
endif(WITH_MBEDTLS)
if (WITH_MBEDTLS3)
message("Found mbedtls 3.6 -> can compile HAL with TLS 1.3 support")
set(WITH_MBEDTLS3 1)
endif(WITH_MBEDTLS3)
if(WITH_MBEDTLS)
include_directories(
${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls
@ -147,6 +152,32 @@ list (APPEND libhal_SRCS ${tls_SRCS})
endif(WITH_MBEDTLS)
if(WITH_MBEDTLS3)
include_directories(
${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls3
${MBEDTLS_INCLUDE_DIR}
)
if(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB)
link_directories(${CONFIG_EXTERNAL_MBEDTLS_DYNLIB_PATH})
else()
file(GLOB tls_SRCS ${CMAKE_CURRENT_LIST_DIR}/../third_party/mbedtls/mbedtls-3.6.0/library/*.c)
endif(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB)
add_definitions(-DMBEDTLS_CONFIG_FILE="mbedtls_config.h")
set (libhal_SRCS ${libhal_SRCS}
${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls3/tls_mbedtls.c
)
IF(MSVC)
set_source_files_properties(${libhal_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF()
list (APPEND libhal_SRCS ${tls_SRCS})
endif(WITH_MBEDTLS3)
add_library (hal STATIC ${libhal_SRCS})
add_library (hal-shared STATIC ${libhal_SRCS})
@ -178,6 +209,11 @@ IF(MINGW)
target_link_libraries(hal ws2_32 iphlpapi)
ENDIF(MINGW)
IF (MSVC)
target_link_libraries(hal bcrypt)
target_link_libraries(hal-shared bcrypt)
ENDIF()
iF(WITH_WPCAP)
target_link_libraries(hal
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/Lib/wpcap.lib

@ -17,6 +17,7 @@
#include <unistd.h>
#include <sys/time.h>
#include <sys/select.h>
#include <poll.h>
#include "hal_serial.h"
#include "hal_time.h"
@ -29,11 +30,10 @@ struct sSerialPort {
char parity;
uint8_t stopBits;
uint64_t lastSentTime;
struct timeval timeout;
int timeout;
SerialPortError lastError;
};
SerialPort
SerialPort_create(const char* interfaceName, int baudRate, uint8_t dataBits, char parity, uint8_t stopBits)
{
@ -46,8 +46,7 @@ SerialPort_create(const char* interfaceName, int baudRate, uint8_t dataBits, cha
self->stopBits = stopBits;
self->parity = parity;
self->lastSentTime = 0;
self->timeout.tv_sec = 0;
self->timeout.tv_usec = 100000; /* 100 ms */
self->timeout = 100; /* 100 ms */
strncpy(self->interfaceName, interfaceName, 99);
self->lastError = SERIAL_PORT_ERROR_NONE;
}
@ -212,8 +211,7 @@ SerialPort_discardInBuffer(SerialPort self)
void
SerialPort_setTimeout(SerialPort self, int timeout)
{
self->timeout.tv_sec = timeout / 1000;
self->timeout.tv_usec = (timeout % 1000) * 1000;
self->timeout = timeout;
}
SerialPortError
@ -226,14 +224,14 @@ int
SerialPort_readByte(SerialPort self)
{
uint8_t buf[1];
fd_set set;
struct pollfd fds[1];
self->lastError = SERIAL_PORT_ERROR_NONE;
FD_ZERO(&set);
FD_SET(self->fd, &set);
fds[0].fd = self->fd;
fds[0].events = POLLIN;
int ret = select(self->fd + 1, &set, NULL, NULL, &(self->timeout));
int ret = poll(fds, 1, self->timeout);
if (ret == -1) {
self->lastError = SERIAL_PORT_ERROR_UNKNOWN;

@ -479,10 +479,6 @@ Socket_connectAsync(Socket self, const char* address, int port)
if (!prepareAddress(address, port, &serverAddress))
return false;
fd_set fdSet;
FD_ZERO(&fdSet);
FD_SET(self->fd, &fdSet);
activateTcpNoDelay(self);
fcntl(self->fd, F_SETFL, O_NONBLOCK);
@ -506,17 +502,14 @@ Socket_connectAsync(Socket self, const char* address, int port)
SocketState
Socket_checkAsyncConnectState(Socket self)
{
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
struct pollfd fds[1];
fd_set fdSet;
FD_ZERO(&fdSet);
FD_SET(self->fd, &fdSet);
fds[0].fd = self->fd;
fds[0].events = POLLOUT;
int selectVal = select(self->fd + 1, NULL, &fdSet , NULL, &timeout);
int result = poll(fds, 1, 0);
if (selectVal == 1) {
if (result == 1) {
/* Check if connection is established */
@ -531,7 +524,7 @@ Socket_checkAsyncConnectState(Socket self)
return SOCKET_STATE_FAILED;
}
else if (selectVal == 0) {
else if (result == 0) {
return SOCKET_STATE_CONNECTING;
}
else {
@ -545,15 +538,14 @@ Socket_connect(Socket self, const char* address, int port)
if (Socket_connectAsync(self, address, port) == false)
return false;
struct timeval timeout;
timeout.tv_sec = self->connectTimeout / 1000;
timeout.tv_usec = (self->connectTimeout % 1000) * 1000;
struct pollfd fds[1];
fds[0].fd = self->fd;
fds[0].events = POLLOUT;
fd_set fdSet;
FD_ZERO(&fdSet);
FD_SET(self->fd, &fdSet);
int result = poll(fds, 1, self->connectTimeout);
if (select(self->fd + 1, NULL, &fdSet , NULL, &timeout) == 1) {
if (result == 1) {
/* Check if connection is established */

@ -72,7 +72,7 @@ struct sTLSConfiguration {
/* TLS minimum version allowed (default: TLS_VERSION_TLS_1_0) */
TLSConfigVersion minVersion;
/* TLS minimum version allowed (default: TLS_VERSION_TLS_1_2) */
/* TLS maximum version allowed (default: TLS_VERSION_TLS_1_2) */
TLSConfigVersion maxVersion;
TLSConfiguration_EventHandler eventHandler;
@ -308,7 +308,7 @@ TLSConfiguration_create()
{
TLSConfiguration self = (TLSConfiguration) GLOBAL_CALLOC(1, sizeof(struct sTLSConfiguration));
if (self != NULL)
if (self)
{
mbedtls_ssl_config_init( &(self->conf) );
mbedtls_x509_crt_init( &(self->ownCertificate) );

@ -0,0 +1,73 @@
// https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#introduce-a-level-of-indirection-and-versioning-in-the-config-files
// #ifndef MBEDTLS_CONFIG_H
// #define MBEDTLS_CONFIG_H
/* System support */
#define MBEDTLS_HAVE_ASM
#define MBEDTLS_HAVE_TIME
#define MBEDTLS_HAVE_TIME_DATE
#define MBEDTLS_NO_UDBL_DIVISION
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_DEBUG_C
/* mbed TLS feature support */
#define MBEDTLS_CIPHER_MODE_CBC
#define MBEDTLS_PKCS1_V15
#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
#define MBEDTLS_SSL_PROTO_TLS1_2
#define MBEDTLS_SSL_PROTO_TLS1_3
// MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#remove-support-for-tls-10-11-and-dtls-10
// #define MBEDTLS_SSL_PROTO_TLS1_1
// #define MBEDTLS_SSL_PROTO_TLS1
#define MBEDTLS_SSL_RENEGOTIATION
#error "MBEDTLS"
#define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES
/* mbed TLS modules */
#define MBEDTLS_GCM_C
#define MBEDTLS_AES_C
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_ASN1_WRITE_C
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_CTR_DRBG_C
/* #define MBEDTLS_DES_C */
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_MD_C
#define MBEDTLS_MD5_C
#define MBEDTLS_NET_C
#define MBEDTLS_OID_C
#define MBEDTLS_PK_C
#define MBEDTLS_PK_PARSE_C
#define MBEDTLS_RSA_C
#define MBEDTLS_SHA1_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SSL_CLI_C
#define MBEDTLS_SSL_SRV_C
#define MBEDTLS_SSL_TLS_C
#define MBEDTLS_X509_CRT_PARSE_C
#define MBEDTLS_X509_CRL_PARSE_C
#define MBEDTLS_X509_USE_C
#define MBEDTLS_SSL_CACHE_C
/* For test certificates */
#define MBEDTLS_BASE64_C
#define MBEDTLS_CERTS_C
#define MBEDTLS_PEM_PARSE_C
#define MBEDTLS_PKCS12_C
#define MBEDTLS_PKCS5_C
/* For testing with compat.sh */
#define MBEDTLS_FS_IO
// MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#remove-mbedtls_x509_check__key_usage-options-from-mbedtls_configh
// #define MBEDTLS_X509_CHECK_KEY_USAGE
// #define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE
// MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#introduce-a-level-of-indirection-and-versioning-in-the-config-files
// #include "mbedtls/check_config.h"
// #endif /* MBEDTLS_CONFIG_H */

File diff suppressed because it is too large Load Diff

@ -1,9 +1,16 @@
if(WITH_MBEDTLS3)
include_directories(
${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls3
${CMAKE_CURRENT_LIST_DIR}/../third_party/mbedtls/mbedtls-3.6.0/include
)
else()
if(WITH_MBEDTLS)
include_directories(
${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls
${CMAKE_CURRENT_LIST_DIR}/../third_party/mbedtls/mbedtls-2.28/include
)
endif(WITH_MBEDTLS)
endif(WITH_MBEDTLS3)
set (lib_common_SRCS
./common/string_map.c
@ -189,7 +196,7 @@ set (lib_sv_SRCS
./sampled_values/sv_publisher.c
)
if(WITH_MBEDTLS AND (CONFIG_IEC61850_R_GOOSE OR CONFIG_IEC61850_R_SMV))
if((WITH_MBEDTLS OR WITH_MBEDTLS3) AND (CONFIG_IEC61850_R_GOOSE OR CONFIG_IEC61850_R_SMV))
set (lib_rsession_SRCS
./r_session/r_session.c
./r_session/r_session_crypto_mbedtls.c
@ -220,7 +227,7 @@ set (lib_bsd_SRCS
IF(WIN32)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/Lib/wpcap.lib")
message("Found winpcap -> can compile with GOOSE support")
message("Found winpcap -> can compile with L2 GOOSE/SMV support")
set(WITH_WPCAP 1)
endif()
@ -232,16 +239,13 @@ set_source_files_properties(${lib_common_SRCS} ${lib_windows_SRCS}
PROPERTIES LANGUAGE CXX)
set_source_files_properties(${lib_rsession_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF()
IF(WITH_WPCAP)
IF(MSVC)
set_source_files_properties(${lib_goose_SRCS}
PROPERTIES LANGUAGE CXX)
set_source_files_properties(${lib_sv_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF()
IF(WITH_WPCAP)
ELSE()
add_definitions(-DEXCLUDE_ETHERNET_WINDOWS)
ENDIF()
@ -250,7 +254,7 @@ include_directories(
../third_party/winpcap/include
)
IF(WITH_WPCAP)
IF(WITH_WPCAP OR CONFIG_IEC61850_R_GOOSE OR CONFIG_IEC61850_R_SMV)
set (library_SRCS
${lib_common_SRCS}
${lib_asn1c_SRCS}
@ -266,11 +270,10 @@ set (library_SRCS
${lib_common_SRCS}
${lib_asn1c_SRCS}
${lib_windows_SRCS}
${lib_rsession_SRCS}
${lib_sntp_SRCS}
)
ENDIF(WITH_WPCAP)
ENDIF(WITH_WPCAP OR CONFIG_IEC61850_R_GOOSE OR CONFIG_IEC61850_R_SMV)
ELSEIF(UNIX)
IF(APPLE)

@ -40,7 +40,8 @@
static bool
prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, const char* interfaceID, bool useVlanTags);
struct sGoosePublisher {
struct sGoosePublisher
{
uint8_t* buffer;
#if (CONFIG_IEC61850_R_GOOSE == 1)
@ -49,8 +50,10 @@ struct sGoosePublisher {
uint16_t appId;
#endif /* (CONFIG_IEC61850_R_GOOSE == 1) */
#if (CONFIG_IEC61850_L2_GOOSE == 1)
/* only for Ethernet based GOOSE */
EthernetSocket ethernetSocket;
#endif /* (CONFIG_IEC61850_L2_GOOSE == 1) */
int lengthField;
int payloadStart;
@ -99,6 +102,7 @@ GoosePublisher_createRemote(RSession session, uint16_t appId)
}
#endif /* (CONFIG_IEC61850_R_GOOSE == 1) */
#if (CONFIG_IEC61850_L2_GOOSE == 1)
GoosePublisher
GoosePublisher_createEx(CommParameters* parameters, const char* interfaceID, bool useVlanTag)
{
@ -127,15 +131,18 @@ GoosePublisher_create(CommParameters* parameters, const char* interfaceID)
{
return GoosePublisher_createEx(parameters, interfaceID, true);
}
#endif /* (CONFIG_IEC61850_L2_GOOSE == 1) */
void
GoosePublisher_destroy(GoosePublisher self)
{
if (self)
{
#if (CONFIG_IEC61850_L2_GOOSE == 1)
if (self->ethernetSocket) {
Ethernet_destroySocket(self->ethernetSocket);
}
#endif /* (CONFIG_IEC61850_L2_GOOSE == 1) */
MmsValue_delete(self->timestamp);
@ -242,6 +249,7 @@ GoosePublisher_setTimeAllowedToLive(GoosePublisher self, uint32_t timeAllowedToL
self->timeAllowedToLive = timeAllowedToLive;
}
#if (CONFIG_IEC61850_L2_GOOSE == 1)
static bool
prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, const char* interfaceID, bool useVlanTags)
{
@ -342,6 +350,7 @@ prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, const char*
return false;
}
}
#endif /* (CONFIG_IEC61850_L2_GOOSE == 1) */
static int32_t
createGoosePayload(GoosePublisher self, LinkedList dataSetValues, uint8_t* buffer, size_t maxPayloadSize)
@ -460,7 +469,8 @@ createGoosePayload(GoosePublisher self, LinkedList dataSetValues, uint8_t* buffe
{
MmsValue* dataSetEntry = (MmsValue*) element->data;
if (dataSetEntry) {
if (dataSetEntry)
{
bufPos = MmsValue_encodeMmsData(dataSetEntry, buffer, bufPos, true);
}
else {
@ -490,7 +500,9 @@ GoosePublisher_publish(GoosePublisher self, LinkedList dataSet)
if (self->sqNum == 0)
self->sqNum = 1;
if (self->ethernetSocket) {
#if (CONFIG_IEC61850_L2_GOOSE == 1)
if (self->ethernetSocket)
{
int lengthIndex = self->lengthField;
size_t gooseLength = self->payloadLength + 8;
@ -503,9 +515,11 @@ GoosePublisher_publish(GoosePublisher self, LinkedList dataSet)
if (DEBUG_GOOSE_PUBLISHER)
printf("GOOSE_PUBLISHER: send GOOSE message\n");
}
#if (CONFIG_IEC61850_R_GOOSE == 1)
else if (self->remoteSession) {
#endif /* (CONFIG_IEC61850_L2_GOOSE == 1) */
#if (CONFIG_IEC61850_R_GOOSE == 1)
if (self->remoteSession)
{
RSession_sendMessage(self->remoteSession, RSESSION_SPDU_ID_GOOSE, self->simulation, self->appId, buffer, self->payloadLength);
if (DEBUG_GOOSE_PUBLISHER)

@ -73,7 +73,7 @@ GooseReceiver_createEx(uint8_t* buffer)
{
GooseReceiver self = (GooseReceiver) GLOBAL_MALLOC(sizeof(struct sGooseReceiver));
if (self != NULL)
if (self)
{
self->running = false;
self->stop = false;
@ -94,7 +94,8 @@ GooseReceiver_create()
{
GooseReceiver self = GooseReceiver_createEx(NULL);
if (self) {
if (self)
{
self->buffer = (uint8_t*) GLOBAL_MALLOC(ETH_BUFFER_LENGTH);
}
@ -107,7 +108,8 @@ GooseReceiver_createRemote(RSession session)
{
GooseReceiver self = GooseReceiver_create();
if (self) {
if (self)
{
self->session = session;
}
@ -1116,7 +1118,8 @@ parseGooseMessage(GooseReceiver self, uint8_t* buffer, int numbytes)
if (subscriberFound)
parseGoosePayload(self, buffer + bufPos, apduLength);
else {
else
{
if (DEBUG_GOOSE_SUBSCRIBER)
printf("GOOSE_SUBSCRIBER: GOOSE message ignored due to unknown DST-MAC or APPID value\n");
}
@ -1128,6 +1131,7 @@ gooseReceiverLoop(void *threadParameter)
{
GooseReceiver self = (GooseReceiver) threadParameter;
#if (CONFIG_IEC61850_L2_GOOSE == 1)
if (self->ethSocket)
{
EthernetHandleSet handleSet = EthernetHandleSet_new();
@ -1159,8 +1163,10 @@ gooseReceiverLoop(void *threadParameter)
EthernetHandleSet_destroy(handleSet);
}
#if (CONFIG_IEC61850_R_GOOSE == 0)
else if (self->session)
#endif /* (CONFIG_IEC61850_L2_GOOSE == 1) */
#if (CONFIG_IEC61850_R_GOOSE == 1)
if (self->session)
{
HandleSet handleSet = Handleset_new();
@ -1207,30 +1213,39 @@ GooseReceiver_start(GooseReceiver self)
{
self->thread = Thread_create((ThreadExecutionFunction) gooseReceiverLoop, (void*) self, false);
if (self->thread != NULL) {
if (self->ethSocket) {
if (self->thread)
{
#if (CONFIG_IEC61850_L2_GOOSE == 1)
if (self->ethSocket)
{
if (DEBUG_GOOSE_SUBSCRIBER)
printf("GOOSE_SUBSCRIBER: GOOSE receiver started for interface %s\n", self->interfaceId);
Thread_start(self->thread);
return;
}
#endif /* (CONFIG_IEC61850_L2_GOOSE == 1) */
#if (CONFIG_IEC61850_R_GOOSE == 1)
else if (self->session) {
if (self->session)
{
if (DEBUG_GOOSE_SUBSCRIBER)
printf("GOOSE_SUBSCRIBER: R-GOOSE receiver started\n");
Thread_start(self->thread);
return;
}
#endif /* (CONFIG_IEC61850_R_GOOSE == 1) */
else {
if (DEBUG_GOOSE_SUBSCRIBER)
printf("GOOSE_SUBSCRIBER: ERROR - No link/transport layer specified -> cannot start!\n");
Thread_destroy(self->thread);
self->thread = NULL;
}
}
else {
if (DEBUG_GOOSE_SUBSCRIBER)
printf("GOOSE_SUBSCRIBER: Starting GOOSE receiver failed for interface %s\n", self->interfaceId);
@ -1287,7 +1302,8 @@ EthernetSocket
GooseReceiver_startThreadless(GooseReceiver self)
{
#if (CONFIG_IEC61850_R_GOOSE == 1)
if (self->session) {
if (self->session)
{
if (RSession_start(self->session) == R_SESSION_ERROR_OK)
{
self->running = true;
@ -1304,6 +1320,7 @@ GooseReceiver_startThreadless(GooseReceiver self)
else {
#endif /* (CONFIG_IEC61850_R_GOOSE == 1) */
#if (CONFIG_IEC61850_L2_GOOSE == 1)
if (self->interfaceId == NULL)
self->ethSocket = Ethernet_createSocket(CONFIG_ETHERNET_INTERFACE_ID, NULL);
else
@ -1340,6 +1357,7 @@ GooseReceiver_startThreadless(GooseReceiver self)
else {
self->running = false;
}
#endif /* (CONFIG_IEC61850_L2_GOOSE == 1) */
#if (CONFIG_IEC61850_R_GOOSE == 1)
}
@ -1351,20 +1369,24 @@ GooseReceiver_startThreadless(GooseReceiver self)
void
GooseReceiver_stopThreadless(GooseReceiver self)
{
#if (CONFIG_IEC61850_L2_GOOSE == 1)
if (self->ethSocket)
Ethernet_destroySocket(self->ethSocket);
#endif /* (CONFIG_IEC61850_L2_GOOSE == 1) */
self->running = false;
}
#if (CONFIG_IEC61850_R_GOOSE == 1)
static void
handleSessionPayloadElement(void* parameter, uint16_t appId, uint8_t* payloadData, int payloadSize)
{
(void)appId;
GooseReceiver self = (GooseReceiver) parameter;
parseGoosePayload(self, payloadData, payloadSize);
}
#endif /* (CONFIG_IEC61850_R_GOOSE == 1) */
/* call after reception of ethernet frame */
bool
@ -1381,6 +1403,8 @@ GooseReceiver_tick(GooseReceiver self)
else
{
#endif /* (CONFIG_IEC61850_R_GOOSE == 1) */
#if (CONFIG_IEC61850_L2_GOOSE == 1)
int packetSize = Ethernet_receivePacket(self->ethSocket, self->buffer, ETH_BUFFER_LENGTH);
if (packetSize > 0)
@ -1390,6 +1414,7 @@ GooseReceiver_tick(GooseReceiver self)
}
else
return false;
#endif /* (CONFIG_IEC61850_L2_GOOSE == 1) */
#if (CONFIG_IEC61850_R_GOOSE == 1)
}

@ -3380,8 +3380,8 @@ mmsListObjectsAccessHandler(void* parameter, MmsGetNameListType listType, MmsDom
if (listType == MMS_GETNAMELIST_DATASETS)
{
if (self->listObjectsAccessHandler) {
if (self->listObjectsAccessHandler)
{
char str[65];
char* ldName = MmsDomain_getName(domain);
@ -3414,7 +3414,8 @@ mmsListObjectsAccessHandler(void* parameter, MmsGetNameListType listType, MmsDom
}
else if (listType == MMS_GETNAMELIST_JOURNALS)
{
if (self->listObjectsAccessHandler) {
if (self->listObjectsAccessHandler)
{
char str[65];
char* ldName = MmsDomain_getName(domain);
@ -3457,7 +3458,8 @@ mmsListObjectsAccessHandler(void* parameter, MmsGetNameListType listType, MmsDom
{
FunctionalConstraint fc = IEC61850_FC_NONE;
if (separator) {
if (separator)
{
fc = FunctionalConstraint_fromString(separator + 1);
if (fc == IEC61850_FC_BR || fc == IEC61850_FC_US ||
@ -3473,17 +3475,20 @@ mmsListObjectsAccessHandler(void* parameter, MmsGetNameListType listType, MmsDom
LogicalNode* ln = LogicalDevice_getLogicalNode(ld, str);
if (ln) {
if (ln)
{
char* doStart = strchr(separator + 1, '$');
if (doStart != NULL) {
if (doStart != NULL)
{
char* doEnd = strchr(doStart + 1, '$');
if (doEnd == NULL) {
if (doEnd == NULL)
{
StringUtils_copyStringToBuffer(doStart + 1, str);
}
else {
else
{
doEnd--;
StringUtils_createStringFromBufferInBufferMax(str, (uint8_t*) (doStart + 1), doEnd - doStart, sizeof(str));
@ -3521,7 +3526,8 @@ mmsListObjectsAccessHandler(void* parameter, MmsGetNameListType listType, MmsDom
break;
}
if (self->listObjectsAccessHandler) {
if (self->listObjectsAccessHandler)
{
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection);
allowAccess = self->listObjectsAccessHandler(self->listObjectsAccessHandlerParameter, clientConnection, acsiClass, ld, ln, str, subObjectName, fc);
@ -3543,14 +3549,16 @@ mmsListObjectsAccessHandler(void* parameter, MmsGetNameListType listType, MmsDom
{
char* doStart = strchr(separator + 1, '$');
if (doStart != NULL) {
if (doStart != NULL)
{
char* doEnd = strchr(doStart + 1, '$');
if (doEnd == NULL) {
if (doEnd == NULL)
{
StringUtils_copyStringToBuffer(doStart + 1, str);
}
else {
else
{
doEnd--;
StringUtils_createStringFromBufferInBufferMax(str, (uint8_t*) (doStart + 1), doEnd - doStart, sizeof(str));
@ -3558,8 +3566,10 @@ mmsListObjectsAccessHandler(void* parameter, MmsGetNameListType listType, MmsDom
subObjectName = StringUtils_copyStringToBufferAndReplace(doEnd + 2, subObjectBuf, '$', '.');
}
if (fc == IEC61850_FC_SP) {
if (!strcmp(str, "SGCB")) {
if (fc == IEC61850_FC_SP)
{
if (!strcmp(str, "SGCB"))
{
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer,
connection);
@ -3572,41 +3582,47 @@ mmsListObjectsAccessHandler(void* parameter, MmsGetNameListType listType, MmsDom
ModelNode* dobj = ModelNode_getChild((ModelNode*) ln, str);
if (dobj != NULL) {
if (dobj->modelType == DataObjectModelType) {
if (dobj != NULL)
{
if (dobj->modelType == DataObjectModelType)
{
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer,
connection);
if (self->listObjectsAccessHandler) {
if (self->listObjectsAccessHandler)
{
allowAccess = self->listObjectsAccessHandler(self->listObjectsAccessHandlerParameter, clientConnection, ACSI_CLASS_DATA_OBJECT, ld, ln, dobj->name, subObjectName, fc);
}
}
}
}
else {
else
{
/* no data object but with FC specified */
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer,
connection);
if (self->listObjectsAccessHandler) {
if (self->listObjectsAccessHandler)
{
allowAccess = self->listObjectsAccessHandler(self->listObjectsAccessHandlerParameter, clientConnection, ACSI_CLASS_DATA_OBJECT, ld, ln, NULL, NULL, fc);
}
}
}
}
}
else {
else
{
LogicalNode* ln = LogicalDevice_getLogicalNode(ld, variableId);
if (ln) {
if (ln)
{
/* only LN, no FC specified */
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection);
if (self->listObjectsAccessHandler) {
if (self->listObjectsAccessHandler)
{
allowAccess = self->listObjectsAccessHandler(self->listObjectsAccessHandlerParameter, clientConnection, ACSI_CLASS_DATA_OBJECT, ld, ln, NULL, NULL, fc);
}
}
@ -3778,21 +3794,24 @@ checkDataSetAccess(MmsMapping* self, MmsServerConnection connection, MmsVariable
{
bool accessGranted = true;
if (self->dataSetAccessHandler) {
if (self->dataSetAccessHandler)
{
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection);
char dataSetRef[130];
dataSetRef[0] = 0;
if (listType == MMS_ASSOCIATION_SPECIFIC) {
if (listType == MMS_ASSOCIATION_SPECIFIC)
{
dataSetRef[0] = '@';
StringUtils_copyStringToBuffer(dataSetRef + 1, listName);
}
else if (listType == MMS_VMD_SPECIFIC) {
else if (listType == MMS_VMD_SPECIFIC)
{
StringUtils_copyStringToBuffer(dataSetRef, listName);
}
else if (listType == MMS_DOMAIN_SPECIFIC) {
else if (listType == MMS_DOMAIN_SPECIFIC)
{
StringUtils_appendString(dataSetRef, 129, domain->domainName);
StringUtils_appendString(dataSetRef, 129, "/");
StringUtils_appendString(dataSetRef, 129, listName);
@ -3841,11 +3860,12 @@ variableListAccessHandler (void* parameter, MmsVariableListAccessType accessType
printf("specific (name=%s)\n", listName);
#endif /* (DEBUG_IED_SERVER == 1) */
if (accessType == MMS_VARLIST_CREATE) {
if (checkDataSetAccess(self, connection, listType, domain, listName, DATASET_CREATE)) {
if (listType == MMS_DOMAIN_SPECIFIC) {
if (accessType == MMS_VARLIST_CREATE)
{
if (checkDataSetAccess(self, connection, listType, domain, listName, DATASET_CREATE))
{
if (listType == MMS_DOMAIN_SPECIFIC)
{
/* check if LN exists - otherwise reject request (to fulfill test case sDsN1c) */
allow = MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT;
@ -3854,13 +3874,14 @@ variableListAccessHandler (void* parameter, MmsVariableListAccessType accessType
LogicalDevice* ld = IedModel_getDevice(model, domain->domainName);
if (ld != NULL) {
if (ld != NULL)
{
char lnName[129];
char* separator = strchr(listName, '$');
if (separator != NULL) {
if (separator != NULL)
{
int lnNameLen = separator - listName;
memcpy(lnName, listName, lnNameLen);
@ -3869,7 +3890,6 @@ variableListAccessHandler (void* parameter, MmsVariableListAccessType accessType
if (LogicalDevice_getLogicalNode(ld, lnName) != NULL)
allow = MMS_ERROR_NONE;
}
}
}
}
@ -3877,46 +3897,58 @@ variableListAccessHandler (void* parameter, MmsVariableListAccessType accessType
allow = MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED;
}
}
else if (accessType == MMS_VARLIST_DELETE) {
if (checkDataSetAccess(self, connection, listType, domain, listName, DATASET_DELETE)) {
else if (accessType == MMS_VARLIST_DELETE)
{
if (checkDataSetAccess(self, connection, listType, domain, listName, DATASET_DELETE))
{
/* Check if data set is referenced in a report */
LinkedList rcElement = self->reportControls;
while ((rcElement = LinkedList_getNext(rcElement)) != NULL) {
while ((rcElement = LinkedList_getNext(rcElement)) != NULL)
{
ReportControl* rc = (ReportControl*) rcElement->data;
if (rc->isDynamicDataSet) {
if (rc->dataSet != NULL) {
if (listType == MMS_DOMAIN_SPECIFIC) {
if (rc->dataSet->logicalDeviceName != NULL) {
if (strcmp(rc->dataSet->name, listName) == 0) {
if (strcmp(rc->dataSet->logicalDeviceName, MmsDomain_getName(domain) + strlen(self->model->name)) == 0) {
if (rc->isDynamicDataSet)
{
if (rc->dataSet != NULL)
{
if (listType == MMS_DOMAIN_SPECIFIC)
{
if (rc->dataSet->logicalDeviceName != NULL)
{
if (strcmp(rc->dataSet->name, listName) == 0)
{
if (strcmp(rc->dataSet->logicalDeviceName, MmsDomain_getName(domain) + strlen(self->model->name)) == 0)
{
allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT;
break;
}
}
}
}
else if (listType == MMS_VMD_SPECIFIC) {
if (rc->dataSet->logicalDeviceName == NULL) {
if (strcmp(rc->dataSet->name, listName) == 0) {
else if (listType == MMS_VMD_SPECIFIC)
{
if (rc->dataSet->logicalDeviceName == NULL)
{
if (strcmp(rc->dataSet->name, listName) == 0)
{
allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT;
break;
}
}
}
else if (listType == MMS_ASSOCIATION_SPECIFIC) {
if (rc->dataSet->logicalDeviceName == NULL) {
if (strcmp(rc->dataSet->name, listName) == 0) {
else if (listType == MMS_ASSOCIATION_SPECIFIC)
{
if (rc->dataSet->logicalDeviceName == NULL)
{
if (strcmp(rc->dataSet->name, listName) == 0)
{
allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT;
break;
}
}
}
}
}
}
@ -3925,31 +3957,39 @@ variableListAccessHandler (void* parameter, MmsVariableListAccessType accessType
/* check if data set is referenced in a log control block*/
LinkedList logElement = self->logControls;
while ((logElement = LinkedList_getNext(logElement)) != NULL) {
while ((logElement = LinkedList_getNext(logElement)) != NULL)
{
LogControl* lc = (LogControl*) logElement->data;
if (lc->isDynamicDataSet) {
if (lc->dataSet != NULL) {
if (listType == MMS_DOMAIN_SPECIFIC) {
if (lc->dataSet->logicalDeviceName != NULL) {
if (strcmp(lc->dataSet->name, listName) == 0) {
if (strcmp(lc->dataSet->logicalDeviceName, MmsDomain_getName(domain) + strlen(self->model->name)) == 0) {
if (lc->isDynamicDataSet)
{
if (lc->dataSet != NULL)
{
if (listType == MMS_DOMAIN_SPECIFIC)
{
if (lc->dataSet->logicalDeviceName != NULL)
{
if (strcmp(lc->dataSet->name, listName) == 0)
{
if (strcmp(lc->dataSet->logicalDeviceName, MmsDomain_getName(domain) + strlen(self->model->name)) == 0)
{
allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT;
break;
}
}
}
}
else if (listType == MMS_VMD_SPECIFIC) {
if (lc->dataSet->logicalDeviceName == NULL) {
if (strcmp(lc->dataSet->name, listName) == 0) {
else if (listType == MMS_VMD_SPECIFIC)
{
if (lc->dataSet->logicalDeviceName == NULL)
{
if (strcmp(lc->dataSet->name, listName) == 0)
{
allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT;
break;
}
}
}
}
}
}
@ -3990,7 +4030,8 @@ mmsReadJournalHandler(void* parameter, MmsDomain* domain, const char* logName, M
MmsMapping* self = (MmsMapping*)parameter;
if (self->controlBlockAccessHandler) {
if (self->controlBlockAccessHandler)
{
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection);
LogicalDevice* ld = IedModel_getDevice(self->model, domain->domainName);
@ -4005,7 +4046,8 @@ mmsReadJournalHandler(void* parameter, MmsDomain* domain, const char* logName, M
char* separator = strchr(str, '$');
if (separator) {
if (separator)
{
name = separator + 1;
*separator = 0;
@ -4049,15 +4091,18 @@ isMemberValueRecursive(MmsValue* container, MmsValue* value)
if (container == value)
isMemberValue = true;
else {
else
{
if ((MmsValue_getType(container) == MMS_STRUCTURE) ||
(MmsValue_getType(container) == MMS_ARRAY))
{
int compCount = MmsValue_getArraySize(container);
int i;
for (i = 0; i < compCount; i++) {
if (isMemberValueRecursive(MmsValue_getElement(container, i), value)) {
for (i = 0; i < compCount; i++)
{
if (isMemberValueRecursive(MmsValue_getElement(container, i), value))
{
isMemberValue = true;
break;
}
@ -4077,12 +4122,15 @@ DataSet_isMemberValue(DataSet* dataSet, MmsValue* value, int* index)
DataSetEntry* dataSetEntry = dataSet->fcdas;
while (dataSetEntry != NULL) {
while (dataSetEntry != NULL)
{
MmsValue* dataSetValue = dataSetEntry->value;
if (dataSetValue != NULL) { /* prevent invalid data set members */
if (isMemberValueRecursive(dataSetValue, value)) {
if (dataSetValue != NULL)
{
/* prevent invalid data set members */
if (isMemberValueRecursive(dataSetValue, value))
{
if (index != NULL)
*index = i;
@ -4108,12 +4156,15 @@ DataSet_isMemberValueWithRef(DataSet* dataSet, MmsValue* value, char* dataRef, c
DataSetEntry* dataSetEntry = dataSet->fcdas;
while (dataSetEntry != NULL) {
while (dataSetEntry != NULL)
{
MmsValue *dataSetValue = dataSetEntry->value;
if (dataSetValue != NULL) { /* prevent invalid data set members */
if (isMemberValueRecursive(dataSetValue, value)) {
if (dataSetValue != NULL)
{
/* prevent invalid data set members */
if (isMemberValueRecursive(dataSetValue, value))
{
if (dataRef != NULL)
sprintf(dataRef, "%s%s/%s", iedName, dataSetEntry->logicalDeviceName, dataSetEntry->variableName);
@ -4137,11 +4188,12 @@ MmsMapping_triggerLogging(MmsMapping* self, MmsValue* value, LogInclusionFlag fl
{
LinkedList element = self->logControls;
while ((element = LinkedList_getNext(element)) != NULL) {
while ((element = LinkedList_getNext(element)) != NULL)
{
LogControl* lc = (LogControl*) element->data;
if ((lc->enabled) && (lc->dataSet != NULL)) {
if ((lc->enabled) && (lc->dataSet != NULL))
{
uint8_t reasonCode;
switch (flag) {
@ -4179,15 +4231,16 @@ MmsMapping_triggerLogging(MmsMapping* self, MmsValue* value, LogInclusionFlag fl
int dsEntryIdx = 0;
if (DataSet_isMemberValueWithRef(lc->dataSet, value, dataRef, self->model->name, &dsEntryIdx)) {
if (lc->logInstance != NULL) {
if (lc->dataSet) {
if (DataSet_isMemberValueWithRef(lc->dataSet, value, dataRef, self->model->name, &dsEntryIdx))
{
if (lc->logInstance != NULL)
{
if (lc->dataSet)
{
DataSetEntry* dsEntry = lc->dataSet->fcdas;
while (dsEntry && (dsEntryIdx > 0)) {
while (dsEntry && (dsEntryIdx > 0))
{
dsEntry = dsEntry->sibling;
if (dsEntry == NULL)
@ -4196,21 +4249,20 @@ MmsMapping_triggerLogging(MmsMapping* self, MmsValue* value, LogInclusionFlag fl
dsEntryIdx--;
}
if (dsEntry) {
if (dsEntry)
{
MmsValue* dsValue = dsEntry->value;
LogInstance_logSingleData(lc->logInstance, dataRef, dsValue, reasonCode);
}
}
}
else {
else
{
if (DEBUG_IED_SERVER)
printf("IED_SERVER: No log instance available!\n");
}
}
}
}
}
@ -4278,20 +4330,24 @@ MmsMapping_triggerGooseObservers(MmsMapping* self, MmsValue* value)
{
LinkedList element = self->gseControls;
while ((element = LinkedList_getNext(element)) != NULL) {
while ((element = LinkedList_getNext(element)) != NULL)
{
MmsGooseControlBlock gcb = (MmsGooseControlBlock) element->data;
if (MmsGooseControlBlock_isEnabled(gcb)) {
if (MmsGooseControlBlock_isEnabled(gcb))
{
DataSet* dataSet = MmsGooseControlBlock_getDataSet(gcb);
if (DataSet_isMemberValue(dataSet, value, NULL)) {
if (DataSet_isMemberValue(dataSet, value, NULL))
{
MmsGooseControlBlock_setStateChangePending(gcb);
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_wait(self->isModelLockedMutex);
#endif
if (self->isModelLocked == false) {
if (self->isModelLocked == false)
{
MmsGooseControlBlock_publishNewState(gcb);
}
@ -4308,10 +4364,12 @@ MmsMapping_enableGoosePublishing(MmsMapping* self)
{
LinkedList element = LinkedList_getNext(self->gseControls);
while (element) {
while (element)
{
MmsGooseControlBlock gcb = (MmsGooseControlBlock) LinkedList_getData(element);
if (MmsGooseControlBlock_enable(gcb, self) == false) {
if (MmsGooseControlBlock_enable(gcb, self) == false)
{
if (DEBUG_IED_SERVER)
printf("IED_SERVER: failed to enable GoCB %s\n", MmsGooseControlBlock_getName(gcb));
}
@ -4325,14 +4383,18 @@ MmsMapping_useGooseVlanTag(MmsMapping* self, LogicalNode* ln, const char* gcbNam
{
LinkedList element = self->gseControls;
while ((element = LinkedList_getNext(element)) != NULL) {
while ((element = LinkedList_getNext(element)) != NULL)
{
MmsGooseControlBlock gcb = (MmsGooseControlBlock) element->data;
if (ln == NULL) {
if (ln == NULL)
{
MmsGooseControlBlock_useGooseVlanTag(gcb, useVlanTag);
}
else {
if ((MmsGooseControlBlock_getLogicalNode(gcb) == ln) && !strcmp(MmsGooseControlBlock_getName(gcb), gcbName)) {
else
{
if ((MmsGooseControlBlock_getLogicalNode(gcb) == ln) && !strcmp(MmsGooseControlBlock_getName(gcb), gcbName))
{
MmsGooseControlBlock_useGooseVlanTag(gcb, useVlanTag);
}
}
@ -4344,14 +4406,18 @@ MmsMapping_setGooseInterfaceId(MmsMapping* self, LogicalNode* ln, const char* g
{
LinkedList element = self->gseControls;
while ((element = LinkedList_getNext(element)) != NULL) {
while ((element = LinkedList_getNext(element)) != NULL)
{
MmsGooseControlBlock gcb = (MmsGooseControlBlock) element->data;
if (ln == NULL) {
if (ln == NULL)
{
MmsGooseControlBlock_setGooseInterfaceId(gcb, interfaceId);
}
else {
if ((MmsGooseControlBlock_getLogicalNode(gcb) == ln) && !strcmp(MmsGooseControlBlock_getName(gcb), gcbName)) {
else
{
if ((MmsGooseControlBlock_getLogicalNode(gcb) == ln) && !strcmp(MmsGooseControlBlock_getName(gcb), gcbName))
{
MmsGooseControlBlock_setGooseInterfaceId(gcb, interfaceId);
}
}
@ -4363,7 +4429,8 @@ MmsMapping_disableGoosePublishing(MmsMapping* self)
{
LinkedList element = self->gseControls;
while ((element = LinkedList_getNext(element)) != NULL) {
while ((element = LinkedList_getNext(element)) != NULL)
{
MmsGooseControlBlock gcb = (MmsGooseControlBlock) element->data;
MmsGooseControlBlock_disable(gcb, self);
@ -4393,10 +4460,12 @@ GOOSE_processGooseEvents(MmsMapping* self, uint64_t currentTimeInMs)
{
LinkedList element = LinkedList_getNext(self->gseControls);
while (element != NULL) {
while (element != NULL)
{
MmsGooseControlBlock mmsGCB = (MmsGooseControlBlock) element->data;
if (MmsGooseControlBlock_isEnabled(mmsGCB)) {
if (MmsGooseControlBlock_isEnabled(mmsGCB))
{
MmsGooseControlBlock_checkAndPublish(mmsGCB, currentTimeInMs, self);
}
@ -4449,8 +4518,8 @@ eventWorkerThread(MmsMapping* self)
{
bool running = true;
while (running) {
while (running)
{
processPeriodicTasks(self);
Thread_sleep(1); /* hand-over control to other threads */
@ -4477,11 +4546,12 @@ MmsMapping_startEventWorkerThread(MmsMapping* self)
void
MmsMapping_stopEventWorkerThread(MmsMapping* self)
{
if (self->reportThreadRunning) {
if (self->reportThreadRunning)
{
self->reportThreadRunning = false;
if (self->reportWorkerThread) {
if (self->reportWorkerThread)
{
Thread_destroy(self->reportWorkerThread);
self->reportWorkerThread = NULL;
}
@ -4494,15 +4564,18 @@ MmsMapping_createDataSetByNamedVariableList(MmsMapping* self, MmsNamedVariableLi
{
DataSet* dataSet = (DataSet*) GLOBAL_CALLOC(1, sizeof(DataSet));
if (dataSet) {
if (variableList->domain != NULL) {
if (dataSet)
{
if (variableList->domain != NULL)
{
LogicalDevice* ld = IedModel_getDevice(self->model, MmsDomain_getName(variableList->domain));
if (ld) {
if (ld)
{
dataSet->logicalDeviceName = ld->name;
}
else {
else
{
if (DEBUG_IED_SERVER)
printf("IED_SERVER: LD lookup error!");
}
@ -4517,17 +4590,18 @@ MmsMapping_createDataSetByNamedVariableList(MmsMapping* self, MmsNamedVariableLi
DataSetEntry* lastDataSetEntry = NULL;
while (element != NULL) {
while (element != NULL)
{
MmsAccessSpecifier* listEntry = (MmsAccessSpecifier*) element->data;
LogicalDevice* entryLd = IedModel_getDevice(self->model, MmsDomain_getName(listEntry->domain));
if (entryLd) {
if (entryLd)
{
DataSetEntry* dataSetEntry = (DataSetEntry*) GLOBAL_MALLOC(sizeof(DataSetEntry));
if (dataSetEntry) {
if (dataSetEntry)
{
/* use variable name part of domain name as logicalDeviceName */
dataSetEntry->logicalDeviceName = entryLd->name;
dataSetEntry->variableName = listEntry->variableName;
@ -4545,42 +4619,51 @@ MmsMapping_createDataSetByNamedVariableList(MmsMapping* self, MmsNamedVariableLi
MmsValue* dataSetEntryValue = MmsServer_getValueFromCacheEx(self->mmsServer, listEntry->domain, listEntry->variableName, &dataSetEntryVarSpec);
if (dataSetEntryValue) {
if (dataSetEntry->index != -1) {
if (dataSetEntryVarSpec->type == MMS_ARRAY) {
if (dataSetEntryValue)
{
if (dataSetEntry->index != -1)
{
if (dataSetEntryVarSpec->type == MMS_ARRAY)
{
MmsValue* elementValue = MmsValue_getElement(dataSetEntryValue, dataSetEntry->index);
if (elementValue) {
if (dataSetEntry->componentName) {
if (elementValue)
{
if (dataSetEntry->componentName)
{
MmsVariableSpecification* elementType = dataSetEntryVarSpec->typeSpec.array.elementTypeSpec;
MmsValue* subElementValue = MmsVariableSpecification_getChildValue(elementType, elementValue, dataSetEntry->componentName);
if (subElementValue) {
if (subElementValue)
{
dataSetEntry->value = subElementValue;
}
else {
else
{
if (DEBUG_IED_SERVER)
printf("IED_SERVER: ERROR - component %s of array element not found\n", dataSetEntry->componentName);
}
}
else {
else
{
dataSetEntry->value = elementValue;
}
}
else {
else
{
if (DEBUG_IED_SERVER)
printf("IED_SERVER: ERROR - array element %i not found\n", dataSetEntry->index);
}
}
else {
else
{
if (DEBUG_IED_SERVER)
printf("IED_SERVER: ERROR - variable %s/%s is not an array\n", dataSetEntry->logicalDeviceName, dataSetEntry->variableName);
}
}
else {
else
{
dataSetEntry->value = dataSetEntryValue;
}
}
@ -4588,7 +4671,8 @@ MmsMapping_createDataSetByNamedVariableList(MmsMapping* self, MmsNamedVariableLi
lastDataSetEntry = dataSetEntry;
}
}
else {
else
{
if (DEBUG_IED_SERVER)
printf("IED_SERVER: LD lookup error!\n");
}
@ -4644,7 +4728,8 @@ MmsMapping_freeDynamicallyCreatedDataSet(DataSet* dataSet)
{
DataSetEntry* dataSetEntry = dataSet->fcdas;
while (dataSetEntry != NULL) {
while (dataSetEntry)
{
DataSetEntry* nextEntry = dataSetEntry->sibling;
GLOBAL_FREEMEM (dataSetEntry);

@ -1,7 +1,7 @@
/*
* ber_encoder.c
*
* Copyright 2013-2022 Michael Zillgith
* Copyright 2013-2024 Michael Zillgith
*
* This file is part of libIEC61850.
*

@ -1018,6 +1018,20 @@ MmsValue_printToBuffer(const MmsValue* self, char* buffer, int bufferSize);
LIB61850_API MmsValue*
MmsValue_decodeMmsData(uint8_t* buffer, int bufPos, int bufferLength, int* endBufPos);
/**
* \brief create a new MmsValue instance from a BER encoded MMS Data element (deserialize) with a defined maximum recursion depth
*
* \param buffer the buffer to read from
* \param bufPos the start position of the mms value data in the buffer
* \param bufferLength the length of the buffer
* \param endBufPos the position in the buffer after the read MMS data element (NULL if not required)
* \param maxDepth the maximum recursion depth
*
* \return the MmsValue instance created from the buffer
*/
LIB61850_API MmsValue*
MmsValue_decodeMmsDataMaxRecursion(uint8_t* buffer, int bufPos, int bufferLength, int* endBufPos, int maxDepth);
/**
* \brief Serialize the MmsValue instance as BER encoded MMS Data element
*

@ -1,7 +1,7 @@
/*
* ber_encoder.h
*
* Copyright 2013-2018 Michael Zillgith
* Copyright 2013-2024 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -75,6 +75,9 @@ BerEncoder_encodeFloat(uint8_t* floatValue, uint8_t formatWidth, uint8_t exponen
LIB61850_INTERNAL int
BerEncoder_UInt32determineEncodedSize(uint32_t value);
LIB61850_INTERNAL int
BerEncoder_Int32determineEncodedSize(int32_t value);
LIB61850_INTERNAL int
BerEncoder_determineLengthSize(uint32_t length);

@ -67,8 +67,8 @@ writeOptions(CotpConnection* self)
uint8_t* buffer = self->writeBuffer->buffer;
int bufPos = self->writeBuffer->size;
if (self->options.tpduSize != 0) {
if (self->options.tpduSize != 0)
{
if (DEBUG_COTP)
printf("COTP: send TPDU size: %i\n", CotpConnection_getTpduSize(self));
@ -77,7 +77,8 @@ writeOptions(CotpConnection* self)
buffer[bufPos++] = self->options.tpduSize;
}
if (self->options.tSelDst.size != 0) {
if (self->options.tSelDst.size != 0)
{
buffer[bufPos++] = 0xc2;
buffer[bufPos++] = (uint8_t) self->options.tSelDst.size;
@ -86,7 +87,8 @@ writeOptions(CotpConnection* self)
buffer[bufPos++] = (uint8_t) self->options.tSelDst.value[i];
}
if (self->options.tSelSrc.size != 0) {
if (self->options.tSelSrc.size != 0)
{
buffer[bufPos++] = 0xc1;
buffer[bufPos++] = (uint8_t) self->options.tSelSrc.size;
@ -177,28 +179,32 @@ writeToSocket(CotpConnection* self, uint8_t* buf, int size)
static bool
flushBuffer(CotpConnection* self)
{
if (self->socketExtensionBufferFill > 0) {
if (self->socketExtensionBufferFill > 0)
{
int sentBytes = writeToSocket(self, self->socketExtensionBuffer, self->socketExtensionBufferFill);
if (sentBytes > 0) {
if (sentBytes != self->socketExtensionBufferFill) {
if (sentBytes > 0)
{
if (sentBytes != self->socketExtensionBufferFill)
{
int target = 0;
int i;
uint8_t* buf = self->socketExtensionBuffer;
for (i = sentBytes; i < self->socketExtensionBufferFill; i++) {
for (i = sentBytes; i < self->socketExtensionBufferFill; i++)
{
buf[target++] = buf[i];
}
self->socketExtensionBufferFill = self->socketExtensionBufferFill - sentBytes;
}
else {
else
{
self->socketExtensionBufferFill = 0;
}
}
else if (sentBytes == -1) {
else if (sentBytes == -1)
{
return false;
}
}
@ -214,35 +220,40 @@ sendBuffer(CotpConnection* self)
bool retVal = false;
if (flushBuffer(self) == false) {
if (flushBuffer(self) == false)
{
goto exit_function;
}
int sentBytes = 0;
if (self->socketExtensionBufferFill == 0) {
if (self->socketExtensionBufferFill == 0)
{
sentBytes = writeToSocket(self, buffer, remainingSize);
}
if (sentBytes == -1)
goto exit_function;
if (sentBytes != remainingSize) {
if (sentBytes != remainingSize)
{
/* write additional data to extension buffer */
if (self->socketExtensionBuffer) {
if (self->socketExtensionBuffer)
{
uint8_t* extBuf = self->socketExtensionBuffer;
int extCurrentPos = self->socketExtensionBufferFill;
int bytesNotSent = remainingSize - sentBytes;
int i;
for (i = 0; i < bytesNotSent; i++) {
for (i = 0; i < bytesNotSent; i++)
{
extBuf[i + extCurrentPos] = buffer[sentBytes + i];
}
self->socketExtensionBufferFill = extCurrentPos + bytesNotSent;
}
else {
else
{
goto exit_function;
}
}
@ -264,7 +275,9 @@ CotpConnection_sendDataMessage(CotpConnection* self, BufferChain payload)
int fragmentPayloadSize = CotpConnection_getTpduSize(self) - COTP_DATA_HEADER_SIZE;
if (payload->length > fragmentPayloadSize) { /* Check if segmentation is required? */
if (payload->length > fragmentPayloadSize)
{
/* Check if segmentation is required? */
fragments = payload->length / fragmentPayloadSize;
if ((payload->length % fragmentPayloadSize) != 0)
@ -275,15 +288,18 @@ CotpConnection_sendDataMessage(CotpConnection* self, BufferChain payload)
int totalSize = (fragments * (COTP_DATA_HEADER_SIZE + 4)) + payload->length;
/* try to flush extension buffer */
if (flushBuffer(self) == false) {
if (flushBuffer(self) == false)
{
return COTP_ERROR;
}
/* check if totalSize will fit in extension buffer */
if (self->socketExtensionBuffer) {
if (self->socketExtensionBuffer)
{
int freeExtBufSize = self->socketExtensionBufferSize - self->socketExtensionBufferFill;
if (freeExtBufSize < totalSize) {
if (freeExtBufSize < totalSize)
{
return COTP_ERROR;
}
}
@ -300,12 +316,15 @@ CotpConnection_sendDataMessage(CotpConnection* self, BufferChain payload)
uint8_t* buffer = self->writeBuffer->buffer;
while (fragments > 0) {
if (fragments > 1) {
while (fragments > 0)
{
if (fragments > 1)
{
currentLimit = currentBufPos + fragmentPayloadSize;
lastUnit = 0;
}
else {
else
{
currentLimit = payload->length;
lastUnit = 1;
}
@ -317,9 +336,10 @@ CotpConnection_sendDataMessage(CotpConnection* self, BufferChain payload)
int bufPos = 7;
int i;
for (i = currentBufPos; i < currentLimit; i++) {
if (currentChainIndex >= currentChain->partLength) {
for (i = currentBufPos; i < currentLimit; i++)
{
if (currentChainIndex >= currentChain->partLength)
{
currentChain = currentChain->nextPart;
if (DEBUG_COTP)
printf("COTP: nextBufferPart: len:%i partLen:%i\n", currentChain->length, currentChain->partLength);
@ -338,7 +358,8 @@ CotpConnection_sendDataMessage(CotpConnection* self, BufferChain payload)
if (DEBUG_COTP)
printf("COTP: Send COTP fragment %i bufpos: %i\n", fragments, currentBufPos);
if (!sendBuffer(self)) {
if (!sendBuffer(self))
{
retValue = COTP_ERROR;
if (DEBUG_COTP)
@ -438,11 +459,13 @@ parseOptions(CotpConnection* self, uint8_t* buffer, int bufLen)
{
int bufPos = 0;
while (bufPos < bufLen) {
while (bufPos < bufLen)
{
uint8_t optionType = buffer[bufPos++];
uint8_t optionLen = buffer[bufPos++];
if (optionLen > (bufLen - bufPos)) {
if (optionLen > (bufLen - bufPos))
{
if (DEBUG_COTP)
printf("COTP: option to long optionLen:%i bufPos:%i bufLen:%i\n", optionLen, bufPos, bufLen);
goto cpo_error;
@ -453,7 +476,8 @@ parseOptions(CotpConnection* self, uint8_t* buffer, int bufLen)
switch (optionType) {
case 0xc0:
if (optionLen == 1) {
if (optionLen == 1)
{
int requestedTpduSize = (1 << buffer[bufPos++]);
CotpConnection_setTpduSize(self, requestedTpduSize);
@ -466,7 +490,8 @@ parseOptions(CotpConnection* self, uint8_t* buffer, int bufLen)
break;
case 0xc1: /* remote T-selector */
if (optionLen < 5) {
if (optionLen < 5)
{
self->options.tSelSrc.size = optionLen;
int i;
@ -478,7 +503,8 @@ parseOptions(CotpConnection* self, uint8_t* buffer, int bufLen)
break;
case 0xc2: /* local T-selector */
if (optionLen < 5) {
if (optionLen < 5)
{
self->options.tSelDst.size = optionLen;
int i;
@ -650,7 +676,8 @@ parseDataTpdu(CotpConnection* self, uint8_t* buffer, uint8_t len)
static bool
addPayloadToBuffer(CotpConnection* self, uint8_t* buffer, int payloadLength)
{
if (payloadLength < 1) {
if (payloadLength < 1)
{
if (DEBUG_COTP)
printf("COTP: missing payload\n");
@ -681,7 +708,8 @@ parseCotpMessage(CotpConnection* self)
len = buffer[0];
if (len > tpduLength) {
if (len > tpduLength)
{
if (DEBUG_COTP)
printf("COTP: parseCotpMessage: len=%d tpduLength=%d\n", len, tpduLength);
@ -702,8 +730,8 @@ parseCotpMessage(CotpConnection* self)
else
return COTP_ERROR;
case 0xf0:
if (parseDataTpdu(self, buffer + 2, len)) {
if (parseDataTpdu(self, buffer + 2, len))
{
if (addPayloadToBuffer(self, buffer + 3, tpduLength - 3) != 1)
return COTP_ERROR;
@ -743,7 +771,8 @@ readFromSocket(CotpConnection* self, uint8_t* buf, int size)
#if (CONFIG_MMS_SUPPORT_TLS == 1)
if (self->tlsSocket)
return TLSSocket_read(self->tlsSocket, buf, size);
else {
else
{
switch (Handleset_waitReady(self->handleSet, 10))
{
case -1:
@ -787,7 +816,8 @@ CotpConnection_readToTpktBuffer(CotpConnection* self)
assert (bufferSize > 4);
if (self->socketExtensionBufferFill > 0) {
if (self->socketExtensionBufferFill > 0)
{
if (flushBuffer(self) == false)
goto exit_error;
@ -797,33 +827,38 @@ CotpConnection_readToTpktBuffer(CotpConnection* self)
int readBytes;
if (bufPos < 4) {
if (bufPos < 4)
{
readBytes = readFromSocket(self, buffer + bufPos, 4 - bufPos);
if (readBytes < 0)
goto exit_closed;
if (DEBUG_COTP) {
if (DEBUG_COTP)
{
if (readBytes > 0)
printf("TPKT: read %i bytes from socket\n", readBytes);
}
bufPos += readBytes;
if (bufPos == 4) {
if ((buffer[0] == 3) && (buffer[1] == 0)) {
if (bufPos == 4)
{
if ((buffer[0] == 3) && (buffer[1] == 0))
{
self->packetSize = (buffer[2] * 0x100) + buffer[3];
if (DEBUG_COTP)
printf("TPKT: header complete (msg size = %i)\n", self->packetSize);
if (self->packetSize > bufferSize) {
if (self->packetSize > bufferSize)
{
if (DEBUG_COTP) printf("TPKT: packet too large\n");
goto exit_error;
}
}
else {
else
{
if (DEBUG_COTP) printf("TPKT: failed to decode TPKT header.\n");
goto exit_error;
}
@ -869,4 +904,3 @@ exit_waiting:
self->readBuffer->size = bufPos;
return TPKT_WAITING;
}

@ -3579,6 +3579,7 @@ MmsJournalEntry_destroy(MmsJournalEntry self)
MmsValue_delete(self->occurenceTime);
LinkedList_destroyDeep(self->journalVariables,
(LinkedListValueDeleteFunction) MmsJournalVariable_destroy);
GLOBAL_FREEMEM(self);
}
}

@ -1,7 +1,7 @@
/*
* mms_client_journals.c
*
* Copyright 2016 Michael Zillgith
* Copyright 2016-2024 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -38,15 +38,16 @@ parseJournalVariable(uint8_t* buffer, int bufPos, int maxLength, MmsJournalVaria
{
int maxBufPos = bufPos + maxLength;
while (bufPos < maxBufPos) {
while (bufPos < maxBufPos)
{
uint8_t tag = buffer[bufPos++];
int length;
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
if (bufPos < 0) {
if (bufPos < 0)
{
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: parseReadJournalResponse: invalid length field\n");
@ -56,17 +57,23 @@ parseJournalVariable(uint8_t* buffer, int bufPos, int maxLength, MmsJournalVaria
switch (tag) {
case 0x80: /* variableTag */
if (journalVariable->tag == NULL) {
if (journalVariable->tag == NULL)
{
journalVariable->tag = (char*) GLOBAL_MALLOC(length + 1);
if (journalVariable->tag)
{
memcpy(journalVariable->tag, buffer + bufPos, length);
journalVariable->tag[length] = 0;
}
}
break;
case 0xa1: /* valueSpec */
if (journalVariable->value == NULL) {
if (journalVariable->value == NULL)
{
journalVariable->value = MmsValue_decodeMmsData(buffer, bufPos, bufPos + length, NULL);
}
@ -91,30 +98,52 @@ parseJournalVariables(uint8_t* buffer, int bufPos, int maxLength, MmsJournalEntr
{
int maxBufPos = bufPos + maxLength;
while (bufPos < maxBufPos) {
while (bufPos < maxBufPos)
{
int length;
uint8_t tag = buffer[bufPos++];
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
if (bufPos < 0) {
if (bufPos < 0)
{
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: parseReadJournalResponse: invalid length field\n");
return false;
}
MmsJournalVariable journalVariable;
switch (tag) {
case 0x30: /* journalVariable */
journalVariable = (MmsJournalVariable)
MmsJournalVariable journalVariable = (MmsJournalVariable)
GLOBAL_CALLOC(1, sizeof(struct sMmsJournalVariable));
parseJournalVariable(buffer, bufPos, length, journalVariable);
if (journalVariable)
{
if (parseJournalVariable(buffer, bufPos, length, journalVariable))
{
LinkedList_add(journalEntry->journalVariables, (void*) journalVariable);
}
else
{
if (journalVariable->tag)
GLOBAL_FREEMEM(journalVariable->tag);
if (journalVariable->value)
MmsValue_delete(journalVariable->value);
GLOBAL_FREEMEM(journalVariable);
return false;
}
}
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: parseReadJournalResponse: out of memory\n");
return false;
}
break;
@ -136,13 +165,14 @@ parseData(uint8_t* buffer, int bufPos, int maxLength, MmsJournalEntry journalEnt
{
int maxBufPos = bufPos + maxLength;
while (bufPos < maxBufPos) {
while (bufPos < maxBufPos)
{
int length;
uint8_t tag = buffer[bufPos++];
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
if (bufPos < 0) {
if (bufPos < 0)
{
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: parseReadJournalResponse: invalid length field\n");
@ -151,10 +181,29 @@ parseData(uint8_t* buffer, int bufPos, int maxLength, MmsJournalEntry journalEnt
switch (tag) {
case 0xa1: /* journalVariables */
if (journalEntry->journalVariables)
{
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: parseReadJournalResponse: duplicate journalVariables\n");
return false;
}
else
{
journalEntry->journalVariables = LinkedList_create();
if (journalEntry->journalVariables == NULL)
{
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: parseReadJournalResponse: out of memory\n");
return false;
}
else
{
parseJournalVariables(buffer, bufPos, length, journalEntry);
}
}
break;
@ -163,7 +212,6 @@ parseData(uint8_t* buffer, int bufPos, int maxLength, MmsJournalEntry journalEnt
default:
break;
}
bufPos += length;
@ -177,13 +225,14 @@ parseEntryContent(uint8_t* buffer, int bufPos, int maxLength, MmsJournalEntry jo
{
int maxBufPos = bufPos + maxLength;
while (bufPos < maxBufPos) {
while (bufPos < maxBufPos)
{
int length;
uint8_t tag = buffer[bufPos++];
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
if (bufPos < 0) {
if (bufPos < 0)
{
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: parseReadJournalResponse: invalid length field\n");
@ -192,6 +241,16 @@ parseEntryContent(uint8_t* buffer, int bufPos, int maxLength, MmsJournalEntry jo
switch (tag) {
case 0x80: /* occurenceTime */
if (journalEntry->occurenceTime)
{
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: parseReadJournalResponse: duplicate occurenceTime\n");
return false;
}
else
{
if (length == 6)
journalEntry->occurenceTime = MmsValue_newBinaryTime(false);
else if (length == 4)
@ -200,6 +259,7 @@ parseEntryContent(uint8_t* buffer, int bufPos, int maxLength, MmsJournalEntry jo
break;
memcpy(journalEntry->occurenceTime->value.binaryTime.buf, buffer + bufPos, length);
}
break;
@ -230,26 +290,46 @@ parseJournalEntry(uint8_t* buffer, int bufPos, int maxLength, LinkedList journal
int maxBufPos = bufPos + maxLength;
MmsJournalEntry journalEntry = (MmsJournalEntry) GLOBAL_CALLOC(1, sizeof(struct sMmsJournalEntry));
LinkedList_add(journalEntries, (void*) journalEntry);
while (bufPos < maxBufPos) {
if (journalEntry == NULL)
{
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: parseReadJournalResponse: out of memory\n");
return false;
}
while (bufPos < maxBufPos)
{
int length;
uint8_t tag = buffer[bufPos++];
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
if (bufPos < 0) {
if (bufPos < 0)
{
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: parseReadJournalResponse: invalid length field\n");
return false;
goto exit_error;
}
switch (tag) {
switch (tag)
{
case 0x80: /* entryID */
if (journalEntry->entryID)
{
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: parseReadJournalResponse: duplicate entryID\n");
goto exit_error;
}
else
{
journalEntry->entryID = MmsValue_newOctetString(length, length);
if (journalEntry->entryID)
MmsValue_setOctetString(journalEntry->entryID, buffer + bufPos, length);
}
break;
case 0xa1: /* originatingApplication */
@ -258,7 +338,7 @@ parseJournalEntry(uint8_t* buffer, int bufPos, int maxLength, LinkedList journal
case 0xa2: /* entryContent */
if (parseEntryContent(buffer, bufPos, length, journalEntry) == false)
return false;
goto exit_error;
break;
@ -269,13 +349,21 @@ parseJournalEntry(uint8_t* buffer, int bufPos, int maxLength, LinkedList journal
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: parseReadJournalResponse: unknown tag %02x\n", tag);
return false;
goto exit_error;
}
bufPos += length;
}
LinkedList_add(journalEntries, (void*) journalEntry);
return true;
exit_error:
MmsJournalEntry_destroy(journalEntry);
return false;
}
static bool
@ -283,14 +371,14 @@ parseListOfJournalEntries(uint8_t* buffer, int bufPos, int maxLength, LinkedList
{
int maxBufPos = bufPos + maxLength;
while (bufPos < maxBufPos) {
while (bufPos < maxBufPos)
{
int length;
uint8_t tag = buffer[bufPos++];
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
if (bufPos < 0) {
if (bufPos < 0)
{
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: parseReadJournalResponse: invalid length field\n");
@ -322,8 +410,6 @@ parseListOfJournalEntries(uint8_t* buffer, int bufPos, int maxLength, LinkedList
bool
mmsClient_parseReadJournalResponse(ByteBuffer* response, int respBufPos, bool* moreFollows, LinkedList* result)
{
uint8_t* buffer = ByteBuffer_getBuffer(response);
int maxBufPos = ByteBuffer_getSize(response);
int bufPos = respBufPos;
@ -331,7 +417,8 @@ mmsClient_parseReadJournalResponse(ByteBuffer* response, int respBufPos, bool* m
uint8_t tag = buffer[bufPos++];
if (tag != 0xbf) {
if (tag != 0xbf)
{
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: mmsClient_parseReadJournalResponse: unknown tag %02x\n", tag);
return false;
@ -342,7 +429,8 @@ mmsClient_parseReadJournalResponse(ByteBuffer* response, int respBufPos, bool* m
if (moreFollows)
*moreFollows = false;
if (tag != 0x41) {
if (tag != 0x41)
{
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: mmsClient_parseReadJournalResponse: unknown tag %02x\n", tag);
return false;
@ -355,17 +443,43 @@ mmsClient_parseReadJournalResponse(ByteBuffer* response, int respBufPos, bool* m
LinkedList journalEntries = NULL;
while (bufPos < endPos) {
while (bufPos < endPos)
{
tag = buffer[bufPos++];
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
if (bufPos < 0) return false;
switch (tag) {
case 0xa0: /* listOfJournalEntry */
if (journalEntries)
{
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: mmsClient_parseReadJournalResponse: duplicate listOfJournalEntry\n");
LinkedList_destroyDeep(journalEntries, (LinkedListValueDeleteFunction) MmsJournalEntry_destroy);
return false;
}
else
{
journalEntries = LinkedList_create();
if (journalEntries)
{
if (!parseListOfJournalEntries(buffer, bufPos, length, journalEntries))
{
LinkedList_destroyDeep(journalEntries, (LinkedListValueDeleteFunction) MmsJournalEntry_destroy);
return false;
}
}
else
{
return false;
}
}
break;
case 0x81: /* moreFollows */
@ -380,6 +494,8 @@ mmsClient_parseReadJournalResponse(ByteBuffer* response, int respBufPos, bool* m
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: mmsClient_parseReadJournalResponse: message contains unknown tag %02x!\n", tag);
LinkedList_destroyDeep(journalEntries, (LinkedListValueDeleteFunction) MmsJournalEntry_destroy);
return false;
}
@ -524,4 +640,3 @@ mmsClient_createReadJournalRequestStartAfter(uint32_t invokeId, ByteBuffer* requ
request->size = bufPos;
}

@ -1,7 +1,7 @@
/*
* mms_client_read.c
*
* Copyright 2013-2022 Michael Zillgith
* Copyright 2013-2024 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -45,17 +45,19 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
int i = 0;
for (i = 0; i < elementCount; i++) {
for (i = 0; i < elementCount; i++)
{
value = NULL;
AccessResult_PR presentType = accessResultList[i]->present;
if (presentType == AccessResult_PR_failure) {
if (presentType == AccessResult_PR_failure)
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: received access error!\n");
if (accessResultList[i]->choice.failure.size > 0) {
if (accessResultList[i]->choice.failure.size > 0)
{
int errorCode = (int) accessResultList[i]->choice.failure.buf[0];
MmsDataAccessError dataAccessError = DATA_ACCESS_ERROR_UNKNOWN;
@ -68,26 +70,29 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
else
value = MmsValue_newDataAccessError(DATA_ACCESS_ERROR_UNKNOWN);
}
else if (presentType == AccessResult_PR_array) {
else if (presentType == AccessResult_PR_array)
{
int arrayElementCount =
accessResultList[i]->choice.array.list.count;
if (arrayElementCount > 0) {
if (arrayElementCount > 0)
{
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_ARRAY;
value->value.structure.size = arrayElementCount;
value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(arrayElementCount, sizeof(MmsValue*));
if (value->value.structure.components) {
if (value->value.structure.components)
{
int j;
for (j = 0; j < arrayElementCount; j++) {
for (j = 0; j < arrayElementCount; j++)
{
value->value.structure.components[j] = mmsMsg_parseDataElement(
accessResultList[i]->choice.array.list.array[j]);
if (value->value.structure.components[j] == NULL) {
if (value->value.structure.components[j] == NULL)
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: failed to parse array element %i\n", j);
@ -98,33 +103,37 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
}
}
}
else {
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing access result (invalid array size)!\n");
}
}
else if (presentType == AccessResult_PR_structure) {
else if (presentType == AccessResult_PR_structure)
{
int componentCount =
accessResultList[i]->choice.structure.list.count;
if (componentCount > 0) {
if (componentCount > 0)
{
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
if (value) {
if (value)
{
value->type = MMS_STRUCTURE;
value->value.structure.size = componentCount;
value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*));
if (value->value.structure.components) {
if (value->value.structure.components)
{
int j;
for (j = 0; j < componentCount; j++) {
for (j = 0; j < componentCount; j++)
{
value->value.structure.components[j] = mmsMsg_parseDataElement(
accessResultList[i]->choice.structure.list.array[j]);
if (value->value.structure.components[j] == NULL) {
if (value->value.structure.components[j] == NULL)
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: failed to parse struct element %i\n", j);
@ -136,26 +145,28 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
}
}
}
else {
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing access result (invalid structure size)!\n");
}
}
else if (presentType == AccessResult_PR_bitstring) {
else if (presentType == AccessResult_PR_bitstring)
{
int size = accessResultList[i]->choice.bitstring.size;
if (size > 0) {
if (size > 0)
{
int maxSize = (size * 8);
int bitSize = maxSize - accessResultList[i]->choice.bitstring.bits_unused;
if ((bitSize > 0) && (maxSize >= bitSize)) {
if ((bitSize > 0) && (maxSize >= bitSize))
{
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_BIT_STRING;
if (value)
{
value->type = MMS_BIT_STRING;
value->value.bitString.size = (size * 8)
- accessResultList[i]->choice.bitstring.bits_unused;
@ -164,56 +175,64 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
memcpy(value->value.bitString.buf,
accessResultList[i]->choice.bitstring.buf, size);
}
else {
}
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing access result (bit string padding problem)!\n");
}
}
else {
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing access result (bit string size 0 or negative)!\n");
}
}
else if (presentType == AccessResult_PR_integer) {
else if (presentType == AccessResult_PR_integer)
{
int size = accessResultList[i]->choice.integer.size;
if (size > 0) {
if (size > 0)
{
Asn1PrimitiveValue* berInteger =
BerInteger_createFromBuffer(accessResultList[i]->choice.integer.buf, size);
value = MmsValue_newIntegerFromBerInteger(berInteger);
}
else {
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing access result (invalid integer size)!\n");
}
}
else if (presentType == AccessResult_PR_unsigned) {
else if (presentType == AccessResult_PR_unsigned)
{
int size = accessResultList[i]->choice.Unsigned.size;
if (size > 0) {
if (size > 0)
{
Asn1PrimitiveValue* berInteger =
BerInteger_createFromBuffer(accessResultList[i]->choice.Unsigned.buf,
accessResultList[i]->choice.Unsigned.size);
value = MmsValue_newUnsignedFromBerInteger(berInteger);
}
else {
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing access result (invalid unsigned size)!\n");
}
}
else if (presentType == AccessResult_PR_floatingpoint) {
else if (presentType == AccessResult_PR_floatingpoint)
{
int size = accessResultList[i]->choice.floatingpoint.size;
if (size == 5) { /* FLOAT32 */
if (size == 5) /* FLOAT32 */
{
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
if (value)
{
value->type = MMS_FLOAT;
value->value.floatingPoint.formatWidth = 32;
@ -226,11 +245,14 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
#else
memcpy(value->value.floatingPoint.buf, floatBuf, 4);
#endif
}
else if (size == 9) { /* FLOAT64 */
}
else if (size == 9) /* FLOAT64 */
{
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
if (value)
{
value->type = MMS_FLOAT;
value->value.floatingPoint.formatWidth = 64;
@ -244,19 +266,23 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
memcpy(value->value.floatingPoint.buf, floatBuf, 8);
#endif
}
else {
}
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing float (size must be 5 or 9, is %i)\n", size);
}
}
else if (presentType == AccessResult_PR_visiblestring) {
else if (presentType == AccessResult_PR_visiblestring)
{
int strSize = accessResultList[i]->choice.visiblestring.size;
if (strSize >= 0) {
if (strSize >= 0)
{
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
if (value)
{
value->type = MMS_VISIBLE_STRING;
value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1);
value->value.visibleString.size = strSize;
@ -267,19 +293,23 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
value->value.visibleString.buf[strSize] = 0;
}
else {
}
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing access result (invalid visible-string size)\n");
}
}
else if (presentType == AccessResult_PR_mMSString) {
else if (presentType == AccessResult_PR_mMSString)
{
int strSize = accessResultList[i]->choice.mMSString.size;
if (strSize >= 0) {
if (strSize >= 0)
{
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
if (value)
{
value->type = MMS_STRING;
value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1);
value->value.visibleString.size = strSize;
@ -289,60 +319,83 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
value->value.visibleString.buf[strSize] = 0;
}
else {
}
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing access result (invalid mms-string size)\n");
}
}
else if (presentType == AccessResult_PR_utctime) {
else if (presentType == AccessResult_PR_utctime)
{
int size = accessResultList[i]->choice.utctime.size;
if (size == 8) {
if (size == 8)
{
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
if (value)
{
value->type = MMS_UTC_TIME;
memcpy(value->value.utcTime, accessResultList[i]->choice.utctime.buf, 8);
}
else {
}
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing UTC time (size is %i instead of 8\n", size);
}
}
else if (presentType == AccessResult_PR_boolean) {
else if (presentType == AccessResult_PR_boolean)
{
value = MmsValue_newBoolean(accessResultList[i]->choice.boolean);
}
else if (presentType == AccessResult_PR_binarytime) {
else if (presentType == AccessResult_PR_binarytime)
{
int size = accessResultList[i]->choice.binarytime.size;
if ((size == 4) || (size == 6)) {
if ((size == 4) || (size == 6))
{
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
if (value)
{
value->type = MMS_BINARY_TIME;
value->value.binaryTime.size = size;
memcpy(value->value.binaryTime.buf, accessResultList[i]->choice.binarytime.buf, size);
}
else {
}
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing binary time (size must be 4 or 6, is %i\n", size);
}
}
else if (presentType == AccessResult_PR_octetstring) {
else if (presentType == AccessResult_PR_octetstring)
{
int size = accessResultList[i]->choice.octetstring.size;
if (size >= 0) {
if (size >= 0)
{
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
if (value)
{
value->type = MMS_OCTET_STRING;
value->value.octetString.maxSize = -size;
value->value.octetString.size = size;
value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size);
memcpy(value->value.octetString.buf, accessResultList[i]->choice.octetstring.buf, size);
}
else {
}
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing access result (invalid octet-string size)\n");
}
}
else {
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: unknown type %i in access result\n", presentType);
value = MmsValue_newDataAccessError(DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID);

@ -185,25 +185,29 @@ mmsMsg_parseDataElement(Data_t* dataElement)
{
MmsValue* value = NULL;
if (dataElement->present == Data_PR_array) {
if (dataElement->present == Data_PR_array)
{
int componentCount = dataElement->choice.array->list.count;
if (componentCount > 0) {
if (componentCount > 0)
{
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
if (value) {
if (value)
{
value->type = MMS_ARRAY;
value->value.structure.size = componentCount;
value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*));
int i;
for (i = 0; i < componentCount; i++) {
for (i = 0; i < componentCount; i++)
{
value->value.structure.components[i] =
mmsMsg_parseDataElement(dataElement->choice.array->list.array[i]);
if (value->value.structure.components[i] == NULL) {
if (value->value.structure.components[i] == NULL)
{
MmsValue_delete(value);
value = NULL;
break;
@ -211,31 +215,35 @@ mmsMsg_parseDataElement(Data_t* dataElement)
}
}
}
else {
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing data element (invalid array size)!\n");
}
}
else if (dataElement->present == Data_PR_structure) {
else if (dataElement->present == Data_PR_structure)
{
int componentCount = dataElement->choice.structure->list.count;
if (componentCount > 0) {
if (componentCount > 0)
{
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
if (value) {
if (value)
{
value->type = MMS_STRUCTURE;
value->value.structure.size = componentCount;
value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*));
int i;
for (i = 0; i < componentCount; i++) {
for (i = 0; i < componentCount; i++)
{
value->value.structure.components[i] =
mmsMsg_parseDataElement(dataElement->choice.structure->list.array[i]);
if (value->value.structure.components[i] == NULL) {
if (value->value.structure.components[i] == NULL)
{
MmsValue_delete(value);
value = NULL;
break;
@ -243,112 +251,128 @@ mmsMsg_parseDataElement(Data_t* dataElement)
}
}
}
else {
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing data element (invalid structure size)!\n");
}
}
else {
if (dataElement->present == Data_PR_integer) {
if (dataElement->choice.integer.size > 0) {
else
{
if (dataElement->present == Data_PR_integer)
{
if (dataElement->choice.integer.size > 0)
{
Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer(
dataElement->choice.integer.buf, dataElement->choice.integer.size);
if (berInteger)
value = MmsValue_newIntegerFromBerInteger(berInteger);
}
else {
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing data element (invalid integer size)!\n");
}
}
else if (dataElement->present == Data_PR_unsigned) {
if (dataElement->choice.Unsigned.size > 0) {
else if (dataElement->present == Data_PR_unsigned)
{
if (dataElement->choice.Unsigned.size > 0)
{
Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer(
dataElement->choice.Unsigned.buf, dataElement->choice.Unsigned.size);
if (berInteger)
value = MmsValue_newUnsignedFromBerInteger(berInteger);
}
else {
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing data element (invalid unsigned size)!\n");
}
}
else if (dataElement->present == Data_PR_visiblestring) {
if (dataElement->choice.visiblestring.size >= 0) {
else if (dataElement->present == Data_PR_visiblestring)
{
if (dataElement->choice.visiblestring.size >= 0)
{
value = MmsValue_newVisibleStringFromByteArray(dataElement->choice.visiblestring.buf,
dataElement->choice.visiblestring.size);
}
}
else if (dataElement->present == Data_PR_mMSString) {
if ( dataElement->choice.mMSString.size >= 0) {
else if (dataElement->present == Data_PR_mMSString)
{
if ( dataElement->choice.mMSString.size >= 0)
{
value = MmsValue_newMmsStringFromByteArray(dataElement->choice.mMSString.buf,
dataElement->choice.mMSString.size);
}
}
else if (dataElement->present == Data_PR_bitstring) {
else if (dataElement->present == Data_PR_bitstring)
{
int size = dataElement->choice.bitstring.size;
if (size >= 0) {
if (size >= 0)
{
int maxSize = (size * 8);
int bitSize = maxSize - dataElement->choice.bitstring.bits_unused;
if ((bitSize > 0) && (maxSize >= bitSize)) {
if ((bitSize > 0) && (maxSize >= bitSize))
{
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
if (value) {
if (value)
{
value->type = MMS_BIT_STRING;
value->value.bitString.size = bitSize;
value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size);
if (value->value.bitString.buf) {
if (value->value.bitString.buf)
{
memcpy(value->value.bitString.buf,
dataElement->choice.bitstring.buf, size);
}
else {
else
{
GLOBAL_FREEMEM(value);
value = 0;
}
}
}
else if (bitSize == 0) {
else if (bitSize == 0)
{
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
if (value) {
if (value)
{
value->type = MMS_BIT_STRING;
value->value.bitString.size = 0;
value->value.bitString.buf = NULL;
}
}
else {
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing data element (bit string padding problem)!\n");
}
}
else {
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing data element (bit string size 0 or negative)!\n");
}
}
else if (dataElement->present == Data_PR_floatingpoint) {
else if (dataElement->present == Data_PR_floatingpoint)
{
int size = dataElement->choice.floatingpoint.size;
if (size == 5) { /* FLOAT32 */
if (size == 5) /* FLOAT32 */
{
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
if (value) {
if (value)
{
value->type = MMS_FLOAT;
value->value.floatingPoint.formatWidth = 32;
@ -364,11 +388,12 @@ mmsMsg_parseDataElement(Data_t* dataElement)
}
}
if (size == 9) { /* FLOAT64 */
if (size == 9) /* FLOAT64 */
{
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
if (value) {
if (value)
{
value->type = MMS_FLOAT;
value->value.floatingPoint.formatWidth = 64;
@ -384,29 +409,34 @@ mmsMsg_parseDataElement(Data_t* dataElement)
}
}
}
else if (dataElement->present == Data_PR_utctime) {
else if (dataElement->present == Data_PR_utctime)
{
int size = dataElement->choice.utctime.size;
if (size == 8) {
if (size == 8)
{
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
if (value) {
if (value)
{
value->type = MMS_UTC_TIME;
memcpy(value->value.utcTime, dataElement->choice.utctime.buf, 8);
}
}
else {
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing UTC time (size is %i instead of 8\n", size);
}
}
else if (dataElement->present == Data_PR_octetstring) {
if (dataElement->choice.octetstring.size >= 0) {
else if (dataElement->present == Data_PR_octetstring)
{
if (dataElement->choice.octetstring.size >= 0)
{
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
if (value) {
if (value)
{
value->type = MMS_OCTET_STRING;
int size = dataElement->choice.octetstring.size;
@ -419,44 +449,51 @@ mmsMsg_parseDataElement(Data_t* dataElement)
value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(abs(value->value.octetString.maxSize));
if (value->value.octetString.buf) {
if (value->value.octetString.buf)
{
memcpy(value->value.octetString.buf, dataElement->choice.octetstring.buf, size);
}
else {
else
{
GLOBAL_FREEMEM(value);
value = NULL;
}
}
}
}
else if (dataElement->present == Data_PR_binarytime) {
else if (dataElement->present == Data_PR_binarytime)
{
int size = dataElement->choice.binarytime.size;
if ((size == 4) || (size == 6)) {
if ((size == 4) || (size == 6))
{
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
if (value) {
if (value)
{
value->type = MMS_BINARY_TIME;
value->value.binaryTime.size = size;
memcpy(value->value.binaryTime.buf, dataElement->choice.binarytime.buf, size);
}
}
else {
else
{
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing binary time (size must be 4 or 6, is %i\n", size);
}
}
else if (dataElement->present == Data_PR_boolean) {
else if (dataElement->present == Data_PR_boolean)
{
value = MmsValue_newBoolean(dataElement->choice.boolean);
}
else if (dataElement->present == Data_PR_booleanArray) {
else if (dataElement->present == Data_PR_booleanArray)
{
/* not supported */
}
}
if (DEBUG_MMS_CLIENT) {
if (DEBUG_MMS_CLIENT)
{
if (value == NULL)
printf("MMS CLIENT: error parsing data element\n");
}
@ -472,16 +509,16 @@ mmsMsg_createStringFromAsnIdentifier(Identifier_t identifier)
return str;
}
void
mmsMsg_copyAsn1IdentifierToStringBuffer(Identifier_t identifier, char* buffer, int bufSize)
{
if (identifier.size < bufSize) {
if (identifier.size < bufSize)
{
memcpy(buffer, identifier.buf, identifier.size);
buffer[identifier.size] = 0;
}
else {
else
{
if (DEBUG_MMS_SERVER || DEBUG_MMS_CLIENT)
printf("MMS_COMMON: mms_common_msg.c: ASN1 identifier to long!\n");
@ -492,12 +529,12 @@ mmsMsg_copyAsn1IdentifierToStringBuffer(Identifier_t identifier, char* buffer, i
char*
mmsMsg_getComponentNameFromAlternateAccess(AlternateAccess_t* alternateAccess, char* componentNameBuf, int nameBufPos)
{
if (alternateAccess->list.count == 1) {
if (alternateAccess->list.array[0]->present == AlternateAccess__Member_PR_unnamed) {
if (alternateAccess->list.array[0]->choice.unnamed->present == AlternateAccessSelection_PR_selectAlternateAccess) {
if (alternateAccess->list.count == 1)
{
if (alternateAccess->list.array[0]->present == AlternateAccess__Member_PR_unnamed)
{
if (alternateAccess->list.array[0]->choice.unnamed->present == AlternateAccessSelection_PR_selectAlternateAccess)
{
if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.present ==
AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_component)
{
@ -507,26 +544,30 @@ mmsMsg_getComponentNameFromAlternateAccess(AlternateAccess_t* alternateAccess, c
AlternateAccess_t* nextAlternateAccess = alternateAccess->list.array[0]->choice.unnamed->
choice.selectAlternateAccess.alternateAccess;
if (nextAlternateAccess) {
if (nameBufPos + componentIdentifier.size + 1 < 65) {
if (nextAlternateAccess)
{
if (nameBufPos + componentIdentifier.size + 1 < 65)
{
memcpy(componentNameBuf + nameBufPos, componentIdentifier.buf, componentIdentifier.size);
nameBufPos += componentIdentifier.size;
componentNameBuf[nameBufPos++] = '$';
return mmsMsg_getComponentNameFromAlternateAccess(nextAlternateAccess, componentNameBuf, nameBufPos);
}
else {
else
{
if (DEBUG_MMS_SERVER)
printf("MMS_SERVER: component identifier name too long!\n");
}
}
else {
else
{
if (DEBUG_MMS_SERVER)
printf("MMS_SERVER: next alternate access specification is missing!\n");
}
}
}
else if (alternateAccess->list.array[0]->choice.unnamed->present == AlternateAccessSelection_PR_selectAccess) {
else if (alternateAccess->list.array[0]->choice.unnamed->present == AlternateAccessSelection_PR_selectAccess)
{
/* final component part */
if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present ==
@ -535,21 +576,21 @@ mmsMsg_getComponentNameFromAlternateAccess(AlternateAccess_t* alternateAccess, c
Identifier_t componentIdentifier = alternateAccess->list.array[0]->choice.unnamed->
choice.selectAccess.choice.component;
if (nameBufPos + componentIdentifier.size + 1 < 65) {
if (nameBufPos + componentIdentifier.size + 1 < 65)
{
memcpy(componentNameBuf + nameBufPos, componentIdentifier.buf, componentIdentifier.size);
nameBufPos += componentIdentifier.size;
componentNameBuf[nameBufPos++] = 0;
return componentNameBuf;
}
else {
else
{
if (DEBUG_MMS_SERVER)
printf("MMS_SERVER: component identifier name too long!\n");
}
}
}
}
}
if (DEBUG_MMS_SERVER)
@ -610,7 +651,8 @@ mmsMsg_parseFileName(char* filename, uint8_t* buffer, int* bufPos, int maxBufPos
uint8_t tag = buffer[(*bufPos)++];
if (tag != 0x19) {
if (tag != 0x19)
{
mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response);
return false;
}
@ -619,12 +661,14 @@ mmsMsg_parseFileName(char* filename, uint8_t* buffer, int* bufPos, int maxBufPos
*bufPos = BerDecoder_decodeLength(buffer, &length, *bufPos, maxBufPos);
if (*bufPos < 0) {
if (*bufPos < 0)
{
mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response);
return false;
}
if (length > 255) {
if (length > 255)
{
mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response);
return false;
}
@ -637,7 +681,8 @@ mmsMsg_parseFileName(char* filename, uint8_t* buffer, int* bufPos, int maxBufPos
* TODO this may be platform dependent. Also depending of the platform there might be other evil
* characters.
*/
if (strstr(filename, "..") != NULL) {
if (strstr(filename, "..") != NULL)
{
mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_FILE_FILE_NON_EXISTENT);
return false;
}
@ -646,4 +691,3 @@ mmsMsg_parseFileName(char* filename, uint8_t* buffer, int* bufPos, int maxBufPos
}
#endif /* (MMS_FILE_SERVICE == 1) */

@ -152,9 +152,14 @@ exit_with_error:
return -1;
}
MmsValue*
MmsValue_decodeMmsData(uint8_t* buffer, int bufPos, int bufferLength, int* endBufPos)
static MmsValue*
MmsValue_decodeMmsDataRecursive(uint8_t* buffer, int bufPos, int bufferLength, int* endBufPos, int depth, int maxDepth)
{
depth++;
if (depth > maxDepth)
return NULL;
MmsValue* value = NULL;
int dataEndBufPos = bufferLength;
@ -206,7 +211,7 @@ MmsValue_decodeMmsData(uint8_t* buffer, int bufPos, int bufferLength, int* endBu
int elementBufLength = newBufPos - bufPos + elementLength;
MmsValue* elementValue = MmsValue_decodeMmsData(buffer, bufPos, bufPos + elementBufLength, NULL);
MmsValue* elementValue = MmsValue_decodeMmsDataRecursive(buffer, bufPos, bufPos + elementBufLength, NULL, depth, maxDepth);
if (elementValue == NULL)
goto exit_with_error;
@ -338,6 +343,18 @@ exit_with_error:
return NULL;
}
MmsValue*
MmsValue_decodeMmsDataMaxRecursion(uint8_t* buffer, int bufPos, int bufferLength, int* endBufPos, int maxDepth)
{
return MmsValue_decodeMmsDataRecursive(buffer, bufPos, bufferLength, endBufPos, 0, maxDepth);
}
MmsValue*
MmsValue_decodeMmsData(uint8_t* buffer, int bufPos, int bufferLength, int* endBufPos)
{
return MmsValue_decodeMmsDataMaxRecursion(buffer, bufPos, bufferLength, endBufPos, 25);
}
static int
MmsValue_getMaxStructSize(MmsValue* self)
{

@ -1,7 +1,7 @@
/*
* mms_server.c
*
* Copyright 2013-2023 Michael Zillgith
* Copyright 2013-2024 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -34,7 +34,8 @@ createValueCaches(MmsDevice* device)
Map valueCaches = Map_create();
int i;
for (i = 0; i < device->domainCount; i++) {
for (i = 0; i < device->domainCount; i++)
{
MmsValueCache valueCache = MmsValueCache_create(device->domains[i]);
Map_addEntry(valueCaches, device->domains[i], valueCache);
}
@ -52,7 +53,8 @@ MmsServer_create(MmsDevice* device, TLSConfiguration tlsConfiguration)
{
MmsServer self = (MmsServer) GLOBAL_CALLOC(1, sizeof(struct sMmsServer));
if (self) {
if (self)
{
#if (CONFIG_MMS_THREADLESS_STACK != 1)
self->openConnectionsLock = Semaphore_create(1);
@ -75,7 +77,8 @@ MmsServer_create(MmsDevice* device, TLSConfiguration tlsConfiguration)
if (self->isoServerList == NULL)
goto exit_error;
if (tlsConfiguration) {
if (tlsConfiguration)
{
IsoServer isoServer = IsoServer_create(tlsConfiguration);
if (isoServer == NULL)
@ -115,7 +118,8 @@ MmsServer_create(MmsDevice* device, TLSConfiguration tlsConfiguration)
{
int i;
for (i = 0; i < CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS; i++) {
for (i = 0; i < CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS; i++)
{
self->fileUploadTasks[i].state = 0;
#if (CONFIG_MMS_THREADLESS_STACK != 1)
@ -140,8 +144,8 @@ MmsServer_addAP(MmsServer self, const char* ipAddr, int tcpPort, TLSConfiguratio
{
IsoServer isoServer = IsoServer_create(tlsConfiguration);
if (isoServer) {
if (isoServer)
{
IsoServer_setLocalIpAddress(isoServer, ipAddr);
if (tcpPort != -1)
@ -161,13 +165,15 @@ MmsServer_addAP(MmsServer self, const char* ipAddr, int tcpPort, TLSConfiguratio
void
MmsServer_setLocalIpAddress(MmsServer self, const char* localIpAddress)
{
if (LinkedList_size(self->isoServerList) == 0) {
if (LinkedList_size(self->isoServerList) == 0)
{
MmsServer_addAP(self, NULL, -1, NULL);
}
LinkedList elem = LinkedList_get(self->isoServerList, 0);
if (elem) {
if (elem)
{
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
IsoServer_setLocalIpAddress(isoServer, localIpAddress);
@ -179,7 +185,8 @@ MmsServer_isRunning(MmsServer self)
{
LinkedList elem = LinkedList_get(self->isoServerList, 0);
if (elem) {
if (elem)
{
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
if (IsoServer_getState(isoServer) == ISO_SVR_STATE_RUNNING)
@ -193,12 +200,13 @@ void
MmsServer_setFilestoreBasepath(MmsServer self, const char* basepath)
{
#if (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1)
if (self->filestoreBasepath != NULL) {
if (self->filestoreBasepath)
{
GLOBAL_FREEMEM(self->filestoreBasepath);
self->filestoreBasepath = NULL;
}
if (basepath != NULL)
if (basepath)
self->filestoreBasepath = StringUtils_copyString(basepath);
#endif /* (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1) */
}
@ -208,15 +216,17 @@ MmsServer_setFilestoreBasepath(MmsServer self, const char* basepath)
void
MmsServer_setMaxConnections(MmsServer self, int maxConnections)
{
if (self->isoServerList) {
if (LinkedList_size(self->isoServerList) == 0) {
if (self->isoServerList)
{
if (LinkedList_size(self->isoServerList) == 0)
{
MmsServer_addAP(self, NULL, -1, NULL);
}
LinkedList elem = LinkedList_getNext(self->isoServerList);
while (elem) {
while (elem)
{
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
IsoServer_setMaxConnections(isoServer, maxConnections);
@ -307,13 +317,14 @@ MmsServer_getObtainFileTask(MmsServer self)
{
int i;
for (i = 0; i < CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS; i++) {
for (i = 0; i < CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS; i++)
{
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_wait(self->fileUploadTasks[i].taskLock);
#endif
if (self->fileUploadTasks[i].state == 0) {
if (self->fileUploadTasks[i].state == 0)
{
self->fileUploadTasks[i].state = 1;
return &(self->fileUploadTasks[i]);
@ -322,7 +333,6 @@ MmsServer_getObtainFileTask(MmsServer self)
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_post(self->fileUploadTasks[i].taskLock);
#endif
}
return NULL;
@ -392,11 +402,12 @@ MmsServer_setClientAuthenticator(MmsServer self, AcseAuthenticator authenticator
self->authenticator = authenticator;
self->authenticatorParameter = authenticatorParameter;
if (self->isoServerList) {
if (self->isoServerList)
{
LinkedList elem = LinkedList_getNext(self->isoServerList);
while (elem) {
while (elem)
{
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
IsoServer_setAuthenticator(isoServer, authenticator, authenticatorParameter);
@ -448,7 +459,8 @@ deleteSingleCache(MmsValueCache cache)
void
MmsServer_destroy(MmsServer self)
{
if (self) {
if (self)
{
LinkedList_destroyDeep(self->isoServerList, (LinkedListValueDeleteFunction) IsoServer_destroy);
Map_deleteDeep(self->openConnections, false, closeConnection);
@ -476,7 +488,8 @@ MmsServer_destroy(MmsServer self)
#if (MMS_OBTAIN_FILE_SERVICE == 1)
#if (CONFIG_MMS_THREADLESS_STACK != 1)
int i;
for (i = 0; i < CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS; i++) {
for (i = 0; i < CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS; i++)
{
if (self->fileUploadTasks[i].taskLock)
Semaphore_destroy(self->fileUploadTasks[i].taskLock);
}
@ -492,10 +505,10 @@ MmsServer_getValueFromCache(MmsServer self, MmsDomain* domain, const char* itemI
{
MmsValueCache cache = (MmsValueCache) Map_getEntry(self->valueCaches, domain);
if (cache != NULL)
if (cache)
return MmsValueCache_lookupValue(cache, itemId, NULL);
return NULL ;
return NULL;
}
MmsValue*
@ -503,10 +516,10 @@ MmsServer_getValueFromCacheEx(MmsServer self, MmsDomain* domain, const char* ite
{
MmsValueCache cache = (MmsValueCache) Map_getEntry(self->valueCaches, domain);
if (cache != NULL)
if (cache)
return MmsValueCache_lookupValue(cache, itemId, typeSpec);
return NULL ;
return NULL;
}
MmsValue*
@ -514,10 +527,10 @@ MmsServer_getValueFromCacheEx2(MmsServer self, MmsDomain* domain, const char* it
{
MmsValueCache cache = (MmsValueCache) Map_getEntry(self->valueCaches, domain);
if (cache != NULL)
if (cache)
return MmsValueCache_lookupValueEx(cache, itemId, idx, componentId, NULL);
return NULL ;
return NULL;
}
void
@ -525,9 +538,8 @@ MmsServer_insertIntoCache(MmsServer self, MmsDomain* domain, char* itemId, MmsVa
{
MmsValueCache cache = (MmsValueCache) Map_getEntry(self->valueCaches, domain);
if (cache != NULL) {
if (cache)
MmsValueCache_insertValue(cache, itemId, value);
}
}
MmsDataAccessError
@ -541,7 +553,8 @@ mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* va
indication = self->writeHandler(self->writeHandlerParameter, domain,
itemId, -1, NULL, value, connection);
}
else {
else
{
MmsValue* cachedValue;
if (domain == NULL)
@ -549,10 +562,12 @@ mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* va
cachedValue = MmsServer_getValueFromCache(self, domain, itemId);
if (cachedValue) {
if (cachedValue)
{
MmsValue_update(cachedValue, value);
indication = DATA_ACCESS_ERROR_SUCCESS;
} else
}
else
indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID;
}
@ -570,7 +585,8 @@ mmsServer_setValueEx(MmsServer self, MmsDomain* domain, char* itemId, MmsValue*
indication = self->writeHandler(self->writeHandlerParameter, domain,
itemId, arrayIdx, componentId, value, connection);
}
else {
else
{
MmsValue* cachedValue = NULL;
if (domain == NULL)
@ -578,10 +594,12 @@ mmsServer_setValueEx(MmsServer self, MmsDomain* domain, char* itemId, MmsValue*
cachedValue = MmsServer_getValueFromCacheEx2(self, domain, itemId, arrayIdx, componentId);
if (cachedValue) {
if (cachedValue)
{
MmsValue_update(cachedValue, value);
indication = DATA_ACCESS_ERROR_SUCCESS;
} else
}
else
indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID;
}
@ -593,12 +611,14 @@ mmsServer_getValue(MmsServer self, MmsDomain* domain, char* itemId, MmsServerCon
{
MmsValue* value = NULL;
if (self->readAccessHandler != NULL) {
if (self->readAccessHandler != NULL)
{
MmsDataAccessError accessError =
self->readAccessHandler(self->readAccessHandlerParameter, (domain == (MmsDomain*) self->device) ? NULL : domain,
itemId, connection, isDirectAccess);
if (accessError != DATA_ACCESS_ERROR_SUCCESS) {
if (accessError != DATA_ACCESS_ERROR_SUCCESS)
{
value = MmsValue_newDataAccessError(accessError);
MmsValue_setDeletable(value);
goto exit_function;
@ -616,26 +636,13 @@ exit_function:
return value;
}
MmsDataAccessError
mmsServer_checkReadAccess(MmsServer self, MmsDomain* domain, char* itemId, MmsServerConnection connection, bool isDirectAccess)
{
MmsDataAccessError accessError = DATA_ACCESS_ERROR_SUCCESS;
if (self->readAccessHandler) {
accessError =
self->readAccessHandler(self->readAccessHandlerParameter, (domain == (MmsDomain*) self->device) ? NULL : domain,
itemId, connection, isDirectAccess);
}
return accessError;
}
bool
mmsServer_checkListAccess(MmsServer self, MmsGetNameListType listType, MmsDomain* domain, char* itemId, MmsServerConnection connection)
{
bool allowAccess = true;
if (self->listAccessHandler) {
if (self->listAccessHandler)
{
allowAccess = self->listAccessHandler(self->listAccessHandlerParameter, listType, domain, itemId, connection);
}
@ -654,7 +661,8 @@ isoConnectionIndicationHandler(IsoConnectionIndication indication,
{
MmsServer self = (MmsServer) parameter;
if (indication == ISO_CONNECTION_OPENED) {
if (indication == ISO_CONNECTION_OPENED)
{
MmsServerConnection mmsCon = MmsServerConnection_init(0, self, connection);
#if (CONFIG_MMS_THREADLESS_STACK != 1)
@ -671,8 +679,8 @@ isoConnectionIndicationHandler(IsoConnectionIndication indication,
self->connectionHandler(self->connectionHandlerParameter,
mmsCon, MMS_SERVER_NEW_CONNECTION);
}
else if (indication == ISO_CONNECTION_CLOSED) {
else if (indication == ISO_CONNECTION_CLOSED)
{
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_wait(self->openConnectionsLock);
#endif
@ -697,15 +705,17 @@ isoConnectionIndicationHandler(IsoConnectionIndication indication,
void
MmsServer_startListening(MmsServer self, int tcpPort)
{
if (self->isoServerList) {
if (LinkedList_size(self->isoServerList) == 0) {
if (self->isoServerList)
{
if (LinkedList_size(self->isoServerList) == 0)
{
MmsServer_addAP(self, NULL, -1, NULL);
}
LinkedList elem = LinkedList_getNext(self->isoServerList);
while (elem) {
while (elem)
{
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
IsoServer_setConnectionHandler(isoServer, isoConnectionIndicationHandler, (void*) self);
@ -723,10 +733,12 @@ MmsServer_startListening(MmsServer self, int tcpPort)
void
MmsServer_stopListening(MmsServer self)
{
if (self->isoServerList) {
if (self->isoServerList)
{
LinkedList elem = LinkedList_getNext(self->isoServerList);
while (elem) {
while (elem)
{
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
IsoServer_stopListening(isoServer);
@ -740,15 +752,17 @@ MmsServer_stopListening(MmsServer self)
void
MmsServer_startListeningThreadless(MmsServer self, int tcpPort)
{
if (self->isoServerList) {
if (LinkedList_size(self->isoServerList) == 0) {
if (self->isoServerList)
{
if (LinkedList_size(self->isoServerList) == 0)
{
MmsServer_addAP(self, NULL, -1, NULL);
}
LinkedList elem = LinkedList_getNext(self->isoServerList);
while (elem) {
while (elem)
{
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
IsoServer_setConnectionHandler(isoServer, isoConnectionIndicationHandler, (void*) self);
@ -768,21 +782,25 @@ MmsServer_waitReady(MmsServer self, unsigned int timeoutMs)
{
int result = 0;
if (self->isoServerList) {
if (self->isoServerList)
{
bool isFirst = true;
LinkedList elem = LinkedList_getNext(self->isoServerList);
while (elem) {
while (elem)
{
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
int serverResult;
if (isFirst) {
if (isFirst)
{
serverResult = IsoServer_waitReady(isoServer, timeoutMs);
isFirst = false;
}
else {
else
{
serverResult = IsoServer_waitReady(isoServer, 0);
}
@ -799,10 +817,12 @@ MmsServer_waitReady(MmsServer self, unsigned int timeoutMs)
void
MmsServer_handleIncomingMessages(MmsServer self)
{
if (self->isoServerList) {
if (self->isoServerList)
{
LinkedList elem = LinkedList_getNext(self->isoServerList);
while (elem) {
while (elem)
{
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
IsoServer_processIncomingMessages(isoServer);
@ -844,10 +864,12 @@ MmsServer_getConnectionCounter(MmsServer self)
{
int count = 0;
if (self->isoServerList) {
if (self->isoServerList)
{
LinkedList elem = LinkedList_getNext(self->isoServerList);
while (elem) {
while (elem)
{
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
count += IsoServer_getConnectionCounter(isoServer);
@ -862,7 +884,8 @@ MmsServer_getConnectionCounter(MmsServer self)
void
MmsServer_callConnectionHandler(MmsServer self, MmsServerConnection connection)
{
if (self->connectionHandler) {
if (self->connectionHandler)
{
self->connectionHandler(self->connectionHandlerParameter, connection, MMS_SERVER_CONNECTION_TICK);
}
}
@ -870,10 +893,12 @@ MmsServer_callConnectionHandler(MmsServer self, MmsServerConnection connection)
void
MmsServer_stopListeningThreadless(MmsServer self)
{
if (self->isoServerList) {
if (self->isoServerList)
{
LinkedList elem = LinkedList_getNext(self->isoServerList);
while (elem) {
while (elem)
{
IsoServer isoServer = (IsoServer) LinkedList_getData(elem);
IsoServer_stopListeningThreadless(isoServer);

@ -81,7 +81,7 @@ struct sRSessionPayloadElement
* \return new RSession instance
*/
LIB61850_API RSession
RSession_create();
RSession_create(void);
/**
* \brief Set the maximum buffer size for session messages (range: 128 - 65535)

@ -3,7 +3,7 @@
*
* Implementation of RSessionCrypto interface using mbedtls
*
* Copyright 2013-2023 Michael Zillgith
* Copyright 2013-2024 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -25,7 +25,6 @@
#include "mbedtls/cipher.h"
#include "mbedtls/md.h"
#include "mbedtls/md_internal.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/gcm.h"
#include "mbedtls/entropy.h"
@ -42,7 +41,7 @@
bool
RSessionCrypto_createHMAC(uint8_t* buffer, int bufSize, uint8_t* key, int keySize, uint8_t* hmac, int hmacMaxSize)
{
const mbedtls_md_info_t* md_info = &mbedtls_sha256_info;
const mbedtls_md_info_t* md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
mbedtls_md_context_t md_ctx;

@ -1,7 +1,7 @@
/*
* sv_publisher.c
*
* Copyright 2016-2022 Michael Zillgith
* Copyright 2016-2024 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -76,8 +76,10 @@ struct sSVPublisher {
uint16_t appId;
bool simulation;
#if (CONFIG_IEC61850_L2_SMV == 1)
/* only for Ethernet based SV */
EthernetSocket ethernetSocket;
#endif /* (CONFIG_IEC61850_L2_SMV == 1) */
#if (CONFIG_IEC61850_R_SMV == 1)
/* only for R-SV */
@ -93,7 +95,7 @@ struct sSVPublisher {
SVPublisher_ASDU asduList;
};
#if (CONFIG_IEC61850_L2_SMV == 1)
static bool
preparePacketBuffer(SVPublisher self, CommParameters* parameters, const char* interfaceId, bool useVlanTags)
{
@ -194,7 +196,7 @@ preparePacketBuffer(SVPublisher self, CommParameters* parameters, const char* in
return true;
}
#endif /* (CONFIG_IEC61850_L2_SMV == 1) */
static int
encodeUInt16FixedSize(uint16_t value, uint8_t* buffer, int bufPos)
@ -303,6 +305,7 @@ SVPublisher_createRemote(RSession session, uint16_t appId)
}
#endif /* (CONFIG_IEC61850_R_SMV == 1) */
#if (CONFIG_IEC61850_L2_SMV == 1)
SVPublisher
SVPublisher_createEx(CommParameters* parameters, const char* interfaceId, bool useVlanTag)
{
@ -329,6 +332,7 @@ SVPublisher_create(CommParameters* parameters, const char* interfaceId)
{
return SVPublisher_createEx(parameters, interfaceId, true);
}
#endif /* (CONFIG_IEC61850_R_SMV == 1) */
SVPublisher_ASDU
SVPublisher_addASDU(SVPublisher self, const char* svID, const char* datset, uint32_t confRev)
@ -527,21 +531,25 @@ SVPublisher_setupComplete(SVPublisher self)
void
SVPublisher_publish(SVPublisher self)
{
#if (CONFIG_IEC61850_L2_SMV == 1)
if (self->ethernetSocket)
{
if (DEBUG_SV_PUBLISHER)
printf("SV_PUBLISHER: send SV message\n");
printf("SV_PUBLISHER: send L2 SV message\n");
if (self->ethernetSocket) {
Ethernet_sendPacket(self->ethernetSocket, self->buffer, self->payloadStart + self->payloadLength);
}
#endif /* (CONFIG_IEC61850_L2_SMV == 1) */
#if (CONFIG_IEC61850_R_SMV == 1)
else if (self->remoteSession) {
if (self->remoteSession)
{
if (DEBUG_SV_PUBLISHER)
printf("SV_PUBLISHER: send R-SV message\n");
RSession_sendMessage(self->remoteSession, RSESSION_SPDU_ID_SV, self->simulation, self->appId, self->buffer, self->payloadLength);
}
#endif /* (CONFIG_IEC61850_R_SMV == 1) */
else {
if (DEBUG_SV_PUBLISHER)
printf("SV_PUBLISHER: no network layer!\n");
}
}
void
@ -549,8 +557,10 @@ SVPublisher_destroy(SVPublisher self)
{
if (self)
{
#if (CONFIG_IEC61850_L2_SMV == 1)
if (self->ethernetSocket)
Ethernet_destroySocket(self->ethernetSocket);
#endif /* (CONFIG_IEC61850_L2_SMV == 1) */
if (self->buffer)
GLOBAL_FREEMEM(self->buffer);
@ -808,139 +818,3 @@ SVPublisher_ASDU_setSmpSynch(SVPublisher_ASDU self, uint16_t smpSynch)
self->smpSynch = smpSynch;
*(self->smpSynchBuf) = self->smpSynch;
}
/*******************************************************************
* Wrapper functions to support old API (remove in future versions)
*******************************************************************/
SVPublisher
SampledValuesPublisher_create(CommParameters* parameters, const char* interfaceId)
{
return SVPublisher_create(parameters, interfaceId);
}
SVPublisher_ASDU
SampledValuesPublisher_addASDU(SVPublisher self, char* svID, char* datset, uint32_t confRev)
{
return SVPublisher_addASDU(self, svID, datset, confRev);
}
void
SampledValuesPublisher_setupComplete(SVPublisher self)
{
SVPublisher_setupComplete(self);
}
void
SampledValuesPublisher_publish(SVPublisher self)
{
SVPublisher_publish(self);
}
void
SampledValuesPublisher_destroy(SVPublisher self)
{
SVPublisher_destroy(self);
}
void
SV_ASDU_resetBuffer(SVPublisher_ASDU self)
{
SVPublisher_ASDU_resetBuffer(self);
}
int
SV_ASDU_addINT8(SVPublisher_ASDU self)
{
return SVPublisher_ASDU_addINT8(self);
}
void
SV_ASDU_setINT8(SVPublisher_ASDU self, int index, int8_t value)
{
SVPublisher_ASDU_setINT8(self, index, value);
}
int
SV_ASDU_addINT32(SVPublisher_ASDU self)
{
return SVPublisher_ASDU_addINT32(self);
}
void
SV_ASDU_setINT32(SVPublisher_ASDU self, int index, int32_t value)
{
SVPublisher_ASDU_setINT32(self, index, value);
}
int
SV_ASDU_addINT64(SVPublisher_ASDU self)
{
return SVPublisher_ASDU_addINT64(self);
}
void
SV_ASDU_setINT64(SVPublisher_ASDU self, int index, int64_t value)
{
SVPublisher_ASDU_setINT64(self, index, value);
}
int
SV_ASDU_addFLOAT(SVPublisher_ASDU self)
{
return SVPublisher_ASDU_addFLOAT(self);
}
void
SV_ASDU_setFLOAT(SVPublisher_ASDU self, int index, float value)
{
SVPublisher_ASDU_setFLOAT(self, index, value);
}
int
SV_ASDU_addFLOAT64(SVPublisher_ASDU self)
{
return SVPublisher_ASDU_addFLOAT64(self);
}
void
SV_ASDU_setFLOAT64(SVPublisher_ASDU self, int index, double value)
{
SVPublisher_ASDU_setFLOAT64(self, index, value);
}
void
SV_ASDU_setSmpCnt(SVPublisher_ASDU self, uint16_t value)
{
SVPublisher_ASDU_setSmpCnt(self, value);
}
uint16_t
SV_ASDU_getSmpCnt(SVPublisher_ASDU self)
{
return SVPublisher_ASDU_getSmpCnt(self);
}
void
SV_ASDU_increaseSmpCnt(SVPublisher_ASDU self)
{
SVPublisher_ASDU_increaseSmpCnt(self);
}
void
SV_ASDU_setRefrTm(SVPublisher_ASDU self, uint64_t refrTm)
{
SVPublisher_ASDU_setRefrTm(self, refrTm);
}
void
SV_ASDU_setSmpMod(SVPublisher_ASDU self, uint8_t smpMod)
{
SVPublisher_ASDU_setSmpMod(self, smpMod);
}
void
SV_ASDU_setSmpRate(SVPublisher_ASDU self, uint16_t smpRate)
{
SVPublisher_ASDU_setSmpRate(self, smpRate);
}

@ -1,7 +1,7 @@
/*
* sv_receiver.c
*
* Copyright 2015-2022 Michael Zillgith
* Copyright 2015-2024 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -67,7 +67,6 @@ struct sSVReceiver
Semaphore subscriberListLock;
Thread thread;
#endif
};
struct sSVSubscriber
@ -101,7 +100,8 @@ SVReceiver_create(void)
{
SVReceiver self = (SVReceiver) GLOBAL_CALLOC(1, sizeof(struct sSVReceiver));
if (self != NULL) {
if (self)
{
self->subscriberList = LinkedList_create();
self->buffer = (uint8_t*) GLOBAL_MALLOC(ETH_BUFFER_LENGTH);
@ -122,7 +122,8 @@ SVReceiver_createRemote(RSession session)
{
SVReceiver self = (SVReceiver) GLOBAL_CALLOC(1, sizeof(struct sSVReceiver));
if (self != NULL) {
if (self != NULL)
{
self->subscriberList = LinkedList_create();
self->buffer = NULL;
@ -193,6 +194,7 @@ svReceiverLoop(void* threadParameter)
{
SVReceiver self = (SVReceiver) threadParameter;
#if (CONFIG_IEC61850_L2_SMV == 1)
if (self->ethSocket)
{
EthernetHandleSet handleSet = EthernetHandleSet_new();
@ -217,8 +219,10 @@ svReceiverLoop(void* threadParameter)
EthernetHandleSet_destroy(handleSet);
}
#endif /* (CONFIG_IEC61850_L2_SMV == 1) */
#if (CONFIG_IEC61850_R_SMV == 1)
else if (self->session)
if (self->session)
{
self->stopped = false;
@ -349,14 +353,12 @@ SVReceiver_startThreadless(SVReceiver self)
return true;
}
else
{
return false;
}
}
else
{
#endif /* (CONFIG_IEC61850_R_SMV == 1) */
#if (CONFIG_IEC61850_L2_SMV == 1)
if (self->interfaceId == NULL)
self->ethSocket = Ethernet_createSocket(CONFIG_ETHERNET_INTERFACE_ID, NULL);
else
@ -367,22 +369,25 @@ SVReceiver_startThreadless(SVReceiver self)
Ethernet_setProtocolFilter(self->ethSocket, ETH_P_SV);
self->running = true;
}
if (self->ethSocket)
return true;
else
return false;
}
#endif /* (CONFIG_IEC61850_L2_SMV == 1) */
#if (CONFIG_IEC61850_R_SMV == 1)
}
#endif /* (CONFIG_IEC61850_R_SMV == 1) */
return false;
}
void
SVReceiver_stopThreadless(SVReceiver self)
{
#if (CONFIG_IEC61850_L2_SMV == 1)
if (self->ethSocket)
Ethernet_destroySocket(self->ethSocket);
#endif /* (CONFIG_IEC61850_L2_SMV == 1) */
#if (CONFIG_IEC61850_R_SMV == 1)
if (self->session) {
@ -611,35 +616,37 @@ handleSVApdu(SVReceiver self, uint16_t appId, uint8_t* apdu, int apduLength, uin
bool subscriberFound = false;
while (element != NULL) {
while (element)
{
subscriber = (SVSubscriber) LinkedList_getData(element);
if (subscriber->appId == appId) {
if (self->checkDestAddr) {
if (self->ethSocket) {
if (memcmp(dstAddr, subscriber->ethAddr, 6) == 0) {
if (subscriber->appId == appId)
{
if (self->checkDestAddr)
{
if (self->ethSocket)
{
if (memcmp(dstAddr, subscriber->ethAddr, 6) == 0)
{
subscriberFound = true;
break;
}
else
{
if (DEBUG_SV_SUBSCRIBER)
printf("SV_SUBSCRIBER: Checking ethernet dest address failed!\n");
}
else {
}
else
{
//TODO check destination IP address for R-SV
}
}
else {
else
{
subscriberFound = true;
break;
}
}
element = LinkedList_getNext(element);
@ -650,8 +657,11 @@ handleSVApdu(SVReceiver self, uint16_t appId, uint8_t* apdu, int apduLength, uin
#endif
if (subscriberFound)
{
parseSVPayload(self, subscriber, apdu, apduLength);
else {
}
else
{
if (DEBUG_SV_SUBSCRIBER)
printf("SV_SUBSCRIBER: SV message ignored due to unknown APPID value or dest address mismatch\n");
}
@ -710,17 +720,21 @@ parseSVMessage(SVReceiver self, int numbytes)
handleSVApdu(self, appId, buffer + bufPos, apduLength, dstAddr);
}
#if (CONFIG_IEC61850_R_SMV == 1)
static void
handleSessionPayloadElement(void* parameter, uint16_t appId, uint8_t* payloadData, int payloadSize)
{
(void)appId;
SVReceiver self = (SVReceiver) parameter;
handleSVApdu(self, appId, payloadData, payloadSize, NULL);
}
#endif /* (CONFIG_IEC61850_R_SMV == 1) */
bool
SVReceiver_tick(SVReceiver self)
{
#if (CONFIG_IEC61850_L2_SMV == 1)
if (self->ethSocket)
{
int packetSize = Ethernet_receivePacket(self->ethSocket, self->buffer, ETH_BUFFER_LENGTH);
@ -731,8 +745,10 @@ SVReceiver_tick(SVReceiver self)
return true;
}
}
#endif /* (CONFIG_IEC61850_L2_SMV == 1) */
#if (CONFIG_IEC61850_R_SMV == 1)
else if (self->session)
if (self->session)
{
if (RSession_receiveMessage(self->session, handleSessionPayloadElement, (void*) self) == R_SESSION_ERROR_OK)
return true;
@ -747,7 +763,7 @@ SVSubscriber_create(const uint8_t* ethAddr, uint16_t appID)
{
SVSubscriber self = (SVSubscriber) GLOBAL_CALLOC(1, sizeof(struct sSVSubscriber));
if (self != NULL)
if (self)
{
self->appId = appID;
@ -761,7 +777,7 @@ SVSubscriber_create(const uint8_t* ethAddr, uint16_t appID)
void
SVSubscriber_destroy(SVSubscriber self)
{
if (self != NULL)
if (self)
GLOBAL_FREEMEM(self);
}
@ -816,7 +832,7 @@ decodeUtcTimeToNsTime(uint8_t* buffer, uint8_t* timeQuality)
nsVal = nsVal * 1000000000UL;
nsVal = nsVal >> 24;
if (timeQuality != NULL)
if (timeQuality)
*timeQuality = buffer[7];
uint64_t timeval64 = (uint64_t) timeval32 * 1000000000ULL + nsVal;
@ -829,7 +845,7 @@ SVSubscriber_ASDU_getRefrTmAsMs(SVSubscriber_ASDU self)
{
msSinceEpoch msTime = 0;
if (self->refrTm != NULL)
if (self->refrTm)
msTime = decodeUtcTimeToNsTime(self->refrTm, NULL);
return (msTime / 1000000ULL);
@ -840,7 +856,7 @@ SVSubscriber_ASDU_getRefrTmAsNs(SVSubscriber_ASDU self)
{
nsSinceEpoch nsTime = 0;
if (self->refrTm != NULL)
if (self->refrTm)
nsTime = decodeUtcTimeToNsTime(self->refrTm, NULL);
return nsTime;
@ -1083,99 +1099,3 @@ SVSubscriber_ASDU_getDataSize(SVSubscriber_ASDU self)
{
return self->dataBufferLength;
}
uint16_t
SVClientASDU_getSmpCnt(SVSubscriber_ASDU self)
{
return SVSubscriber_ASDU_getSmpCnt(self);
}
const char*
SVClientASDU_getSvId(SVSubscriber_ASDU self)
{
return SVSubscriber_ASDU_getSvId(self);
}
uint32_t
SVClientASDU_getConfRev(SVSubscriber_ASDU self)
{
return SVSubscriber_ASDU_getConfRev(self);
}
bool
SVClientASDU_hasRefrTm(SVSubscriber_ASDU self)
{
return SVSubscriber_ASDU_hasRefrTm(self);
}
uint64_t
SVClientASDU_getRefrTmAsMs(SVSubscriber_ASDU self)
{
return SVSubscriber_ASDU_getRefrTmAsMs(self);
}
int8_t
SVClientASDU_getINT8(SVSubscriber_ASDU self, int index)
{
return SVSubscriber_ASDU_getINT8(self, index);
}
int16_t
SVClientASDU_getINT16(SVSubscriber_ASDU self, int index)
{
return SVSubscriber_ASDU_getINT16(self, index);
}
int32_t
SVClientASDU_getINT32(SVSubscriber_ASDU self, int index)
{
return SVSubscriber_ASDU_getINT32(self, index);
}
int64_t
SVClientASDU_getINT64(SVSubscriber_ASDU self, int index)
{
return SVSubscriber_ASDU_getINT64(self, index);
}
uint8_t
SVClientASDU_getINT8U(SVSubscriber_ASDU self, int index)
{
return SVSubscriber_ASDU_getINT8U(self, index);
}
uint16_t
SVClientASDU_getINT16U(SVSubscriber_ASDU self, int index)
{
return SVSubscriber_ASDU_getINT16U(self, index);
}
uint32_t
SVClientASDU_getINT32U(SVSubscriber_ASDU self, int index)
{
return SVSubscriber_ASDU_getINT32U(self, index);
}
uint64_t
SVClientASDU_getINT64U(SVSubscriber_ASDU self, int index)
{
return SVSubscriber_ASDU_getINT64U(self, index);
}
float
SVClientASDU_getFLOAT32(SVSubscriber_ASDU self, int index)
{
return SVSubscriber_ASDU_getFLOAT32(self, index);
}
double
SVClientASDU_getFLOAT64(SVSubscriber_ASDU self, int index)
{
return SVSubscriber_ASDU_getFLOAT64(self, index);
}
int
SVClientASDU_getDataSize(SVSubscriber_ASDU self)
{
return SVSubscriber_ASDU_getDataSize(self);
}

@ -560,72 +560,7 @@ SVSubscriber_ASDU_getDataSize(SVSubscriber_ASDU self);
uint8_t
SVSubscriber_ASDU_getSmpSynch(SVSubscriber_ASDU self);
#ifndef DEPRECATED
#if defined(__GNUC__) || defined(__clang__)
#define DEPRECATED __attribute__((deprecated))
#else
#define DEPRECATED
#endif
#endif
/**
* \addtogroup sv_subscriber_deprecated_api_group Deprecated API
* \ingroup sv_subscriber_api_group IEC 61850 Sampled Values (SV) publisher API
* \deprecated
* @{
*/
typedef struct sSVSubscriberASDU* SVClientASDU;
LIB61850_API DEPRECATED uint16_t
SVClientASDU_getSmpCnt(SVSubscriber_ASDU self);
LIB61850_API DEPRECATED const char*
SVClientASDU_getSvId(SVSubscriber_ASDU self);
LIB61850_API DEPRECATED uint32_t
SVClientASDU_getConfRev(SVSubscriber_ASDU self);
LIB61850_API DEPRECATED bool
SVClientASDU_hasRefrTm(SVSubscriber_ASDU self);
LIB61850_API DEPRECATED uint64_t
SVClientASDU_getRefrTmAsMs(SVSubscriber_ASDU self);
LIB61850_API DEPRECATED int8_t
SVClientASDU_getINT8(SVSubscriber_ASDU self, int index);
LIB61850_API DEPRECATED int16_t
SVClientASDU_getINT16(SVSubscriber_ASDU self, int index);
LIB61850_API DEPRECATED int32_t
SVClientASDU_getINT32(SVSubscriber_ASDU self, int index);
LIB61850_API DEPRECATED int64_t
SVClientASDU_getINT64(SVSubscriber_ASDU self, int index);
LIB61850_API DEPRECATED uint8_t
SVClientASDU_getINT8U(SVSubscriber_ASDU self, int index);
LIB61850_API DEPRECATED uint16_t
SVClientASDU_getINT16U(SVSubscriber_ASDU self, int index);
LIB61850_API DEPRECATED uint32_t
SVClientASDU_getINT32U(SVSubscriber_ASDU self, int index);
LIB61850_API DEPRECATED uint64_t
SVClientASDU_getINT64U(SVSubscriber_ASDU self, int index);
LIB61850_API DEPRECATED float
SVClientASDU_getFLOAT32(SVSubscriber_ASDU self, int index);
LIB61850_API DEPRECATED double
SVClientASDU_getFLOAT64(SVSubscriber_ASDU self, int index);
LIB61850_API DEPRECATED int
SVClientASDU_getDataSize(SVSubscriber_ASDU self);
/**@} @}*/
/** @}*/
#ifdef __cplusplus
}

@ -37,8 +37,8 @@ typedef struct sSNTPClient* SNTPClient;
/* new time types */
typedef struct {
typedef struct
{
uint32_t coarse;
uint32_t fine;
} NtpTime;
@ -164,7 +164,8 @@ parseResponseMessage(SNTPClient self, uint8_t* buffer, int bufSize)
int li = (header & 0xc0)>> 6;
/* check for "clock-not-synchronized" */
if (li == 3) {
if (li == 3)
{
/* ignore time message */
if (SNTP_DEBUG)
printf("WARNING: received clock-not-synchronized from server\n");
@ -223,7 +224,8 @@ parseResponseMessage(SNTPClient self, uint8_t* buffer, int bufSize)
uint64_t trnsTime = ntpTimeToNsTime(coarse, fine);
/* set system time */
if (Hal_setTimeInNs(trnsTime) == false) {
if (Hal_setTimeInNs(trnsTime) == false)
{
if (SNTP_DEBUG)
printf("SNTP: failed to set system clock!\n");
}
@ -231,11 +233,13 @@ parseResponseMessage(SNTPClient self, uint8_t* buffer, int bufSize)
self->clockSynced = true;
self->outStandingRequest = false;
if (self->userCallback) {
if (self->userCallback)
{
self->userCallback(self->userCallbackParameter, true);
}
if (SNTP_DEBUG) {
if (SNTP_DEBUG)
{
printf("SNTP: reference time: %u.%.6u\n", nsTimeToSeconds(refTime), getUsPartFromNsTime(refTime));
printf("SNTP: original time: %u.%.9u\n", nsTimeToSeconds(origTime), getUsPartFromNsTime(origTime));
printf("SNTP: receive time: %u.%.6u\n", nsTimeToSeconds(recvTime), getUsPartFromNsTime(recvTime));
@ -310,14 +314,17 @@ SNTPClient_create()
{
SNTPClient self = (SNTPClient) GLOBAL_CALLOC(1, sizeof(struct sSNTPClient));
if (self) {
if (self)
{
self->socket = UdpSocket_create();
if (self->socket == NULL) {
if (self->socket == NULL)
{
GLOBAL_FREEMEM(self);
self = NULL;
}
else {
else
{
self->handleSet = Handleset_new();
Handleset_addSocket(self->handleSet, (Socket) self->socket);
self->pollInterval = 30000000000UL; /* 30 s */
@ -351,7 +358,8 @@ SNTPClient_isSynchronized(SNTPClient self)
void
SNTPClient_setUserCallback(SNTPClient self, SNTPClient_UserCallback callback, void* parameter)
{
if (self) {
if (self)
{
self->userCallback = callback;
self->userCallbackParameter = parameter;
}
@ -375,23 +383,28 @@ SNTPClient_tick(SNTPClient self)
if (self->lastRequestTimestamp > now)
self->lastRequestTimestamp = now;
if (self->lastRequestTimestamp > 0) {
if (self->lastRequestTimestamp > 0)
{
/* check for timeout */
if ((now - self->lastReceivedMessage) > 300000000000UL) {
if (self->clockSynced) {
if ((now - self->lastReceivedMessage) > 300000000000UL)
{
if (self->clockSynced)
{
self->clockSynced = false;
printf("SNTP: request timeout\n");
//TODO when to call user handler?
if (self->userCallback) {
if (self->userCallback)
{
self->userCallback(self->userCallbackParameter, false);
}
}
}
}
if (self->serverAddr) {
if ((now - self->lastRequestTimestamp) > self->pollInterval) {
if (self->serverAddr)
{
if ((now - self->lastRequestTimestamp) > self->pollInterval)
{
sendRequestMessage(self, self->serverAddr, self->serverPort);
}
}
@ -405,17 +418,19 @@ SNTPClient_handleIncomingMessage(SNTPClient self)
uint8_t buffer[200];
int rcvdBytes = UdpSocket_receiveFrom(self->socket, ipAddress, 200, buffer, sizeof(buffer));
if (rcvdBytes > 0) {
if (rcvdBytes > 0)
{
if (SNTP_DEBUG)
printf("SNTP: received response from %s\n", ipAddress);
parseResponseMessage(self, buffer, rcvdBytes);
}
else if (rcvdBytes == -1) {
else if (rcvdBytes == -1)
{
printf("UDP socket error\n");
}
else {
else
{
printf("No data!\n");
}
}
@ -442,10 +457,12 @@ handleThread(void* parameter)
void
SNTPClient_start(SNTPClient self)
{
if (self) {
if (self)
{
int sntpPoirt = SNTP_DEFAULT_PORT;
if (UdpSocket_bind(self->socket, "0.0.0.0", SNTP_DEFAULT_PORT)) {
if (UdpSocket_bind(self->socket, "0.0.0.0", SNTP_DEFAULT_PORT))
{
printf("Start NTP thread\n");
self->thread = Thread_create(handleThread, self, false);
@ -453,7 +470,8 @@ SNTPClient_start(SNTPClient self)
if (self->thread)
Thread_start(self->thread);
}
else {
else
{
if (SNTP_DEBUG)
printf("SNTP: Failed to bind to port %i\n", sntpPoirt);
}
@ -463,7 +481,8 @@ SNTPClient_start(SNTPClient self)
void
SNTPClient_stop(SNTPClient self)
{
if (self->thread) {
if (self->thread)
{
self->running = false;
Thread_destroy(self->thread);
self->thread = NULL;
@ -473,16 +492,15 @@ SNTPClient_stop(SNTPClient self)
void
SNTPClient_destroy(SNTPClient self)
{
if (self) {
if (self)
{
SNTPClient_stop(self);
if (self->serverAddr)
GLOBAL_FREEMEM(self->serverAddr);
if (self->socket) {
if (self->socket)
Socket_destroy((Socket) self->socket);
}
GLOBAL_FREEMEM(self);
}

@ -1,9 +1,33 @@
README
------
For TLS support with mbedtls download the source tarball of version 2.28.x and extract here in the subfolder
At the moment libiec61850 provides support for two versions of mbedtls (2.28 and 3.6).
mbedtls version 2.28 support different TLS versions up to TLS 1.2.
mbedtls version 3.6 only support TLS 1.2 and TLS 1.3. Older versions are not supported.
It is recommended that you use version 3.6 unless you need support for older versions of TLS.
mbedtls-2.28
------------
Download the latest source tarball from version 2.27.x and extract it here in the subfolder mbedtls-2.28
After extracting of the archive you may have to rename the folder to match the exact name "mbedtls-2.28". Otherwise the build system will not find the library.
wget https://github.com/Mbed-TLS/mbedtls/archive/refs/tags/v2.28.8.tar.gz
tar xzf v2.28.8.tar.gz
mv mbedtls-2.28.8 mbedtls-2.28
mbedtls-3.6.0
-------------
You just have to download the archive and extract it in this folder.
wget https://github.com/Mbed-TLS/mbedtls/archive/refs/tags/v3.6.0.tar.gz
tar xzf v3.6.0.tar.gz

Loading…
Cancel
Save