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 - Ethernet(Linux): Set to promisc mode by default
- removed legacy defines for report reasons (#449) - removed legacy defines for report reasons (#449)
- removed legacy compatibility functions for SV subscriner ("SVClientaSDU_")
Fixed bugs and vulnerabilities: Fixed bugs and vulnerabilities:
- fixed out-of-bound read in parseAarePdu function (LIB61850-442)(#513) - Vulnerability: fixed potential stack buffer overflow in MMS client identity service and other services (LIB61850-447)
- ACSE: fixed out-of-bounds read in parseAarqPdu function (LIB61850-441)(#512) - 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 - 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) - 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) - 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) - 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 - 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) - 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_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_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_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_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_R_SMV "Build with support for R-SMV (mbedtls required)" ON)
option(CONFIG_IEC61850_SNTP_CLIENT "Build with SNTP client code" 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") 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) 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) if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28)
set(WITH_MBEDTLS 1) set(WITH_MBEDTLS 1)
set(MBEDTLS_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28/include") 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-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) add_definitions(-DCONFIG_MMS_SUPPORT_TLS=1)
@ -163,7 +170,12 @@ if (CONFIG_IEC61850_SNTP_CLIENT)
set(BUILD_SNTP_CLIENT_EXAMPLES 1) set(BUILD_SNTP_CLIENT_EXAMPLES 1)
endif (CONFIG_IEC61850_SNTP_CLIENT) 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) include(CheckCCompilerFlag)

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

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

@ -68,36 +68,20 @@
/* maximum COTP (ISO 8073) TPDU size - valid range is 1024 - 8192 */ /* maximum COTP (ISO 8073) TPDU size - valid range is 1024 - 8192 */
#define CONFIG_COTP_MAX_TPDU_SIZE 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 "eth0"
/* #define CONFIG_ETHERNET_INTERFACE_ID "vboxnet0" */ /* #define CONFIG_ETHERNET_INTERFACE_ID "vboxnet0" */
/* #define CONFIG_ETHERNET_INTERFACE_ID "en0" // OS X uses enX in place of ethX as ethernet NIC names. */ /* #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 #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 #define CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT 1
/* Set to 1 to compile for edition 1 server - default is 0 to compile for edition 2 */ /* Set to 1 to compile for edition 1 server - default is 0 to compile for edition 2 */
#define CONFIG_IEC61850_EDITION_1 0 #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 */ /* The GOOSE retransmission interval in ms for the stable condition - i.e. no monitored value changed */
#define CONFIG_GOOSE_STABLE_STATE_TRANSMISSION_INTERVAL 5000 #define CONFIG_GOOSE_STABLE_STATE_TRANSMISSION_INTERVAL 5000
@ -179,9 +163,36 @@
/* compile with support for R-SMV (mbedtls required) */ /* compile with support for R-SMV (mbedtls required) */
#define CONFIG_IEC61850_R_SMV 0 #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 */ /* compile SNTP client code */
#define CONFIG_IEC61850_SNTP_CLIENT 0 #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 */ /* overwrite default results for MMS identify service */
/* #define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com" */ /* #define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com" */
/* #define CONFIG_DEFAULT_MMS_MODEL_NAME "LIBIEC61850" */ /* #define CONFIG_DEFAULT_MMS_MODEL_NAME "LIBIEC61850" */

@ -68,10 +68,10 @@
/* #define CONFIG_ETHERNET_INTERFACE_ID "vboxnet0" */ /* #define CONFIG_ETHERNET_INTERFACE_ID "vboxnet0" */
/* #define CONFIG_ETHERNET_INTERFACE_ID "en0" // OS X uses enX in place of ethX as ethernet NIC names. */ /* #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 #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 #define CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT 1
/* compile with support for R-GOOSE (mbedtls requried) */ /* compile with support for R-GOOSE (mbedtls requried) */
@ -80,6 +80,12 @@
/* compile with support for R-SMV (mbedtls required) */ /* compile with support for R-SMV (mbedtls required) */
#cmakedefine01 CONFIG_IEC61850_R_SMV #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 */ /* compile SNTP client code */
#cmakedefine01 CONFIG_IEC61850_SNTP_CLIENT #cmakedefine01 CONFIG_IEC61850_SNTP_CLIENT
@ -88,12 +94,16 @@
#ifdef _WIN32 #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 EXCLUDE_ETHERNET_WINDOWS
#ifdef CONFIG_INCLUDE_GOOSE_SUPPORT #ifdef CONFIG_IEC61850_L2_GOOSE
#undef CONFIG_INCLUDE_GOOSE_SUPPORT #undef CONFIG_IEC61850_L2_GOOSE
#endif
#ifdef CONFIG_IEC61850_L2_SMV
#undef CONFIG_IEC61850_L2_SMV
#endif #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 #define CONFIG_INCUDE_ETHERNET_WINDOWS 0
#else #else
#define CONFIG_INCLUDE_ETHERNET_WINDOWS 1 #define CONFIG_INCLUDE_ETHERNET_WINDOWS 1

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

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

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

@ -50,8 +50,8 @@ main(int argc, char** argv)
{ {
RSession rSession = RSession_create(); RSession rSession = RSession_create();
if (rSession) { if (rSession)
{
RSession_setLocalAddress(rSession, "0.0.0.0", 102); RSession_setLocalAddress(rSession, "0.0.0.0", 102);
RSession_addMulticastGroup(rSession, "230.0.10.10"); RSession_addMulticastGroup(rSession, "230.0.10.10");
@ -64,7 +64,8 @@ main(int argc, char** argv)
SVReceiver receiver = SVReceiver_createRemote(rSession); SVReceiver receiver = SVReceiver_createRemote(rSession);
if (receiver) { if (receiver)
{
/* Create a subscriber listening to SV messages with APPID 4000h */ /* Create a subscriber listening to SV messages with APPID 4000h */
SVSubscriber subscriber = SVSubscriber_create(NULL, 0x4000); 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 */ /* Start listening to SV messages - starts a new receiver background thread */
SVReceiver_start(receiver); SVReceiver_start(receiver);
if (SVReceiver_isRunning(receiver)) { if (SVReceiver_isRunning(receiver))
{
signal(SIGINT, sigint_handler); signal(SIGINT, sigint_handler);
while (running) while (running)
@ -86,21 +88,23 @@ main(int argc, char** argv)
/* Stop listening to SV messages */ /* Stop listening to SV messages */
SVReceiver_stop(receiver); 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"); 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 */ /* Cleanup and free resources */
SVReceiver_destroy(receiver); SVReceiver_destroy(receiver);
} }
else { else
{
printf("Failed to create SV receiver\n"); printf("Failed to create SV receiver\n");
} }
RSession_destroy(rSession); RSession_destroy(rSession);
} }
else { else
{
printf("Failed to create remote session protocol\n"); printf("Failed to create remote session protocol\n");
} }
} }

@ -10,7 +10,7 @@ endif()
project(hal) project(hal)
set(LIBHAL_VERSION_MAJOR "2") set(LIBHAL_VERSION_MAJOR "2")
set(LIBHAL_VERSION_MINOR "1") set(LIBHAL_VERSION_MINOR "2")
set(LIBHAL_VERSION_PATCH "0") set(LIBHAL_VERSION_PATCH "0")
# feature checks # feature checks
@ -28,7 +28,7 @@ message("Found winpcap -> compile ethernet HAL layer (required for GOOSE/SV supp
set(WITH_WPCAP 1) set(WITH_WPCAP 1)
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/Include") include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/Include")
else() 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()
endif(WIN32) endif(WIN32)
@ -116,10 +116,15 @@ ENDIF(WIN32)
#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC" ) #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC" )
if(WITH_MBEDTLS) 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) set(WITH_MBEDTLS 1)
endif(WITH_MBEDTLS) 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) if(WITH_MBEDTLS)
include_directories( include_directories(
${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls ${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls
@ -147,6 +152,32 @@ list (APPEND libhal_SRCS ${tls_SRCS})
endif(WITH_MBEDTLS) 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 STATIC ${libhal_SRCS})
add_library (hal-shared STATIC ${libhal_SRCS}) add_library (hal-shared STATIC ${libhal_SRCS})
@ -178,6 +209,11 @@ IF(MINGW)
target_link_libraries(hal ws2_32 iphlpapi) target_link_libraries(hal ws2_32 iphlpapi)
ENDIF(MINGW) ENDIF(MINGW)
IF (MSVC)
target_link_libraries(hal bcrypt)
target_link_libraries(hal-shared bcrypt)
ENDIF()
iF(WITH_WPCAP) iF(WITH_WPCAP)
target_link_libraries(hal target_link_libraries(hal
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/Lib/wpcap.lib ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/Lib/wpcap.lib

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

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

@ -72,7 +72,7 @@ struct sTLSConfiguration {
/* TLS minimum version allowed (default: TLS_VERSION_TLS_1_0) */ /* TLS minimum version allowed (default: TLS_VERSION_TLS_1_0) */
TLSConfigVersion minVersion; TLSConfigVersion minVersion;
/* TLS minimum version allowed (default: TLS_VERSION_TLS_1_2) */ /* TLS maximum version allowed (default: TLS_VERSION_TLS_1_2) */
TLSConfigVersion maxVersion; TLSConfigVersion maxVersion;
TLSConfiguration_EventHandler eventHandler; TLSConfiguration_EventHandler eventHandler;
@ -308,7 +308,7 @@ TLSConfiguration_create()
{ {
TLSConfiguration self = (TLSConfiguration) GLOBAL_CALLOC(1, sizeof(struct sTLSConfiguration)); TLSConfiguration self = (TLSConfiguration) GLOBAL_CALLOC(1, sizeof(struct sTLSConfiguration));
if (self != NULL) if (self)
{ {
mbedtls_ssl_config_init( &(self->conf) ); mbedtls_ssl_config_init( &(self->conf) );
mbedtls_x509_crt_init( &(self->ownCertificate) ); 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) if(WITH_MBEDTLS)
include_directories( include_directories(
${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls ${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls
${CMAKE_CURRENT_LIST_DIR}/../third_party/mbedtls/mbedtls-2.28/include ${CMAKE_CURRENT_LIST_DIR}/../third_party/mbedtls/mbedtls-2.28/include
) )
endif(WITH_MBEDTLS) endif(WITH_MBEDTLS)
endif(WITH_MBEDTLS3)
set (lib_common_SRCS set (lib_common_SRCS
./common/string_map.c ./common/string_map.c
@ -189,7 +196,7 @@ set (lib_sv_SRCS
./sampled_values/sv_publisher.c ./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 set (lib_rsession_SRCS
./r_session/r_session.c ./r_session/r_session.c
./r_session/r_session_crypto_mbedtls.c ./r_session/r_session_crypto_mbedtls.c
@ -220,7 +227,7 @@ set (lib_bsd_SRCS
IF(WIN32) IF(WIN32)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/Lib/wpcap.lib") 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) set(WITH_WPCAP 1)
endif() endif()
@ -232,16 +239,13 @@ set_source_files_properties(${lib_common_SRCS} ${lib_windows_SRCS}
PROPERTIES LANGUAGE CXX) PROPERTIES LANGUAGE CXX)
set_source_files_properties(${lib_rsession_SRCS} set_source_files_properties(${lib_rsession_SRCS}
PROPERTIES LANGUAGE CXX) PROPERTIES LANGUAGE CXX)
ENDIF()
IF(WITH_WPCAP)
IF(MSVC)
set_source_files_properties(${lib_goose_SRCS} set_source_files_properties(${lib_goose_SRCS}
PROPERTIES LANGUAGE CXX) PROPERTIES LANGUAGE CXX)
set_source_files_properties(${lib_sv_SRCS} set_source_files_properties(${lib_sv_SRCS}
PROPERTIES LANGUAGE CXX) PROPERTIES LANGUAGE CXX)
ENDIF() ENDIF()
IF(WITH_WPCAP)
ELSE() ELSE()
add_definitions(-DEXCLUDE_ETHERNET_WINDOWS) add_definitions(-DEXCLUDE_ETHERNET_WINDOWS)
ENDIF() ENDIF()
@ -250,7 +254,7 @@ include_directories(
../third_party/winpcap/include ../third_party/winpcap/include
) )
IF(WITH_WPCAP) IF(WITH_WPCAP OR CONFIG_IEC61850_R_GOOSE OR CONFIG_IEC61850_R_SMV)
set (library_SRCS set (library_SRCS
${lib_common_SRCS} ${lib_common_SRCS}
${lib_asn1c_SRCS} ${lib_asn1c_SRCS}
@ -266,11 +270,10 @@ set (library_SRCS
${lib_common_SRCS} ${lib_common_SRCS}
${lib_asn1c_SRCS} ${lib_asn1c_SRCS}
${lib_windows_SRCS} ${lib_windows_SRCS}
${lib_rsession_SRCS}
${lib_sntp_SRCS} ${lib_sntp_SRCS}
) )
ENDIF(WITH_WPCAP) ENDIF(WITH_WPCAP OR CONFIG_IEC61850_R_GOOSE OR CONFIG_IEC61850_R_SMV)
ELSEIF(UNIX) ELSEIF(UNIX)
IF(APPLE) IF(APPLE)

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

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

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

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

@ -1018,6 +1018,20 @@ MmsValue_printToBuffer(const MmsValue* self, char* buffer, int bufferSize);
LIB61850_API MmsValue* LIB61850_API MmsValue*
MmsValue_decodeMmsData(uint8_t* buffer, int bufPos, int bufferLength, int* endBufPos); 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 * \brief Serialize the MmsValue instance as BER encoded MMS Data element
* *

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

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

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

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

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

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

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

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

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

@ -3,7 +3,7 @@
* *
* Implementation of RSessionCrypto interface using mbedtls * Implementation of RSessionCrypto interface using mbedtls
* *
* Copyright 2013-2023 Michael Zillgith * Copyright 2013-2024 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -25,7 +25,6 @@
#include "mbedtls/cipher.h" #include "mbedtls/cipher.h"
#include "mbedtls/md.h" #include "mbedtls/md.h"
#include "mbedtls/md_internal.h"
#include "mbedtls/platform_util.h" #include "mbedtls/platform_util.h"
#include "mbedtls/gcm.h" #include "mbedtls/gcm.h"
#include "mbedtls/entropy.h" #include "mbedtls/entropy.h"
@ -42,7 +41,7 @@
bool bool
RSessionCrypto_createHMAC(uint8_t* buffer, int bufSize, uint8_t* key, int keySize, uint8_t* hmac, int hmacMaxSize) 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; mbedtls_md_context_t md_ctx;

@ -1,7 +1,7 @@
/* /*
* sv_publisher.c * sv_publisher.c
* *
* Copyright 2016-2022 Michael Zillgith * Copyright 2016-2024 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -76,8 +76,10 @@ struct sSVPublisher {
uint16_t appId; uint16_t appId;
bool simulation; bool simulation;
#if (CONFIG_IEC61850_L2_SMV == 1)
/* only for Ethernet based SV */ /* only for Ethernet based SV */
EthernetSocket ethernetSocket; EthernetSocket ethernetSocket;
#endif /* (CONFIG_IEC61850_L2_SMV == 1) */
#if (CONFIG_IEC61850_R_SMV == 1) #if (CONFIG_IEC61850_R_SMV == 1)
/* only for R-SV */ /* only for R-SV */
@ -93,7 +95,7 @@ struct sSVPublisher {
SVPublisher_ASDU asduList; SVPublisher_ASDU asduList;
}; };
#if (CONFIG_IEC61850_L2_SMV == 1)
static bool static bool
preparePacketBuffer(SVPublisher self, CommParameters* parameters, const char* interfaceId, bool useVlanTags) preparePacketBuffer(SVPublisher self, CommParameters* parameters, const char* interfaceId, bool useVlanTags)
{ {
@ -194,7 +196,7 @@ preparePacketBuffer(SVPublisher self, CommParameters* parameters, const char* in
return true; return true;
} }
#endif /* (CONFIG_IEC61850_L2_SMV == 1) */
static int static int
encodeUInt16FixedSize(uint16_t value, uint8_t* buffer, int bufPos) 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) */ #endif /* (CONFIG_IEC61850_R_SMV == 1) */
#if (CONFIG_IEC61850_L2_SMV == 1)
SVPublisher SVPublisher
SVPublisher_createEx(CommParameters* parameters, const char* interfaceId, bool useVlanTag) 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); return SVPublisher_createEx(parameters, interfaceId, true);
} }
#endif /* (CONFIG_IEC61850_R_SMV == 1) */
SVPublisher_ASDU SVPublisher_ASDU
SVPublisher_addASDU(SVPublisher self, const char* svID, const char* datset, uint32_t confRev) SVPublisher_addASDU(SVPublisher self, const char* svID, const char* datset, uint32_t confRev)
@ -527,21 +531,25 @@ SVPublisher_setupComplete(SVPublisher self)
void void
SVPublisher_publish(SVPublisher self) SVPublisher_publish(SVPublisher self)
{ {
if (DEBUG_SV_PUBLISHER) #if (CONFIG_IEC61850_L2_SMV == 1)
printf("SV_PUBLISHER: send SV message\n"); if (self->ethernetSocket)
{
if (DEBUG_SV_PUBLISHER)
printf("SV_PUBLISHER: send L2 SV message\n");
if (self->ethernetSocket) {
Ethernet_sendPacket(self->ethernetSocket, self->buffer, self->payloadStart + self->payloadLength); Ethernet_sendPacket(self->ethernetSocket, self->buffer, self->payloadStart + self->payloadLength);
} }
#endif /* (CONFIG_IEC61850_L2_SMV == 1) */
#if (CONFIG_IEC61850_R_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); RSession_sendMessage(self->remoteSession, RSESSION_SPDU_ID_SV, self->simulation, self->appId, self->buffer, self->payloadLength);
} }
#endif /* (CONFIG_IEC61850_R_SMV == 1) */ #endif /* (CONFIG_IEC61850_R_SMV == 1) */
else {
if (DEBUG_SV_PUBLISHER)
printf("SV_PUBLISHER: no network layer!\n");
}
} }
void void
@ -549,8 +557,10 @@ SVPublisher_destroy(SVPublisher self)
{ {
if (self) if (self)
{ {
#if (CONFIG_IEC61850_L2_SMV == 1)
if (self->ethernetSocket) if (self->ethernetSocket)
Ethernet_destroySocket(self->ethernetSocket); Ethernet_destroySocket(self->ethernetSocket);
#endif /* (CONFIG_IEC61850_L2_SMV == 1) */
if (self->buffer) if (self->buffer)
GLOBAL_FREEMEM(self->buffer); GLOBAL_FREEMEM(self->buffer);
@ -808,139 +818,3 @@ SVPublisher_ASDU_setSmpSynch(SVPublisher_ASDU self, uint16_t smpSynch)
self->smpSynch = smpSynch; self->smpSynch = smpSynch;
*(self->smpSynchBuf) = self->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 * sv_receiver.c
* *
* Copyright 2015-2022 Michael Zillgith * Copyright 2015-2024 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -67,7 +67,6 @@ struct sSVReceiver
Semaphore subscriberListLock; Semaphore subscriberListLock;
Thread thread; Thread thread;
#endif #endif
}; };
struct sSVSubscriber struct sSVSubscriber
@ -101,7 +100,8 @@ SVReceiver_create(void)
{ {
SVReceiver self = (SVReceiver) GLOBAL_CALLOC(1, sizeof(struct sSVReceiver)); SVReceiver self = (SVReceiver) GLOBAL_CALLOC(1, sizeof(struct sSVReceiver));
if (self != NULL) { if (self)
{
self->subscriberList = LinkedList_create(); self->subscriberList = LinkedList_create();
self->buffer = (uint8_t*) GLOBAL_MALLOC(ETH_BUFFER_LENGTH); 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)); SVReceiver self = (SVReceiver) GLOBAL_CALLOC(1, sizeof(struct sSVReceiver));
if (self != NULL) { if (self != NULL)
{
self->subscriberList = LinkedList_create(); self->subscriberList = LinkedList_create();
self->buffer = NULL; self->buffer = NULL;
@ -193,6 +194,7 @@ svReceiverLoop(void* threadParameter)
{ {
SVReceiver self = (SVReceiver) threadParameter; SVReceiver self = (SVReceiver) threadParameter;
#if (CONFIG_IEC61850_L2_SMV == 1)
if (self->ethSocket) if (self->ethSocket)
{ {
EthernetHandleSet handleSet = EthernetHandleSet_new(); EthernetHandleSet handleSet = EthernetHandleSet_new();
@ -217,8 +219,10 @@ svReceiverLoop(void* threadParameter)
EthernetHandleSet_destroy(handleSet); EthernetHandleSet_destroy(handleSet);
} }
#endif /* (CONFIG_IEC61850_L2_SMV == 1) */
#if (CONFIG_IEC61850_R_SMV == 1) #if (CONFIG_IEC61850_R_SMV == 1)
else if (self->session) if (self->session)
{ {
self->stopped = false; self->stopped = false;
@ -349,14 +353,12 @@ SVReceiver_startThreadless(SVReceiver self)
return true; return true;
} }
else
{
return false;
}
} }
else else
{ {
#endif /* (CONFIG_IEC61850_R_SMV == 1) */ #endif /* (CONFIG_IEC61850_R_SMV == 1) */
#if (CONFIG_IEC61850_L2_SMV == 1)
if (self->interfaceId == NULL) if (self->interfaceId == NULL)
self->ethSocket = Ethernet_createSocket(CONFIG_ETHERNET_INTERFACE_ID, NULL); self->ethSocket = Ethernet_createSocket(CONFIG_ETHERNET_INTERFACE_ID, NULL);
else else
@ -367,22 +369,25 @@ SVReceiver_startThreadless(SVReceiver self)
Ethernet_setProtocolFilter(self->ethSocket, ETH_P_SV); Ethernet_setProtocolFilter(self->ethSocket, ETH_P_SV);
self->running = true; self->running = true;
}
if (self->ethSocket)
return true; return true;
else }
return false; #endif /* (CONFIG_IEC61850_L2_SMV == 1) */
#if (CONFIG_IEC61850_R_SMV == 1) #if (CONFIG_IEC61850_R_SMV == 1)
} }
#endif /* (CONFIG_IEC61850_R_SMV == 1) */ #endif /* (CONFIG_IEC61850_R_SMV == 1) */
return false;
} }
void void
SVReceiver_stopThreadless(SVReceiver self) SVReceiver_stopThreadless(SVReceiver self)
{ {
#if (CONFIG_IEC61850_L2_SMV == 1)
if (self->ethSocket) if (self->ethSocket)
Ethernet_destroySocket(self->ethSocket); Ethernet_destroySocket(self->ethSocket);
#endif /* (CONFIG_IEC61850_L2_SMV == 1) */
#if (CONFIG_IEC61850_R_SMV == 1) #if (CONFIG_IEC61850_R_SMV == 1)
if (self->session) { if (self->session) {
@ -611,35 +616,37 @@ handleSVApdu(SVReceiver self, uint16_t appId, uint8_t* apdu, int apduLength, uin
bool subscriberFound = false; bool subscriberFound = false;
while (element != NULL) { while (element)
{
subscriber = (SVSubscriber) LinkedList_getData(element); subscriber = (SVSubscriber) LinkedList_getData(element);
if (subscriber->appId == appId) { if (subscriber->appId == appId)
{
if (self->checkDestAddr)
if (self->checkDestAddr) { {
if (self->ethSocket)
if (self->ethSocket) { {
if (memcmp(dstAddr, subscriber->ethAddr, 6) == 0) { if (memcmp(dstAddr, subscriber->ethAddr, 6) == 0)
{
subscriberFound = true; subscriberFound = true;
break; break;
} }
else else
{
if (DEBUG_SV_SUBSCRIBER) if (DEBUG_SV_SUBSCRIBER)
printf("SV_SUBSCRIBER: Checking ethernet dest address failed!\n"); printf("SV_SUBSCRIBER: Checking ethernet dest address failed!\n");
}
} }
else { else
{
//TODO check destination IP address for R-SV //TODO check destination IP address for R-SV
} }
} }
else { else
{
subscriberFound = true; subscriberFound = true;
break; break;
} }
} }
element = LinkedList_getNext(element); element = LinkedList_getNext(element);
@ -650,8 +657,11 @@ handleSVApdu(SVReceiver self, uint16_t appId, uint8_t* apdu, int apduLength, uin
#endif #endif
if (subscriberFound) if (subscriberFound)
{
parseSVPayload(self, subscriber, apdu, apduLength); parseSVPayload(self, subscriber, apdu, apduLength);
else { }
else
{
if (DEBUG_SV_SUBSCRIBER) if (DEBUG_SV_SUBSCRIBER)
printf("SV_SUBSCRIBER: SV message ignored due to unknown APPID value or dest address mismatch\n"); 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); handleSVApdu(self, appId, buffer + bufPos, apduLength, dstAddr);
} }
#if (CONFIG_IEC61850_R_SMV == 1)
static void static void
handleSessionPayloadElement(void* parameter, uint16_t appId, uint8_t* payloadData, int payloadSize) handleSessionPayloadElement(void* parameter, uint16_t appId, uint8_t* payloadData, int payloadSize)
{ {
(void)appId;
SVReceiver self = (SVReceiver) parameter; SVReceiver self = (SVReceiver) parameter;
handleSVApdu(self, appId, payloadData, payloadSize, NULL); handleSVApdu(self, appId, payloadData, payloadSize, NULL);
} }
#endif /* (CONFIG_IEC61850_R_SMV == 1) */
bool bool
SVReceiver_tick(SVReceiver self) SVReceiver_tick(SVReceiver self)
{ {
#if (CONFIG_IEC61850_L2_SMV == 1)
if (self->ethSocket) if (self->ethSocket)
{ {
int packetSize = Ethernet_receivePacket(self->ethSocket, self->buffer, ETH_BUFFER_LENGTH); int packetSize = Ethernet_receivePacket(self->ethSocket, self->buffer, ETH_BUFFER_LENGTH);
@ -731,8 +745,10 @@ SVReceiver_tick(SVReceiver self)
return true; return true;
} }
} }
#endif /* (CONFIG_IEC61850_L2_SMV == 1) */
#if (CONFIG_IEC61850_R_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) if (RSession_receiveMessage(self->session, handleSessionPayloadElement, (void*) self) == R_SESSION_ERROR_OK)
return true; return true;
@ -747,7 +763,7 @@ SVSubscriber_create(const uint8_t* ethAddr, uint16_t appID)
{ {
SVSubscriber self = (SVSubscriber) GLOBAL_CALLOC(1, sizeof(struct sSVSubscriber)); SVSubscriber self = (SVSubscriber) GLOBAL_CALLOC(1, sizeof(struct sSVSubscriber));
if (self != NULL) if (self)
{ {
self->appId = appID; self->appId = appID;
@ -761,7 +777,7 @@ SVSubscriber_create(const uint8_t* ethAddr, uint16_t appID)
void void
SVSubscriber_destroy(SVSubscriber self) SVSubscriber_destroy(SVSubscriber self)
{ {
if (self != NULL) if (self)
GLOBAL_FREEMEM(self); GLOBAL_FREEMEM(self);
} }
@ -816,7 +832,7 @@ decodeUtcTimeToNsTime(uint8_t* buffer, uint8_t* timeQuality)
nsVal = nsVal * 1000000000UL; nsVal = nsVal * 1000000000UL;
nsVal = nsVal >> 24; nsVal = nsVal >> 24;
if (timeQuality != NULL) if (timeQuality)
*timeQuality = buffer[7]; *timeQuality = buffer[7];
uint64_t timeval64 = (uint64_t) timeval32 * 1000000000ULL + nsVal; uint64_t timeval64 = (uint64_t) timeval32 * 1000000000ULL + nsVal;
@ -829,7 +845,7 @@ SVSubscriber_ASDU_getRefrTmAsMs(SVSubscriber_ASDU self)
{ {
msSinceEpoch msTime = 0; msSinceEpoch msTime = 0;
if (self->refrTm != NULL) if (self->refrTm)
msTime = decodeUtcTimeToNsTime(self->refrTm, NULL); msTime = decodeUtcTimeToNsTime(self->refrTm, NULL);
return (msTime / 1000000ULL); return (msTime / 1000000ULL);
@ -840,7 +856,7 @@ SVSubscriber_ASDU_getRefrTmAsNs(SVSubscriber_ASDU self)
{ {
nsSinceEpoch nsTime = 0; nsSinceEpoch nsTime = 0;
if (self->refrTm != NULL) if (self->refrTm)
nsTime = decodeUtcTimeToNsTime(self->refrTm, NULL); nsTime = decodeUtcTimeToNsTime(self->refrTm, NULL);
return nsTime; return nsTime;
@ -1083,99 +1099,3 @@ SVSubscriber_ASDU_getDataSize(SVSubscriber_ASDU self)
{ {
return self->dataBufferLength; 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 uint8_t
SVSubscriber_ASDU_getSmpSynch(SVSubscriber_ASDU self); 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 #ifdef __cplusplus
} }

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

@ -1,9 +1,33 @@
README 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 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. 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