Compare commits

...

24 Commits
v1.5.3 ... v1.5

Author SHA1 Message Date
Michael Zillgith 24b5e28904 Merge remote-tracking branch 'origin/v1.5' into v1.5 12 months ago
Michael Zillgith 2fc6dc32d1 - fixed problem when compiling with dynamically linked mbedtls (LIB61850-458) 12 months ago
Michael Zillgith 09c57e15f4
Update codeql-analysis.yml to action v2 1 year ago
Michael Zillgith 7d4614ad54 - ACSE: fixed out-of-bound read in parseAarqPdu/parseAarePdu functions (#512)(#513)(LIB61850-441)(LIB61850-442) 1 year ago
Michael Zillgith c62287c7c3 - fixed out-of-bound read in parseAarePdu function (LIB61850-442)(#513) 1 year ago
Michael Zillgith a49d0cc78b - GOOSE receiver: added additional length and plausibility checks to fix #509 1 year ago
Michael Zillgith fd820643c5 - fixed memory leak in IedConnection_setLocalAddress (I6LLCV-97) 1 year ago
Michael Zillgith 3bc94bf1bd - fixed potential buffer overflows in MMS client file service handling (LIB61850-449) 1 year ago
Michael Zillgith 3c29e85b00 Merge branch 'v1.5_develop_416' into v1.5 1 year ago
Maxson Ramon dos Anjos Medeiros 193b8bf054 -added function to set the number of outstanding calls-
IedConnection_setMaxOutstandingCalls (LIB61850-433)
1 year ago
Michael Zillgith 0f2443a2fa - IED connection: Fixed memory leak and memory handling problem in function IedConnection_readDataSetValuesAsync (LIB61850-439) 1 year ago
Michael Zillgith 7afa40390b - ACSE: added check for minimum message size (LIB61850-438) 1 year ago
Michael Zillgith a66e07deae - MMS server: fixed - server is sending data set response larger than negotiated MMS PDU size (LIB61850-435) 1 year ago
Michael Zillgith 681d1b0e05 - .NET API: fixed - crash when GetDataSetDirectoryAsync returns error
(LIB61850-434)
1 year ago
Michael Zillgith 249df0176a - fixed potential memory leak when GooseReceiver is immediately stopped after start (I6PLLCV-71) 1 year ago
Michael Zillgith cdd0684ffb - fixed - potential race condition when using IedConnection_installReportHandler and IedConnection_uninstallReportHandler 2 years ago
Michael Zillgith d6c53b1569 - IedServer: fixed crash when client tries to write complete SGCB structure 2 years ago
Michael Zillgith 76e016f59d - IedConnection: fixed potential memory leak in getDataSetHandlerInternal 2 years ago
Michael Zillgith 2823184077 - fixed - null pointer dereference in mmsServer_handleDeleteNamedVariableListRequest when receiving malformed message (LIB61850-430) 2 years ago
Michael Zillgith 5b350102de - fixed compilation problem when MMS_FILE_SERVICE is not set 2 years ago
Michael Zillgith 8c0a75cee9 - Java tools: Support for time stamp Val elements (updated binary) 2 years ago
Michael Zillgith 7442c8da53 Merge branch 'v1.5' of bitbucket.com:mz-automation/libiec61850 into v1.5 2 years ago
Michael Zillgith 41e1ddd308 - Java tools: Support for time stamp Val elements 2 years ago
Michael Zillgith 6f96104a09 - replaced select by poll in linux hal (LIB61850-416)(#463) 2 years ago

@ -43,7 +43,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@ -54,7 +54,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@ -68,4 +68,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2

@ -243,10 +243,24 @@
/* enable to configure MmsServer at runtime */
#define CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME 1
/* Define the default number of the maximum outstanding calls allowed by the caller (client) */
#define CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING 5
/* Define the default number of the maximum outstanding calls allowed by the calling endpoint (server) */
#define CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED 5
/************************************************************************************
* Check configuration for consistency - DO NOT MODIFY THIS PART!
************************************************************************************/
#if (CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING < 1)
#error "Invalid configuration: CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING must be greater than 0!"
#endif
#if (CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED < 1)
#error "Invalid configuration: CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED must be greater than 0!"
#endif
#if (MMS_JOURNAL_SERVICE != 1)
#if (CONFIG_IEC61850_LOG_SERVICE == 1)

@ -232,10 +232,24 @@
/* enable to configure MmsServer at runtime */
#define CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME 1
/* Define the default number of the maximum outstanding calls allowed by the caller (client) */
#define CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING 5
/* Define the default number of the maximum outstanding calls allowed by the calling endpoint (server) */
#define CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED 5
/************************************************************************************
* Check configuration for consistency - DO NOT MODIFY THIS PART!
************************************************************************************/
#if (CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING < 1)
#error "Invalid configuration: CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING must be greater than 0!"
#endif
#if (CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED < 1)
#error "Invalid configuration: CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED must be greater than 0!"
#endif
#if (MMS_JOURNAL_SERVICE != 1)
#if (CONFIG_IEC61850_LOG_SERVICE == 1)

@ -431,6 +431,9 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern UInt32 IedConnection_getRequestTimeout(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedConnection_setMaxOutstandingCalls(IntPtr self, int calling, int called);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedConnection_setTimeQuality(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool leapSecondKnown, [MarshalAs(UnmanagedType.I1)] bool clockFailure, [MarshalAs(UnmanagedType.I1)] bool clockNotSynchronized, int subsecondPrecision);
@ -815,6 +818,16 @@ namespace IEC61850
}
}
/// <summary>
/// Set the maximum number outstanding calls allowed for this connection
/// </summary>
/// <param name="calling">the maximum outstanding calls allowed by the caller (client)</param>
/// <param name="called">the maximum outstanding calls allowed by the called endpoint (server)</param>
public void SetMaxOutstandingCalls(int calling, int called)
{
IedConnection_setMaxOutstandingCalls(connection, calling, called);
}
/// <summary>
/// Gets or sets the maximum size if a PDU (has to be set before calling connect!).
/// </summary>
@ -1175,6 +1188,9 @@ namespace IEC61850
private static List<MmsJournalEntry> WrapNativeLogQueryResult(IntPtr linkedList)
{
if (linkedList == IntPtr.Zero)
return null;
List<MmsJournalEntry> journalEntries = new List<MmsJournalEntry>();
IntPtr element = LinkedList_getNext(linkedList);
@ -2238,11 +2254,15 @@ namespace IEC61850
GetDataSetDirectoryHandler handler = callbackInfo.Item1;
object handlerParameter = callbackInfo.Item2;
IntPtr element = LinkedList_getNext(dataSetDirectory);
handle.Free();
List<string> newList = new List<string>();
List<string> newList = null;
if (dataSetDirectory != IntPtr.Zero)
{
newList = new List<string>();
IntPtr element = LinkedList_getNext(dataSetDirectory);
while (element != IntPtr.Zero)
{
@ -2254,6 +2274,7 @@ namespace IEC61850
}
LinkedList_destroy(dataSetDirectory);
}
handler.Invoke(invokeId, handlerParameter, (IedClientError)err, newList, isDeletable);
}
@ -2428,11 +2449,9 @@ namespace IEC61850
dataSet = new DataSet(nativeDataSet);
}
handler(invokeId, handlerParameter, clientError, dataSet);
}
public delegate void ReadDataSetHandler(UInt32 invokeId,object parameter,IedClientError err,DataSet dataSet);
/// <summary>
@ -2566,7 +2585,6 @@ namespace IEC61850
{
handler(invokeId, handlerParameter, clientError, null, moreFollows);
}
}
/// <summary>
@ -2632,7 +2650,6 @@ namespace IEC61850
return GetLogicalDeviceDataSetsAsync(null, ldName, continueAfter, handler, parameter);
}
public UInt32 GetLogicalDeviceDataSetsAsync(List<string> result, string ldName, string continueAfter, GetNameListHandler handler, object parameter)
{
int error;

@ -130,9 +130,8 @@ 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-2.28/library/*.c)
endif(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB)
add_definitions(-DMBEDTLS_CONFIG_FILE="mbedtls_config.h")
endif(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB)
set (libhal_SRCS ${libhal_SRCS}
${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls/tls_mbedtls.c

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

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

@ -662,10 +662,12 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength)
uint32_t numberOfDatSetEntries = 0;
if (buffer[bufPos++] == 0x61) {
if (buffer[bufPos++] == 0x61)
{
int gooseLength;
bufPos = BerDecoder_decodeLength(buffer, &gooseLength, bufPos, apduLength);
if (bufPos < 0) {
if (bufPos < 0)
{
if (DEBUG_GOOSE_SUBSCRIBER)
printf("GOOSE_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n");
return 0;
@ -673,12 +675,14 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength)
int gooseEnd = bufPos + gooseLength;
while (bufPos < gooseEnd) {
while (bufPos < gooseEnd)
{
int elementLength;
uint8_t tag = buffer[bufPos++];
bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, apduLength);
if (bufPos < 0) {
if (bufPos < 0)
{
if (DEBUG_GOOSE_SUBSCRIBER)
printf("GOOSE_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n");
return 0;
@ -696,7 +700,8 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength)
{
LinkedList element = LinkedList_getNext(self->subscriberList);
while (element != NULL) {
while (element)
{
GooseSubscriber subscriber = (GooseSubscriber) LinkedList_getData(element);
if (subscriber->isObserver)
@ -713,8 +718,10 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength)
matchingSubscriber = subscriber;
break;
}
else if (subscriber->goCBRefLen == elementLength) {
if (memcmp(subscriber->goCBRef, buffer + bufPos, elementLength) == 0) {
else if (subscriber->goCBRefLen == elementLength)
{
if (memcmp(subscriber->goCBRef, buffer + bufPos, elementLength) == 0)
{
if (DEBUG_GOOSE_SUBSCRIBER)
printf("GOOSE_SUBSCRIBER: gocbRef is matching!\n");
matchingSubscriber = subscriber;
@ -832,15 +839,17 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength)
bufPos += elementLength;
}
if (matchingSubscriber != NULL) {
if (matchingSubscriber != NULL)
{
matchingSubscriber->timeAllowedToLive = timeAllowedToLive;
matchingSubscriber->ndsCom = ndsCom;
matchingSubscriber->simulation = simulation;
if (matchingSubscriber->dataSetValuesSelfAllocated) {
if (matchingSubscriber->dataSetValuesSelfAllocated)
{
/* when confRev changed replaced old data set */
if ((matchingSubscriber->dataSetValues != NULL) && (matchingSubscriber->confRev != confRev)) {
if ((matchingSubscriber->dataSetValues != NULL) && (matchingSubscriber->confRev != confRev))
{
MmsValue_delete(matchingSubscriber->dataSetValues);
matchingSubscriber->dataSetValues = NULL;
}
@ -866,7 +875,8 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength)
if (matchingSubscriber->dataSetValues == NULL)
matchingSubscriber->dataSetValues = parseAllDataUnknownValue(matchingSubscriber, dataSetBufferAddress, dataSetBufferLength, false);
else {
else
{
GooseParseError parseError = parseAllData(dataSetBufferAddress, dataSetBufferLength, matchingSubscriber->dataSetValues);
if (parseError != GOOSE_PARSE_ERROR_NO_ERROR) {
@ -876,7 +886,8 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength)
matchingSubscriber->parseError = parseError;
}
if (matchingSubscriber->stNum == stNum) {
if (matchingSubscriber->stNum == stNum)
{
if (matchingSubscriber->sqNum >= sqNum) {
isValid = false;
}
@ -920,13 +931,18 @@ parseGooseMessage(GooseReceiver self, uint8_t* buffer, int numbytes)
uint8_t priority = 0;
uint16_t vlanId = 0;
bool vlanSet = false;
/* check for VLAN tag */
if ((buffer[bufPos] == 0x81) && (buffer[bufPos + 1] == 0x00)) {
if ((buffer[bufPos] == 0x81) && (buffer[bufPos + 1] == 0x00))
{
priority = buffer[bufPos + 2] & 0xF8 >> 5;
vlanId = ((buffer[bufPos + 2] & 0x07) << 8) + buffer[bufPos + 3];
vlanSet = true;
bufPos += 4; /* skip VLAN tag */
headerLength += 4;
if (numbytes < (22 + 4))
return;
}
/* check for GOOSE Ethertype */
@ -956,13 +972,22 @@ parseGooseMessage(GooseReceiver self, uint8_t* buffer, int numbytes)
int apduLength = length - 8;
if (numbytes < length + headerLength) {
if (apduLength < 0)
{
if (DEBUG_GOOSE_SUBSCRIBER)
printf("GOOSE_SUBSCRIBER: Invalid length field\n");
return;
}
if (numbytes < length + headerLength)
{
if (DEBUG_GOOSE_SUBSCRIBER)
printf("GOOSE_SUBSCRIBER: Invalid PDU size\n");
return;
}
if (DEBUG_GOOSE_SUBSCRIBER) {
if (DEBUG_GOOSE_SUBSCRIBER)
{
printf("GOOSE_SUBSCRIBER: GOOSE message:\nGOOSE_SUBSCRIBER: ----------------\n");
printf("GOOSE_SUBSCRIBER: DST-MAC: %02x:%02x:%02x:%02x:%02X:%02X\n",
dstMac[0], dstMac[1], dstMac[2], dstMac[3], dstMac[4], dstMac[5]);
@ -974,7 +999,8 @@ parseGooseMessage(GooseReceiver self, uint8_t* buffer, int numbytes)
/* check if there is an interested subscriber */
LinkedList element = LinkedList_getNext(self->subscriberList);
while (element != NULL) {
while (element)
{
GooseSubscriber subscriber = (GooseSubscriber) LinkedList_getData(element);
if (subscriber->isObserver)
@ -990,7 +1016,8 @@ parseGooseMessage(GooseReceiver self, uint8_t* buffer, int numbytes)
}
if (((subscriber->appId == -1) || (subscriber->appId == appId)) &&
(!subscriber->dstMacSet || (memcmp(subscriber->dstMac, dstMac,6) == 0))) {
(!subscriber->dstMacSet || (memcmp(subscriber->dstMac, dstMac,6) == 0)))
{
subscriberFound = true;
break;
}
@ -1014,9 +1041,12 @@ gooseReceiverLoop(void *threadParameter)
EthernetHandleSet handleSet = EthernetHandleSet_new();
EthernetHandleSet_addSocket(handleSet, self->ethSocket);
if (self->running) {
bool running = true;
while (self->running) {
if (running)
{
while (running)
{
switch (EthernetHandleSet_waitReady(handleSet, 100))
{
case -1:
@ -1030,6 +1060,8 @@ gooseReceiverLoop(void *threadParameter)
}
if (self->stop)
break;
running = self->running;
}
GooseReceiver_stopThreadless(self);
@ -1046,7 +1078,8 @@ void
GooseReceiver_start(GooseReceiver self)
{
#if (CONFIG_MMS_THREADLESS_STACK == 0)
if (GooseReceiver_startThreadless(self)) {
if (GooseReceiver_startThreadless(self))
{
self->thread = Thread_create((ThreadExecutionFunction) gooseReceiverLoop, (void*) self, false);
if (self->thread != NULL) {

@ -3,7 +3,7 @@
*
* Client implementation for IEC 61850 reporting.
*
* Copyright 2013-2022 Michael Zillgith
* Copyright 2013-2024 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -283,14 +283,27 @@ lookupReportHandler(IedConnection self, const char* rcbReference)
return NULL;
}
static void
uninstallReportHandler(IedConnection self, const char* rcbReference)
{
ClientReport report = lookupReportHandler(self, rcbReference);
if (report != NULL) {
LinkedList_remove(self->enabledReports, report);
ClientReport_destroy(report);
}
}
void
IedConnection_installReportHandler(IedConnection self, const char* rcbReference, const char* rptId, ReportCallbackFunction handler,
void* handlerParameter)
{
Semaphore_wait(self->reportHandlerMutex);
ClientReport report = lookupReportHandler(self, rcbReference);
if (report != NULL) {
IedConnection_uninstallReportHandler(self, rcbReference);
uninstallReportHandler(self, rcbReference);
if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: Removed existing report callback handler for %s\n", rcbReference);
@ -306,8 +319,8 @@ IedConnection_installReportHandler(IedConnection self, const char* rcbReference,
else
report->rptId = NULL;
Semaphore_wait(self->reportHandlerMutex);
LinkedList_add(self->enabledReports, report);
Semaphore_post(self->reportHandlerMutex);
if (DEBUG_IED_CLIENT)
@ -319,12 +332,7 @@ IedConnection_uninstallReportHandler(IedConnection self, const char* rcbReferenc
{
Semaphore_wait(self->reportHandlerMutex);
ClientReport report = lookupReportHandler(self, rcbReference);
if (report != NULL) {
LinkedList_remove(self->enabledReports, report);
ClientReport_destroy(report);
}
uninstallReportHandler(self, rcbReference);
Semaphore_post(self->reportHandlerMutex);
}
@ -367,6 +375,8 @@ IedConnection_triggerGIReport(IedConnection self, IedClientError* error, const c
void
iedConnection_handleReport(IedConnection self, MmsValue* value)
{
Semaphore_wait(self->reportHandlerMutex);
MmsValue* rptIdValue = MmsValue_getElement(value, 0);
if ((rptIdValue == NULL) || (MmsValue_getType(rptIdValue) != MMS_VISIBLE_STRING)) {
@ -770,14 +780,13 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
}
}
Semaphore_wait(self->reportHandlerMutex);
if (matchingReport->callback != NULL)
matchingReport->callback(matchingReport->callbackParameter, matchingReport);
exit_function:
Semaphore_post(self->reportHandlerMutex);
exit_function:
return;
}

@ -33,7 +33,6 @@
#define DEFAULT_CONNECTION_TIMEOUT 10000
#define DATA_SET_MAX_NAME_LENGTH 64 /* is 32 according to standard! */
#define OUTSTANDING_CALLS 12
typedef struct sICLogicalDevice
{
@ -174,8 +173,10 @@ iedConnection_allocateOutstandingCall(IedConnection self)
int i = 0;
for (i = 0; i < OUTSTANDING_CALLS; i++) {
if (self->outstandingCalls[i].used == false) {
for (i = 0; i < self->maxOutstandingCalled; i++)
{
if (self->outstandingCalls[i].used == false)
{
self->outstandingCalls[i].used = true;
call = &(self->outstandingCalls[i]);
break;
@ -206,8 +207,10 @@ iedConnection_lookupOutstandingCall(IedConnection self, uint32_t invokeId)
int i = 0;
for (i = 0; i < OUTSTANDING_CALLS; i++) {
if ((self->outstandingCalls[i].used) && (self->outstandingCalls[i].invokeId == invokeId)) {
for (i = 0; i < self->maxOutstandingCalled; i++)
{
if ((self->outstandingCalls[i].used) && (self->outstandingCalls[i].invokeId == invokeId))
{
call = &(self->outstandingCalls[i]);
break;
}
@ -615,7 +618,8 @@ createNewConnectionObject(TLSConfiguration tlsConfig, bool useThreads)
self->reportHandlerMutex = Semaphore_create(1);
self->outstandingCallsLock = Semaphore_create(1);
self->outstandingCalls = (IedConnectionOutstandingCall) GLOBAL_CALLOC(OUTSTANDING_CALLS, sizeof(struct sIedConnectionOutstandingCall));
self->maxOutstandingCalled = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED;
self->outstandingCalls = (IedConnectionOutstandingCall) GLOBAL_CALLOC(CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED, sizeof(struct sIedConnectionOutstandingCall));
self->connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
@ -660,6 +664,29 @@ IedConnection_setLocalAddress(IedConnection self, const char* localIpAddress, in
IsoConnectionParameters_setLocalTcpParameters(isoP, localIpAddress, localPort);
}
void
IedConnection_setMaxOutstandingCalls(IedConnection self, int calling, int called)
{
if (calling < 1)
calling = 1;
if (called < 1)
called = 1;
if (self->outstandingCalls)
{
GLOBAL_FREEMEM(self->outstandingCalls);
}
self->maxOutstandingCalled = called;
self->outstandingCalls = (IedConnectionOutstandingCall)GLOBAL_CALLOC(called, sizeof(struct sIedConnectionOutstandingCall));
if (self->connection)
{
MmsConnnection_setMaxOutstandingCalls(self->connection, calling, called);
}
}
void
IedConnection_setConnectTimeout(IedConnection self, uint32_t timeoutInMs)
{
@ -669,7 +696,8 @@ IedConnection_setConnectTimeout(IedConnection self, uint32_t timeoutInMs)
void
IedConnection_setRequestTimeout(IedConnection self, uint32_t timeoutInMs)
{
if (self->connection) {
if (self->connection)
{
MmsConnection_setRequestTimeout(self->connection, timeoutInMs);
}
}
@ -3703,27 +3731,30 @@ getDataSetHandlerInternal(uint32_t invokeId, void* parameter, MmsError err, MmsV
IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId);
if (call) {
if (call)
{
IedConnection_ReadDataSetHandler handler = (IedConnection_ReadDataSetHandler) call->callback;
ClientDataSet dataSet = (ClientDataSet) call->specificParameter;
char* dataSetReference = (char*) call->specificParameter2.pointer;
if (value != NULL) {
if (value)
{
if (dataSet == NULL) {
dataSet = ClientDataSet_create(dataSetReference);
ClientDataSet_setDataSetValues(dataSet, value);
GLOBAL_FREEMEM(dataSetReference);
ClientDataSet_setDataSetValues(dataSet, MmsValue_clone(value));
}
else {
MmsValue* dataSetValues = ClientDataSet_getValues(dataSet);
MmsValue_update(dataSetValues, value);
MmsValue_delete(value);
}
MmsValue_delete(value);
}
if (dataSetReference)
GLOBAL_FREEMEM(dataSetReference);
handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(err), dataSet);
iedConnection_releaseOutstandingCall(self, call);

@ -1,7 +1,7 @@
/*
* iec61850_client.h
*
* Copyright 2013-2021 Michael Zillgith
* Copyright 2013-2023 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -255,6 +255,16 @@ IedConnection_setLocalAddress(IedConnection self, const char* localIpAddress, in
LIB61850_API void
IedConnection_setConnectTimeout(IedConnection self, uint32_t timeoutInMs);
/**
* \brief Set the maximum number outstanding calls allowed for this connection
*
* \param self the connection object
* \param calling the maximum outstanding calls allowed by the caller (client)
* \param called the maximum outstanding calls allowed by the called endpoint (server)
*/
LIB61850_API void
IedConnection_setMaxOutstandingCalls(IedConnection self, int calling, int called);
/**
* \brief set the request timeout in ms
*
@ -1256,9 +1266,11 @@ typedef void (*ReportCallbackFunction) (void* parameter, ClientReport report);
* Otherwise the internal data structures storing the received data set values will not be updated
* correctly.
*
* When replacing a report handler you only have to call this function. There is no separate call to
* \note Replacing a report handler you only have to call this function. There is no separate call to
* IedConnection_uninstallReportHandler() required.
*
* \note Do not call this function inside of the ReportCallbackFunction. Doing so will cause a deadlock.
*
* \param self the connection object
* \param rcbReference object reference of the report control block
* \param rptId a string that identifies the report. If the rptId is not available then the
@ -1273,6 +1285,8 @@ IedConnection_installReportHandler(IedConnection self, const char* rcbReference,
/**
* \brief uninstall a report handler function for the specified report control block (RCB)
*
* \note Do not call this function inside of the ReportCallbackFunction. Doing so will cause a deadlock.
*
* \param self the connection object
* \param rcbReference object reference of the report control block
*/

@ -69,6 +69,7 @@ struct sIedConnection
Semaphore outstandingCallsLock;
IedConnectionOutstandingCall outstandingCalls;
int maxOutstandingCalled;
IedConnectionClosedHandler connectionCloseHandler;
void* connectionClosedParameter;

@ -1,7 +1,7 @@
/*
* mms_mapping.c
*
* Copyright 2013-2022 Michael Zillgith
* Copyright 2013-2024 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -1309,8 +1309,8 @@ checkForServiceTrackingVariables(MmsMapping* self, LogicalNode* logicalNode)
{
ModelNode* modelNode = logicalNode->firstChild;
while (modelNode) {
while (modelNode)
{
if (!strcmp(modelNode->name, "SpcTrk") || !strcmp(modelNode->name, "DpcTrk") ||
!strcmp(modelNode->name, "IncTrk") || !strcmp(modelNode->name, "EncTrk1") ||
!strcmp(modelNode->name, "ApcFTrk") || !strcmp(modelNode->name, "ApcIntTrk") ||
@ -2644,6 +2644,10 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
if (nextSep != NULL) {
nextSep = strchr(nextSep + 1, '$');
if (nextSep == NULL) {
return DATA_ACCESS_ERROR_OBJECT_ACCESS_UNSUPPORTED;
}
char* nameId = nextSep + 1;
if (strcmp(nameId, "ActSG") == 0) {

@ -160,6 +160,16 @@ MmsConnection_setFilestoreBasepath(MmsConnection self, const char* basepath);
LIB61850_API void
MmsConnection_setRequestTimeout(MmsConnection self, uint32_t timeoutInMs);
/**
* \brief Set the maximum number outstanding calls allowed for this connection
*
* \param self MmsConnection instance to operate on
* \param calling the maximum outstanding calls allowed by the caller (client)
* \param called the maximum outstanding calls allowed by the called endpoint (server)
*/
LIB61850_API void
MmsConnnection_setMaxOutstandingCalls(MmsConnection self, int calling, int called);
/**
* \brief Get the request timeout in ms for this connection
*

@ -95,6 +95,8 @@ struct sMmsConnection {
Semaphore outstandingCallsLock;
MmsOutstandingCall outstandingCalls;
int maxOutstandingCalled;
int maxOutstandingCalling;
uint32_t requestTimeout;
uint32_t connectTimeout;

@ -1,7 +1,7 @@
/*
* mms_common_internal.h
*
* Copyright 2013-2019 Michael Zillgith
* Copyright 2013-2024 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -30,10 +30,10 @@
#include "byte_buffer.h"
#include "mms_server.h"
#define DEFAULT_MAX_SERV_OUTSTANDING_CALLING 5
#define DEFAULT_MAX_SERV_OUTSTANDING_CALLED 5
#define DEFAULT_DATA_STRUCTURE_NESTING_LEVEL 10
typedef struct sMmsOutstandingCall* MmsOutstandingCall;
#if (MMS_FILE_SERVICE == 1)
#ifndef CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION
@ -42,8 +42,6 @@
#include "hal_filesystem.h"
typedef struct sMmsOutstandingCall* MmsOutstandingCall;
typedef struct {
int32_t frsmId;
uint32_t readPosition;

@ -126,7 +126,10 @@ parseUserInformation(AcseConnection* self, uint8_t* buffer, int bufPos, int maxB
bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos);
if (bufPos < 0) {
if (len == 0)
continue;
if ((bufPos < 0) || (bufPos + len > maxBufPos)) {
*userInfoValid = false;
return -1;
}
@ -186,8 +189,23 @@ parseAarePdu(AcseConnection* self, uint8_t* buffer, int bufPos, int maxBufPos)
int len;
bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos);
if (bufPos < 0)
{
if (DEBUG_ACSE)
printf("ACSE: Invalid PDU!\n");
return ACSE_ERROR;
}
if (len == 0)
continue;
if (bufPos + len > maxBufPos)
{
if (DEBUG_ACSE)
printf("ACSE: Invalid PDU!\n");
return ACSE_ERROR;
}
switch (tag)
{
@ -269,7 +287,18 @@ parseAarqPdu(AcseConnection* self, uint8_t* buffer, int bufPos, int maxBufPos)
bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos);
if (bufPos < 0) {
if (bufPos < 0)
{
if (DEBUG_ACSE)
printf("ACSE: Invalid PDU!\n");
return ACSE_ASSOCIATE_FAILED;
}
if (len == 0)
continue;
if (bufPos + len > maxBufPos)
{
if (DEBUG_ACSE)
printf("ACSE: Invalid PDU!\n");
return ACSE_ASSOCIATE_FAILED;
@ -420,6 +449,14 @@ AcseConnection_parseMessage(AcseConnection* self, ByteBuffer* message)
{
AcseIndication indication = ACSE_ERROR;
if (message == NULL || message->size < 1)
{
if (DEBUG_ACSE)
printf("ACSE: invalid message - no payload\n");
return ACSE_ERROR;
}
uint8_t* buffer = message->buffer;
int messageSize = message->size;

@ -63,7 +63,6 @@ AcseAuthenticationParameter_setAuthMechanism(AcseAuthenticationParameter self, A
self->mechanism = mechanism;
}
IsoConnectionParameters
IsoConnectionParameters_create()
{
@ -75,7 +74,13 @@ IsoConnectionParameters_create()
void
IsoConnectionParameters_destroy(IsoConnectionParameters self)
{
if (self)
{
if (self->localIpAddress)
GLOBAL_FREEMEM((void*)(self->localIpAddress));
GLOBAL_FREEMEM(self);
}
}
void
@ -89,7 +94,6 @@ IsoConnectionParameters_setTlsConfiguration(IsoConnectionParameters self, TLSCon
#endif
}
void
IsoConnectionParameters_setAcseAuthenticationParameter(IsoConnectionParameters self,
AcseAuthenticationParameter acseAuthParameter)

@ -37,7 +37,6 @@
#define CONFIG_MMS_CONNECTION_DEFAULT_TIMEOUT 5000
#define CONFIG_MMS_CONNECTION_DEFAULT_CONNECT_TIMEOUT 10000
#define OUTSTANDING_CALLS 10
static void
setConnectionState(MmsConnection self, MmsConnectionState newState)
@ -255,9 +254,12 @@ checkForOutstandingCall(MmsConnection self, uint32_t invokeId)
Semaphore_wait(self->outstandingCallsLock);
for (i = 0; i < OUTSTANDING_CALLS; i++) {
if (self->outstandingCalls[i].isUsed) {
if (self->outstandingCalls[i].invokeId == invokeId) {
for (i = 0; i < self->maxOutstandingCalled; i++)
{
if (self->outstandingCalls[i].isUsed)
{
if (self->outstandingCalls[i].invokeId == invokeId)
{
Semaphore_post(self->outstandingCallsLock);
return &(self->outstandingCalls[i]);
}
@ -276,8 +278,10 @@ addToOutstandingCalls(MmsConnection self, uint32_t invokeId, eMmsOutstandingCall
Semaphore_wait(self->outstandingCallsLock);
for (i = 0; i < OUTSTANDING_CALLS; i++) {
if (self->outstandingCalls[i].isUsed == false) {
for (i = 0; i < self->maxOutstandingCalled; i++)
{
if (self->outstandingCalls[i].isUsed == false)
{
self->outstandingCalls[i].isUsed = true;
self->outstandingCalls[i].invokeId = invokeId;
self->outstandingCalls[i].timeout = Hal_getTimeInMs() + self->requestTimeout;
@ -302,9 +306,12 @@ removeFromOutstandingCalls(MmsConnection self, uint32_t invokeId)
Semaphore_wait(self->outstandingCallsLock);
for (i = 0; i < OUTSTANDING_CALLS; i++) {
if (self->outstandingCalls[i].isUsed) {
if (self->outstandingCalls[i].invokeId == invokeId) {
for (i = 0; i < self->maxOutstandingCalled; i++)
{
if (self->outstandingCalls[i].isUsed)
{
if (self->outstandingCalls[i].invokeId == invokeId)
{
self->outstandingCalls[i].isUsed = false;
break;
}
@ -321,11 +328,12 @@ mmsClient_getMatchingObtainFileRequest(MmsConnection self, const char* filename)
Semaphore_wait(self->outstandingCallsLock);
for (i = 0; i < OUTSTANDING_CALLS; i++) {
if (self->outstandingCalls[i].isUsed) {
if (self->outstandingCalls[i].type == MMS_CALL_TYPE_OBTAIN_FILE) {
for (i = 0; i < self->maxOutstandingCalled; i++)
{
if (self->outstandingCalls[i].isUsed)
{
if (self->outstandingCalls[i].type == MMS_CALL_TYPE_OBTAIN_FILE)
{
char* storedFilename = (char*) self->outstandingCalls[i].internalParameter.ptr;
if (storedFilename) {
@ -1008,8 +1016,8 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
int i = 0;
for (i = 0; i < OUTSTANDING_CALLS; i++) {
for (i = 0; i < self->maxOutstandingCalled; i++)
{
Semaphore_wait(self->outstandingCallsLock);
if (self->outstandingCalls[i].isUsed) {
@ -1057,8 +1065,8 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
{
int i;
for (i = 0; i < OUTSTANDING_CALLS; i++) {
for (i = 0; i < self->maxOutstandingCalled; i++)
{
Semaphore_wait(self->outstandingCallsLock);
if (self->outstandingCalls[i].isUsed) {
@ -1493,7 +1501,9 @@ MmsConnection_createInternal(TLSConfiguration tlsConfig, bool createThread)
self->concludeHandlerParameter = NULL;
self->concludeTimeout = 0;
self->outstandingCalls = (MmsOutstandingCall) GLOBAL_CALLOC(OUTSTANDING_CALLS, sizeof(struct sMmsOutstandingCall));
self->maxOutstandingCalling = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING;
self->maxOutstandingCalled = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED;
self->outstandingCalls = (MmsOutstandingCall) GLOBAL_CALLOC(CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED, sizeof(struct sMmsOutstandingCall));
self->isoParameters = IsoConnectionParameters_create();
@ -1652,6 +1662,25 @@ MmsConnection_setRequestTimeout(MmsConnection self, uint32_t timeoutInMs)
self->requestTimeout = timeoutInMs;
}
void
MmsConnnection_setMaxOutstandingCalls(MmsConnection self, int calling, int called)
{
if (calling < 1)
calling = 1;
if (called < 1)
called = 1;
if (self->outstandingCalls)
{
GLOBAL_FREEMEM(self->outstandingCalls);
}
self->maxOutstandingCalling = calling;
self->maxOutstandingCalled = called;
self->outstandingCalls = (MmsOutstandingCall)GLOBAL_CALLOC(called, sizeof(struct sMmsOutstandingCall));
}
uint32_t
MmsConnection_getRequestTimeout(MmsConnection self)
{

@ -487,8 +487,13 @@ parseFileAttributes(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t* fileSi
break;
case 0x81: /* lastModified */
{
if (lastModified != NULL) {
if (lastModified != NULL)
{
char gtString[40];
if (length > sizeof(gtString) - 1)
return false; /* lastModified string too long */
memcpy(gtString, buffer + bufPos, length);
gtString[length] = 0;
*lastModified = Conversions_generalizedTimeToMsTime(gtString);
@ -515,12 +520,14 @@ parseDirectoryEntry(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t invokeI
uint32_t fileSize = 0;
uint64_t lastModified = 0;
while (bufPos < maxBufPos) {
while (bufPos < maxBufPos)
{
uint8_t tag = buffer[bufPos++];
int length;
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
if (bufPos < 0) {
if (bufPos < 0)
{
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: invalid length field\n");
return false;
@ -534,12 +541,20 @@ parseDirectoryEntry(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t invokeI
tag = buffer[bufPos++];
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
if (bufPos < 0) {
if (bufPos < 0)
{
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: invalid length field\n");
return false;
}
if (length > (sizeof(fileNameMemory) - 1))
{
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: filename too long\n");
return false;
}
memcpy(filename, buffer + bufPos, length);
filename[length] = 0;

@ -39,18 +39,16 @@ static uint8_t servicesSupported[] = { 0xee, 0x1c, 0x00, 0x00, 0x04, 0x08, 0x00,
void
mmsClient_createInitiateRequest(MmsConnection self, ByteBuffer* message)
{
int maxServerOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING;
int maxServerOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED;
int dataStructureNestingLevel = DEFAULT_DATA_STRUCTURE_NESTING_LEVEL;
uint32_t localDetailSize =
BerEncoder_UInt32determineEncodedSize(self->parameters.maxPduSize);
uint32_t proposedMaxServerOutstandingCallingSize =
BerEncoder_UInt32determineEncodedSize(maxServerOutstandingCalling);
BerEncoder_UInt32determineEncodedSize(self->maxOutstandingCalling);
uint32_t proposedMaxServerOutstandingCalledSize =
BerEncoder_UInt32determineEncodedSize(maxServerOutstandingCalled);
BerEncoder_UInt32determineEncodedSize(self->maxOutstandingCalled);
uint32_t dataStructureNestingLevelSize =
BerEncoder_UInt32determineEncodedSize(dataStructureNestingLevel);
@ -76,11 +74,11 @@ mmsClient_createInitiateRequest(MmsConnection self, ByteBuffer* message)
/* proposedMaxServerOutstandingCalling */
bufPos = BerEncoder_encodeTL(0x81, proposedMaxServerOutstandingCallingSize, buffer, bufPos);
bufPos = BerEncoder_encodeUInt32(maxServerOutstandingCalling, buffer, bufPos);
bufPos = BerEncoder_encodeUInt32(self->maxOutstandingCalling, buffer, bufPos);
/* proposedMaxServerOutstandingCalled */
bufPos = BerEncoder_encodeTL(0x82, proposedMaxServerOutstandingCalledSize, buffer, bufPos);
bufPos = BerEncoder_encodeUInt32(maxServerOutstandingCalled, buffer, bufPos);
bufPos = BerEncoder_encodeUInt32(self->maxOutstandingCalled, buffer, bufPos);
/* proposedDataStructureNestingLevel */
bufPos = BerEncoder_encodeTL(0x83, dataStructureNestingLevelSize, buffer, bufPos);
@ -169,8 +167,8 @@ mmsClient_parseInitiateResponse(MmsConnection self, ByteBuffer* response)
{
self->parameters.maxPduSize = CONFIG_MMS_MAXIMUM_PDU_SIZE;
self->parameters.dataStructureNestingLevel = DEFAULT_DATA_STRUCTURE_NESTING_LEVEL;
self->parameters.maxServOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED;
self->parameters.maxServOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING;
self->parameters.maxServOutstandingCalled = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED;
self->parameters.maxServOutstandingCalling = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING;
int bufPos = 1; /* ignore tag - already checked */
@ -203,16 +201,16 @@ mmsClient_parseInitiateResponse(MmsConnection self, ByteBuffer* response)
case 0x81: /* proposed-max-serv-outstanding-calling */
self->parameters.maxServOutstandingCalling = BerDecoder_decodeUint32(buffer, length, bufPos);
if (self->parameters.maxServOutstandingCalling > DEFAULT_MAX_SERV_OUTSTANDING_CALLING)
self->parameters.maxServOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING;
if (self->parameters.maxServOutstandingCalling > CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING)
self->parameters.maxServOutstandingCalling = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING;
break;
case 0x82: /* proposed-max-serv-outstanding-called */
self->parameters.maxServOutstandingCalled = BerDecoder_decodeUint32(buffer, length, bufPos);
if (self->parameters.maxServOutstandingCalled > DEFAULT_MAX_SERV_OUTSTANDING_CALLED)
self->parameters.maxServOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED;
if (self->parameters.maxServOutstandingCalled > CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED)
self->parameters.maxServOutstandingCalled = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED;
break;
case 0x83: /* proposed-data-structure-nesting-level */

@ -330,9 +330,9 @@ parseInitiateRequestPdu(MmsServerConnection self, uint8_t* buffer, int bufPos, i
self->dataStructureNestingLevel =
DEFAULT_DATA_STRUCTURE_NESTING_LEVEL;
self->maxServOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED;
self->maxServOutstandingCalled = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED;
self->maxServOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING;
self->maxServOutstandingCalling = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING;
self->negotiatedParameterCBC[0] = 0;
self->negotiatedParameterCBC[1] = 0;
@ -367,16 +367,16 @@ parseInitiateRequestPdu(MmsServerConnection self, uint8_t* buffer, int bufPos, i
case 0x81: /* proposed-max-serv-outstanding-calling */
self->maxServOutstandingCalling = BerDecoder_decodeUint32(buffer, length, bufPos);
if (self->maxServOutstandingCalling > DEFAULT_MAX_SERV_OUTSTANDING_CALLING)
self->maxServOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING;
if (self->maxServOutstandingCalling > CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING)
self->maxServOutstandingCalling = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING;
break;
case 0x82: /* proposed-max-serv-outstanding-called */
self->maxServOutstandingCalled = BerDecoder_decodeUint32(buffer, length, bufPos);
if (self->maxServOutstandingCalled > DEFAULT_MAX_SERV_OUTSTANDING_CALLED)
self->maxServOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED;
if (self->maxServOutstandingCalled > CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED)
self->maxServOutstandingCalled = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED;
break;
case 0x83: /* proposed-data-structure-nesting-level */

@ -296,9 +296,12 @@ mmsServer_handleGetVariableAccessAttributesRequest(
rval = ber_decode(NULL, &asn_DEF_GetVariableAccessAttributesRequest,
(void**) &request, buffer + bufPos, maxBufPos - bufPos);
if (rval.code == RC_OK) {
if (request->present == GetVariableAccessAttributesRequest_PR_name) {
if (request->choice.name.present == ObjectName_PR_domainspecific) {
if (rval.code == RC_OK)
{
if (request->present == GetVariableAccessAttributesRequest_PR_name)
{
if (request->choice.name.present == ObjectName_PR_domainspecific)
{
Identifier_t domainId = request->choice.name.choice.domainspecific.domainId;
Identifier_t nameId = request->choice.name.choice.domainspecific.itemId;
@ -343,6 +346,13 @@ mmsServer_handleGetVariableAccessAttributesRequest(
asn_DEF_GetVariableAccessAttributesRequest.free_struct(&asn_DEF_GetVariableAccessAttributesRequest, request, 0);
if (ByteBuffer_getSize(response) > connection->maxPduSize)
{
ByteBuffer_setSize(response, 0);
mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_OTHER);
}
return retVal;
}

@ -141,6 +141,12 @@ mmsServer_handleDeleteNamedVariableListRequest(MmsServerConnection connection,
goto exit_function;
}
if (request->listOfVariableListName == NULL)
{
mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response);
goto exit_function;
}
long scopeOfDelete = DeleteNamedVariableListRequest__scopeOfDelete_specific;
if (request->scopeOfDelete)
@ -675,7 +681,8 @@ createGetNamedVariableListAttributesResponse(int invokeId, ByteBuffer* response,
LinkedList variable = LinkedList_getNext(variables);
int i;
for (i = 0; i < variableCount; i++) {
for (i = 0; i < variableCount; i++)
{
MmsNamedVariableListEntry variableEntry = (MmsNamedVariableListEntry) variable->data;
varListResponse->listOfVariable.list.array[i] = (struct GetNamedVariableListAttributesResponse__listOfVariable__Member*)
@ -740,8 +747,8 @@ mmsServer_handleGetNamedVariableListAttributesRequest(
goto exit_function;
}
if (request->present == ObjectName_PR_domainspecific) {
if (request->present == ObjectName_PR_domainspecific)
{
char domainName[65];
char itemName[65];
@ -761,14 +768,15 @@ mmsServer_handleGetNamedVariableListAttributesRequest(
MmsDomain* domain = MmsDevice_getDomain(mmsDevice, domainName);
if (domain != NULL) {
if (domain != NULL)
{
MmsNamedVariableList variableList =
MmsDomain_getNamedVariableList(domain, itemName);
if (variableList != NULL) {
if (createGetNamedVariableListAttributesResponse(invokeId, response, variableList) == false) {
if (variableList != NULL)
{
if (createGetNamedVariableListAttributesResponse(invokeId, response, variableList) == false)
{
/* encoding failed - probably because buffer size is too small for message */
ByteBuffer_setSize(response, 0);
@ -783,8 +791,8 @@ mmsServer_handleGetNamedVariableListAttributesRequest(
}
#if (MMS_DYNAMIC_DATA_SETS == 1)
else if (request->present == ObjectName_PR_aaspecific) {
else if (request->present == ObjectName_PR_aaspecific)
{
char listName[65];
if (request->choice.aaspecific.size > 64) {
@ -803,7 +811,8 @@ mmsServer_handleGetNamedVariableListAttributesRequest(
mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT);
}
#endif /* (MMS_DYNAMIC_DATA_SETS == 1) */
else if (request->present == ObjectName_PR_vmdspecific) {
else if (request->present == ObjectName_PR_vmdspecific)
{
char listName[65];
if (request->choice.vmdspecific.size > 64) {
@ -827,6 +836,13 @@ mmsServer_handleGetNamedVariableListAttributesRequest(
mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED);
}
if (ByteBuffer_getSize(response) > connection->maxPduSize)
{
ByteBuffer_setSize(response, 0);
mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_OTHER);
}
exit_function:
asn_DEF_GetVariableAccessAttributesRequest.free_struct(&asn_DEF_GetNamedVariableListAttributesRequest,

@ -528,7 +528,7 @@ encodeReadResponse(MmsServerConnection connection,
printf("MMS read: message to large! send error PDU!\n");
mmsMsg_createServiceErrorPdu(invokeId, response,
MMS_ERROR_SERVICE_OTHER);
MMS_ERROR_RESOURCE_OTHER);
goto exit_function;
}
@ -933,7 +933,8 @@ mmsServer_handleReadRequest(
goto exit_function;
}
if (request->variableAccessSpecification.present == VariableAccessSpecification_PR_listOfVariable) {
if (request->variableAccessSpecification.present == VariableAccessSpecification_PR_listOfVariable)
{
MmsServer_lockModel(connection->server);
handleReadListOfVariablesRequest(connection, request, invokeId, response);
@ -941,7 +942,8 @@ mmsServer_handleReadRequest(
MmsServer_unlockModel(connection->server);
}
#if (MMS_DATA_SET_SERVICE == 1)
else if (request->variableAccessSpecification.present == VariableAccessSpecification_PR_variableListName) {
else if (request->variableAccessSpecification.present == VariableAccessSpecification_PR_variableListName)
{
MmsServer_lockModel(connection->server);
handleReadNamedVariableListRequest(connection, request, invokeId, response);
@ -953,6 +955,13 @@ mmsServer_handleReadRequest(
mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED);
}
if (ByteBuffer_getSize(response) > connection->maxPduSize)
{
ByteBuffer_setSize(response, 0);
mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_OTHER);
}
exit_function:
asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0);
}

@ -4,7 +4,7 @@ mkdir build
find src/ -name "*.java" > listFile.tmp
javac -target 1.6 -source 1.6 -d build @listFile.tmp
javac -target 1.8 -source 1.8 -d build @listFile.tmp
jar cfm genconfig.jar manifest-dynamic.mf -C build/ com/

@ -188,19 +188,35 @@ public class DataModelValue {
case TIMESTAMP:
case ENTRY_TIME:
try {
{
String modValueString = value.replace(',', '.');
try {
SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-d'T'HH:mm:ss.SSS");
parser.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = parser.parse(modValueString);
this.value = new Long(date.toInstant().toEpochMilli());
break;
}
catch (java.text.ParseException e) {};
try {
SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-d'T'HH:mm:ss");
parser.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = parser.parse(modValueString);
this.value = new Long(date.toInstant().toEpochMilli());
break;
}
catch (java.text.ParseException e) {
catch (java.text.ParseException e) {};
this.value = null;
System.out.println("Warning: Val element does not contain a valid time stamp: " + e.getMessage());
System.out.println("Warning: Val element does not contain a valid time stamp: " + value);
}
break;

@ -543,6 +543,11 @@ public class DynamicModelGenerator {
case FLOAT64:
output.print("=" + value.getValue());
break;
case TIMESTAMP:
case ENTRY_TIME:
output.print("=" + value.getLongValue());
break;
default:
System.out.println("Unknown default value for " + dataAttribute.getName() + " type: " + dataAttribute.getType());
break;

Loading…
Cancel
Save