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) 2 years 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. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v1 uses: github/codeql-action/init@v2
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file. # 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). # 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) # If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild - name: Autobuild
uses: github/codeql-action/autobuild@v1 uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell. # Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl # 📚 https://git.io/JvXDl
@ -68,4 +68,4 @@ jobs:
# make release # make release
- name: Perform CodeQL Analysis - 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 */ /* enable to configure MmsServer at runtime */
#define CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME 1 #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! * 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 (MMS_JOURNAL_SERVICE != 1)
#if (CONFIG_IEC61850_LOG_SERVICE == 1) #if (CONFIG_IEC61850_LOG_SERVICE == 1)

@ -232,10 +232,24 @@
/* enable to configure MmsServer at runtime */ /* enable to configure MmsServer at runtime */
#define CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME 1 #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! * 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 (MMS_JOURNAL_SERVICE != 1)
#if (CONFIG_IEC61850_LOG_SERVICE == 1) #if (CONFIG_IEC61850_LOG_SERVICE == 1)

@ -431,6 +431,9 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern UInt32 IedConnection_getRequestTimeout(IntPtr self); 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)] [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); 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> /// <summary>
/// Gets or sets the maximum size if a PDU (has to be set before calling connect!). /// Gets or sets the maximum size if a PDU (has to be set before calling connect!).
/// </summary> /// </summary>
@ -1175,6 +1188,9 @@ namespace IEC61850
private static List<MmsJournalEntry> WrapNativeLogQueryResult(IntPtr linkedList) private static List<MmsJournalEntry> WrapNativeLogQueryResult(IntPtr linkedList)
{ {
if (linkedList == IntPtr.Zero)
return null;
List<MmsJournalEntry> journalEntries = new List<MmsJournalEntry>(); List<MmsJournalEntry> journalEntries = new List<MmsJournalEntry>();
IntPtr element = LinkedList_getNext(linkedList); IntPtr element = LinkedList_getNext(linkedList);
@ -2238,11 +2254,15 @@ namespace IEC61850
GetDataSetDirectoryHandler handler = callbackInfo.Item1; GetDataSetDirectoryHandler handler = callbackInfo.Item1;
object handlerParameter = callbackInfo.Item2; object handlerParameter = callbackInfo.Item2;
IntPtr element = LinkedList_getNext(dataSetDirectory);
handle.Free(); 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) while (element != IntPtr.Zero)
{ {
@ -2254,6 +2274,7 @@ namespace IEC61850
} }
LinkedList_destroy(dataSetDirectory); LinkedList_destroy(dataSetDirectory);
}
handler.Invoke(invokeId, handlerParameter, (IedClientError)err, newList, isDeletable); handler.Invoke(invokeId, handlerParameter, (IedClientError)err, newList, isDeletable);
} }
@ -2428,11 +2449,9 @@ namespace IEC61850
dataSet = new DataSet(nativeDataSet); dataSet = new DataSet(nativeDataSet);
} }
handler(invokeId, handlerParameter, clientError, dataSet); handler(invokeId, handlerParameter, clientError, dataSet);
} }
public delegate void ReadDataSetHandler(UInt32 invokeId,object parameter,IedClientError err,DataSet dataSet); public delegate void ReadDataSetHandler(UInt32 invokeId,object parameter,IedClientError err,DataSet dataSet);
/// <summary> /// <summary>
@ -2566,7 +2585,6 @@ namespace IEC61850
{ {
handler(invokeId, handlerParameter, clientError, null, moreFollows); handler(invokeId, handlerParameter, clientError, null, moreFollows);
} }
} }
/// <summary> /// <summary>
@ -2632,7 +2650,6 @@ namespace IEC61850
return GetLogicalDeviceDataSetsAsync(null, ldName, continueAfter, handler, parameter); return GetLogicalDeviceDataSetsAsync(null, ldName, continueAfter, handler, parameter);
} }
public UInt32 GetLogicalDeviceDataSetsAsync(List<string> result, string ldName, string continueAfter, GetNameListHandler handler, object parameter) public UInt32 GetLogicalDeviceDataSetsAsync(List<string> result, string ldName, string continueAfter, GetNameListHandler handler, object parameter)
{ {
int error; int error;

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

@ -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;

@ -478,10 +478,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);
@ -505,17 +501,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 */
@ -530,7 +523,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 {
@ -544,15 +537,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 */

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

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

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

@ -1,7 +1,7 @@
/* /*
* iec61850_client.h * iec61850_client.h
* *
* Copyright 2013-2021 Michael Zillgith * Copyright 2013-2023 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -255,6 +255,16 @@ IedConnection_setLocalAddress(IedConnection self, const char* localIpAddress, in
LIB61850_API void LIB61850_API void
IedConnection_setConnectTimeout(IedConnection self, uint32_t timeoutInMs); 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 * \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 * Otherwise the internal data structures storing the received data set values will not be updated
* correctly. * 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. * 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 self the connection object
* \param rcbReference object reference of the report control block * \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 * \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) * \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 self the connection object
* \param rcbReference object reference of the report control block * \param rcbReference object reference of the report control block
*/ */

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

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

@ -160,6 +160,16 @@ MmsConnection_setFilestoreBasepath(MmsConnection self, const char* basepath);
LIB61850_API void LIB61850_API void
MmsConnection_setRequestTimeout(MmsConnection self, uint32_t timeoutInMs); 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 * \brief Get the request timeout in ms for this connection
* *

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

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

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

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

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

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

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

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

@ -296,9 +296,12 @@ mmsServer_handleGetVariableAccessAttributesRequest(
rval = ber_decode(NULL, &asn_DEF_GetVariableAccessAttributesRequest, rval = ber_decode(NULL, &asn_DEF_GetVariableAccessAttributesRequest,
(void**) &request, buffer + bufPos, maxBufPos - bufPos); (void**) &request, buffer + bufPos, maxBufPos - bufPos);
if (rval.code == RC_OK) { if (rval.code == RC_OK)
if (request->present == GetVariableAccessAttributesRequest_PR_name) { {
if (request->choice.name.present == ObjectName_PR_domainspecific) { 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 domainId = request->choice.name.choice.domainspecific.domainId;
Identifier_t nameId = request->choice.name.choice.domainspecific.itemId; 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); 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; return retVal;
} }

@ -141,6 +141,12 @@ mmsServer_handleDeleteNamedVariableListRequest(MmsServerConnection connection,
goto exit_function; goto exit_function;
} }
if (request->listOfVariableListName == NULL)
{
mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response);
goto exit_function;
}
long scopeOfDelete = DeleteNamedVariableListRequest__scopeOfDelete_specific; long scopeOfDelete = DeleteNamedVariableListRequest__scopeOfDelete_specific;
if (request->scopeOfDelete) if (request->scopeOfDelete)
@ -675,7 +681,8 @@ createGetNamedVariableListAttributesResponse(int invokeId, ByteBuffer* response,
LinkedList variable = LinkedList_getNext(variables); LinkedList variable = LinkedList_getNext(variables);
int i; int i;
for (i = 0; i < variableCount; i++) { for (i = 0; i < variableCount; i++)
{
MmsNamedVariableListEntry variableEntry = (MmsNamedVariableListEntry) variable->data; MmsNamedVariableListEntry variableEntry = (MmsNamedVariableListEntry) variable->data;
varListResponse->listOfVariable.list.array[i] = (struct GetNamedVariableListAttributesResponse__listOfVariable__Member*) varListResponse->listOfVariable.list.array[i] = (struct GetNamedVariableListAttributesResponse__listOfVariable__Member*)
@ -740,8 +747,8 @@ mmsServer_handleGetNamedVariableListAttributesRequest(
goto exit_function; goto exit_function;
} }
if (request->present == ObjectName_PR_domainspecific) { if (request->present == ObjectName_PR_domainspecific)
{
char domainName[65]; char domainName[65];
char itemName[65]; char itemName[65];
@ -761,14 +768,15 @@ mmsServer_handleGetNamedVariableListAttributesRequest(
MmsDomain* domain = MmsDevice_getDomain(mmsDevice, domainName); MmsDomain* domain = MmsDevice_getDomain(mmsDevice, domainName);
if (domain != NULL) { if (domain != NULL)
{
MmsNamedVariableList variableList = MmsNamedVariableList variableList =
MmsDomain_getNamedVariableList(domain, itemName); MmsDomain_getNamedVariableList(domain, itemName);
if (variableList != NULL) { if (variableList != NULL)
{
if (createGetNamedVariableListAttributesResponse(invokeId, response, variableList) == false) { if (createGetNamedVariableListAttributesResponse(invokeId, response, variableList) == false)
{
/* encoding failed - probably because buffer size is too small for message */ /* encoding failed - probably because buffer size is too small for message */
ByteBuffer_setSize(response, 0); ByteBuffer_setSize(response, 0);
@ -783,8 +791,8 @@ mmsServer_handleGetNamedVariableListAttributesRequest(
} }
#if (MMS_DYNAMIC_DATA_SETS == 1) #if (MMS_DYNAMIC_DATA_SETS == 1)
else if (request->present == ObjectName_PR_aaspecific) { else if (request->present == ObjectName_PR_aaspecific)
{
char listName[65]; char listName[65];
if (request->choice.aaspecific.size > 64) { if (request->choice.aaspecific.size > 64) {
@ -803,7 +811,8 @@ mmsServer_handleGetNamedVariableListAttributesRequest(
mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT);
} }
#endif /* (MMS_DYNAMIC_DATA_SETS == 1) */ #endif /* (MMS_DYNAMIC_DATA_SETS == 1) */
else if (request->present == ObjectName_PR_vmdspecific) { else if (request->present == ObjectName_PR_vmdspecific)
{
char listName[65]; char listName[65];
if (request->choice.vmdspecific.size > 64) { if (request->choice.vmdspecific.size > 64) {
@ -827,6 +836,13 @@ mmsServer_handleGetNamedVariableListAttributesRequest(
mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED); 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: exit_function:
asn_DEF_GetVariableAccessAttributesRequest.free_struct(&asn_DEF_GetNamedVariableListAttributesRequest, 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"); printf("MMS read: message to large! send error PDU!\n");
mmsMsg_createServiceErrorPdu(invokeId, response, mmsMsg_createServiceErrorPdu(invokeId, response,
MMS_ERROR_SERVICE_OTHER); MMS_ERROR_RESOURCE_OTHER);
goto exit_function; goto exit_function;
} }
@ -933,7 +933,8 @@ mmsServer_handleReadRequest(
goto exit_function; goto exit_function;
} }
if (request->variableAccessSpecification.present == VariableAccessSpecification_PR_listOfVariable) { if (request->variableAccessSpecification.present == VariableAccessSpecification_PR_listOfVariable)
{
MmsServer_lockModel(connection->server); MmsServer_lockModel(connection->server);
handleReadListOfVariablesRequest(connection, request, invokeId, response); handleReadListOfVariablesRequest(connection, request, invokeId, response);
@ -941,7 +942,8 @@ mmsServer_handleReadRequest(
MmsServer_unlockModel(connection->server); MmsServer_unlockModel(connection->server);
} }
#if (MMS_DATA_SET_SERVICE == 1) #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); MmsServer_lockModel(connection->server);
handleReadNamedVariableListRequest(connection, request, invokeId, response); handleReadNamedVariableListRequest(connection, request, invokeId, response);
@ -953,6 +955,13 @@ mmsServer_handleReadRequest(
mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED); 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: exit_function:
asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0);
} }

@ -4,7 +4,7 @@ mkdir build
find src/ -name "*.java" > listFile.tmp 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/ jar cfm genconfig.jar manifest-dynamic.mf -C build/ com/

@ -188,19 +188,35 @@ public class DataModelValue {
case TIMESTAMP: case TIMESTAMP:
case ENTRY_TIME: case ENTRY_TIME:
try { {
String modValueString = value.replace(',', '.'); String modValueString = value.replace(',', '.');
try {
SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-d'T'HH:mm:ss.SSS"); SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-d'T'HH:mm:ss.SSS");
parser.setTimeZone(TimeZone.getTimeZone("UTC")); parser.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = parser.parse(modValueString); Date date = parser.parse(modValueString);
this.value = new Long(date.toInstant().toEpochMilli()); 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; 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; break;

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

Loading…
Cancel
Save