- added function IedServer_setLocalAddresses to configure called local T-,S-,P-selectors (LIB61850-471)

- added code to optionally reject incoming connections with wrong values of called T-,S-,P-selectors (LIB61850-471)
v1.6_develop_471
Michael Zillgith 10 months ago
parent 3ff7cdd933
commit 7cf67bb01b

@ -514,6 +514,21 @@ IedServer_addAccessPoint(IedServer self, const char* ipAddr, int tcpPort, TLSCon
LIB61850_API void LIB61850_API void
IedServer_setLocalIpAddress(IedServer self, const char* localIpAddress); IedServer_setLocalIpAddress(IedServer self, const char* localIpAddress);
/**
* \brief Set the local addresses
*
* \note When set, the values will be checked againt the called addresses of the incoming connections.
* If the set addresses do not match the incoming connection will be rejected.
* Default behavior is to accept all incoming connections independent of the called selectors.
*
* \param self the IedServer instance
* \param pSelector the presentation-selector to set or NULL when no check is required
* \param sSelector the session-selector to set or NULL when no check is required
* \param tSelector the transport-selector to set or NULL when no check is required
*/
LIB61850_API void
IedServer_setLocalAddresses(IedServer self, const PSelector* pSelector, const SSelector* sSelector, const TSelector* tSelector);
/** /**
* \brief Set the identify for the MMS identify service * \brief Set the identify for the MMS identify service
* *

@ -923,6 +923,11 @@ IedServer_setLocalIpAddress(IedServer self, const char* localIpAddress)
MmsServer_setLocalIpAddress(self->mmsServer, self->localIpAddress); MmsServer_setLocalIpAddress(self->mmsServer, self->localIpAddress);
} }
void
IedServer_setLocalAddresses(IedServer self, const PSelector* pSelector, const SSelector* sSelector, const TSelector* tSelector)
{
MmsServer_setLocalAddresses(self->mmsServer, pSelector, sSelector, tSelector);
}
void void
IedServer_startThreadless(IedServer self, int tcpPort) IedServer_startThreadless(IedServer self, int tcpPort)

@ -54,6 +54,9 @@ typedef enum {
LIB61850_INTERNAL void LIB61850_INTERNAL void
MmsServer_setLocalIpAddress(MmsServer self, const char* localIpAddress); MmsServer_setLocalIpAddress(MmsServer self, const char* localIpAddress);
LIB61850_INTERNAL void
MmsServer_setLocalAddresses(MmsServer self, const PSelector* pSelector, const SSelector* sSelector, const TSelector* tSelector);
LIB61850_INTERNAL bool LIB61850_INTERNAL bool
MmsServer_isRunning(MmsServer self); MmsServer_isRunning(MmsServer self);
@ -285,10 +288,6 @@ MmsServer_setMaxDataSetEntries(MmsServer self, int maxDataSetEntries);
LIB61850_INTERNAL void LIB61850_INTERNAL void
MmsServer_enableJournalService(MmsServer self, bool enable); MmsServer_enableJournalService(MmsServer self, bool enable);
/*************************************************** /***************************************************
* Functions for MMS identify service * Functions for MMS identify service
***************************************************/ ***************************************************/

@ -59,6 +59,8 @@ typedef struct {
uint8_t* socketExtensionBuffer; /* buffer to store data when TCP socket is not accepting all data */ uint8_t* socketExtensionBuffer; /* buffer to store data when TCP socket is not accepting all data */
int socketExtensionBufferSize; /* maximum number of bytes to store in the extension buffer */ int socketExtensionBufferSize; /* maximum number of bytes to store in the extension buffer */
int socketExtensionBufferFill; /* number of bytes in the extension buffer (bytes to write) */ int socketExtensionBufferFill; /* number of bytes in the extension buffer (bytes to write) */
const TSelector* checkTSel; /* when set the called TSelector will be check to be equal to this value */
} CotpConnection; } CotpConnection;
typedef enum { typedef enum {
@ -87,6 +89,9 @@ CotpConnection_init(CotpConnection* self, Socket socket,
ByteBuffer* payloadBuffer, ByteBuffer* readBuffer, ByteBuffer* writeBuffer, ByteBuffer* payloadBuffer, ByteBuffer* readBuffer, ByteBuffer* writeBuffer,
uint8_t* socketExtensionBuffer, int socketExtensionBufferSize); uint8_t* socketExtensionBuffer, int socketExtensionBufferSize);
LIB61850_INTERNAL void
CotpConnection_setCheckDstSelector(CotpConnection* self, const TSelector* tSel);
LIB61850_INTERNAL CotpIndication LIB61850_INTERNAL CotpIndication
CotpConnection_parseIncomingMessage(CotpConnection* self); CotpConnection_parseIncomingMessage(CotpConnection* self);

@ -31,6 +31,7 @@
typedef struct { typedef struct {
PSelector callingPresentationSelector; PSelector callingPresentationSelector;
PSelector calledPresentationSelector; PSelector calledPresentationSelector;
const PSelector* checkCalledPSelector;
uint8_t nextContextId; uint8_t nextContextId;
uint8_t acseContextId; uint8_t acseContextId;
uint8_t mmsContextId; uint8_t mmsContextId;
@ -38,13 +39,16 @@ typedef struct {
} IsoPresentation; } IsoPresentation;
LIB61850_INTERNAL void LIB61850_INTERNAL void
IsoPresentation_init(IsoPresentation* session); IsoPresentation_init(IsoPresentation* self);
LIB61850_INTERNAL int LIB61850_INTERNAL void
IsoPresentation_parseUserData(IsoPresentation* session, ByteBuffer* message); IsoPresentation_setCalledPSelector(IsoPresentation* self, const PSelector* calledPSelector);
LIB61850_INTERNAL int LIB61850_INTERNAL int
IsoPresentation_parseConnect(IsoPresentation* session, ByteBuffer* message); IsoPresentation_parseUserData(IsoPresentation* self, ByteBuffer* message);
LIB61850_INTERNAL bool
IsoPresentation_parseConnect(IsoPresentation* self, ByteBuffer* message);
LIB61850_INTERNAL void LIB61850_INTERNAL void
IsoPresentation_createConnectPdu(IsoPresentation* self, IsoConnectionParameters parameters, IsoPresentation_createConnectPdu(IsoPresentation* self, IsoConnectionParameters parameters,

@ -113,6 +113,10 @@ IsoServer_setMaxConnections(IsoServer self, int maxConnections);
LIB61850_INTERNAL void LIB61850_INTERNAL void
IsoServer_setLocalIpAddress(IsoServer self, const char* ipAddress); IsoServer_setLocalIpAddress(IsoServer self, const char* ipAddress);
LIB61850_INTERNAL void
IsoServer_setLocalAddresses(IsoServer self, const PSelector* pSel, const SSelector* sSel,
const TSelector* tSel);
LIB61850_INTERNAL IsoServerState LIB61850_INTERNAL IsoServerState
IsoServer_getState(IsoServer self); IsoServer_getState(IsoServer self);

@ -70,6 +70,15 @@ private_IsoServer_decreaseConnectionCounter(IsoServer self);
LIB61850_INTERNAL int LIB61850_INTERNAL int
private_IsoServer_getConnectionCounter(IsoServer self); private_IsoServer_getConnectionCounter(IsoServer self);
LIB61850_INTERNAL const PSelector*
private_IsoServer_getLocalPSelector(IsoServer self);
LIB61850_INTERNAL const SSelector*
private_IsoServer_getLocalSSelector(IsoServer self);
LIB61850_INTERNAL const TSelector*
private_IsoServer_getLocalTSelector(IsoServer self);
LIB61850_INTERNAL bool LIB61850_INTERNAL bool
IsoConnection_isRunning(IsoConnection self); IsoConnection_isRunning(IsoConnection self);

@ -1,7 +1,7 @@
/* /*
* ise_session.h * ise_session.h
* *
* Copyright 2013-2018 Michael Zillgith * Copyright 2013-2014 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -31,6 +31,7 @@
typedef struct { typedef struct {
SSelector callingSessionSelector; SSelector callingSessionSelector;
SSelector calledSessionSelector; SSelector calledSessionSelector;
const SSelector* checkCalledSSelector;
uint16_t sessionRequirement; uint16_t sessionRequirement;
uint8_t protocolOptions; uint8_t protocolOptions;
ByteBuffer userData; ByteBuffer userData;
@ -51,6 +52,9 @@ typedef enum {
LIB61850_INTERNAL void LIB61850_INTERNAL void
IsoSession_init(IsoSession* session); IsoSession_init(IsoSession* session);
LIB61850_INTERNAL void
IsoSession_setCalledSSelector(IsoSession* session, const SSelector* calledSSelector);
LIB61850_INTERNAL ByteBuffer* LIB61850_INTERNAL ByteBuffer*
IsoSession_getUserData(IsoSession* session); IsoSession_getUserData(IsoSession* session);

@ -105,8 +105,8 @@ struct sMmsObtainFileTask {
#endif /* (MMS_OBTAIN_FILE_SERVICE == 1) */ #endif /* (MMS_OBTAIN_FILE_SERVICE == 1) */
struct sMmsServer { struct sMmsServer
{
LinkedList /*<IsoServer>*/ isoServerList; LinkedList /*<IsoServer>*/ isoServerList;
MmsDevice* device; MmsDevice* device;
@ -198,6 +198,12 @@ struct sMmsServer {
int maxDomainSpecificDataSets; int maxDomainSpecificDataSets;
#endif /* (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1) */ #endif /* (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1) */
PSelector pSel;
bool checkCalledPSel;
SSelector sSel;
bool checkCalledSSel;
TSelector tSel;
bool checkCalledTSel;
}; };
struct sMmsServerConnection { struct sMmsServerConnection {
@ -245,8 +251,6 @@ MmsServer_callConnectionHandler(MmsServer self, MmsServerConnection connection);
LIB61850_INTERNAL int LIB61850_INTERNAL int
mmsServer_write_out(const void *buffer, size_t size, void *app_key); mmsServer_write_out(const void *buffer, size_t size, void *app_key);
LIB61850_INTERNAL void LIB61850_INTERNAL void
mmsServer_handleDeleteNamedVariableListRequest(MmsServerConnection connection, mmsServer_handleDeleteNamedVariableListRequest(MmsServerConnection connection,
uint8_t* buffer, int bufPos, int maxBufPos, uint8_t* buffer, int bufPos, int maxBufPos,

@ -579,6 +579,14 @@ CotpConnection_init(CotpConnection* self, Socket socket,
self->socketExtensionBuffer = socketExtensionBuffer; self->socketExtensionBuffer = socketExtensionBuffer;
self->socketExtensionBufferSize = socketExtensionBufferSize; self->socketExtensionBufferSize = socketExtensionBufferSize;
self->socketExtensionBufferFill = 0; self->socketExtensionBufferFill = 0;
self->checkTSel = NULL;
}
void
CotpConnection_setCheckDstSelector(CotpConnection* self, const TSelector* tSel)
{
self->checkTSel = tSel;
} }
int /* in byte */ int /* in byte */
@ -632,6 +640,24 @@ CotpConnection_getLocalRef(CotpConnection* self)
+--+------+---------+---------+---+---+------+-------+---------+ +--+------+---------+---------+---+---+------+-------+---------+
*/ */
static bool
checkDstTSelector(CotpConnection* self)
{
if (self->checkTSel == NULL)
return true;
if (self->options.tSelDst.size != self->checkTSel->size)
return false;
int i;
for (i = 0; i < self->options.tSelDst.size; i++)
{
if (self->options.tSelDst.value[i] != self->checkTSel->value[i])
return false;
}
return true;
}
static bool static bool
parseConnectRequestTpdu(CotpConnection* self, uint8_t* buffer, uint8_t len) parseConnectRequestTpdu(CotpConnection* self, uint8_t* buffer, uint8_t len)
@ -642,7 +668,25 @@ parseConnectRequestTpdu(CotpConnection* self, uint8_t* buffer, uint8_t len)
self->remoteRef = getUint16(buffer + 2); self->remoteRef = getUint16(buffer + 2);
self->protocolClass = getUint8(buffer + 4); self->protocolClass = getUint8(buffer + 4);
return parseOptions(self, buffer + 5, len - 6); if (parseOptions(self, buffer + 5, len - 6))
{
if (checkDstTSelector(self) == false)
{
if (DEBUG_COTP)
printf("COTP: CR TPDU: wrong called T-selector value\n");
return false;
}
}
else
{
if (DEBUG_COTP)
printf("COTP: CR TPDU: error parsing options\n");
return false;
}
return true;
} }
static bool static bool

@ -180,6 +180,28 @@ MmsServer_setLocalIpAddress(MmsServer self, const char* localIpAddress)
} }
} }
void
MmsServer_setLocalAddresses(MmsServer self, const PSelector* pSelector, const SSelector* sSelector, const TSelector* tSelector)
{
if (pSelector)
{
self->pSel = *pSelector;
self->checkCalledPSel = true;
}
if (sSelector)
{
self->sSel = *sSelector;
self->checkCalledSSel = true;
}
if (tSelector)
{
self->tSel = *tSelector;
self->checkCalledTSel = true;
}
}
bool bool
MmsServer_isRunning(MmsServer self) MmsServer_isRunning(MmsServer self)
{ {
@ -723,6 +745,8 @@ MmsServer_startListening(MmsServer self, int tcpPort)
if (tcpPort != -1) if (tcpPort != -1)
IsoServer_setTcpPort(isoServer, tcpPort); IsoServer_setTcpPort(isoServer, tcpPort);
IsoServer_setLocalAddresses(isoServer, &self->pSel, &self->sSel, &self->tSel);
IsoServer_startListening(isoServer); IsoServer_startListening(isoServer);
elem = LinkedList_getNext(elem); elem = LinkedList_getNext(elem);
@ -770,6 +794,10 @@ MmsServer_startListeningThreadless(MmsServer self, int tcpPort)
if (tcpPort != -1) if (tcpPort != -1)
IsoServer_setTcpPort(isoServer, tcpPort); IsoServer_setTcpPort(isoServer, tcpPort);
IsoServer_setLocalAddresses(isoServer, self->checkCalledPSel ? &self->pSel : NULL,
self->checkCalledSSel ? &self->sSel : NULL,
self->checkCalledTSel ? &self->tSel : NULL);
IsoServer_startListeningThreadless(isoServer); IsoServer_startListeningThreadless(isoServer);
elem = LinkedList_getNext(elem); elem = LinkedList_getNext(elem);

@ -1,7 +1,7 @@
/* /*
* iso_presentation.c * iso_presentation.c
* *
* Copyright 2013-2022 Michael Zillgith * Copyright 2013-2024 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -35,7 +35,6 @@
#define DEBUG_PRES 0 #define DEBUG_PRES 0
#endif #endif
static uint8_t calledPresentationSelector[] = { 0x00, 0x00, 0x00, 0x01 }; static uint8_t calledPresentationSelector[] = { 0x00, 0x00, 0x00, 0x01 };
static uint8_t asn_id_as_acse[] = { 0x52, 0x01, 0x00, 0x01 }; static uint8_t asn_id_as_acse[] = { 0x52, 0x01, 0x00, 0x01 };
@ -58,8 +57,7 @@ encodeAcceptBer(uint8_t* buffer, int bufPos)
} }
static int static int
encodeUserData(uint8_t* buffer, int bufPos, encodeUserData(uint8_t* buffer, int bufPos, BufferChain payload, bool encode, uint8_t contextId)
BufferChain payload, bool encode, uint8_t contextId)
{ {
int payloadLength = payload->length; int payloadLength = payload->length;
@ -73,7 +71,8 @@ encodeUserData(uint8_t* buffer, int bufPos,
fullyEncodedDataLength += BerEncoder_determineLengthSize(encodedDataSetLength) + 1; fullyEncodedDataLength += BerEncoder_determineLengthSize(encodedDataSetLength) + 1;
if (encode) { if (encode)
{
/* fully-encoded-data */ /* fully-encoded-data */
bufPos = BerEncoder_encodeTL(0x61, fullyEncodedDataLength, buffer, bufPos); bufPos = BerEncoder_encodeTL(0x61, fullyEncodedDataLength, buffer, bufPos);
bufPos = BerEncoder_encodeTL(0x30, encodedDataSetLength, buffer, bufPos); bufPos = BerEncoder_encodeTL(0x30, encodedDataSetLength, buffer, bufPos);
@ -87,7 +86,8 @@ encodeUserData(uint8_t* buffer, int bufPos,
return bufPos; return bufPos;
} }
else { else
{
int encodedUserDataLength = fullyEncodedDataLength + 1; int encodedUserDataLength = fullyEncodedDataLength + 1;
encodedUserDataLength += BerEncoder_determineLengthSize(fullyEncodedDataLength); encodedUserDataLength += BerEncoder_determineLengthSize(fullyEncodedDataLength);
@ -195,7 +195,8 @@ parseFullyEncodedData(IsoPresentation* self, uint8_t* buffer, int len, int bufPo
int endPos = bufPos + len; int endPos = bufPos + len;
if (buffer[bufPos++] != 0x30) { if (buffer[bufPos++] != 0x30)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: user-data parse error\n"); printf("PRES: user-data parse error\n");
return -1; return -1;
@ -203,7 +204,8 @@ parseFullyEncodedData(IsoPresentation* self, uint8_t* buffer, int len, int bufPo
bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, endPos); bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, endPos);
if (bufPos < 0) { if (bufPos < 0)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: wrong parameter length\n"); printf("PRES: wrong parameter length\n");
return -1; return -1;
@ -211,19 +213,22 @@ parseFullyEncodedData(IsoPresentation* self, uint8_t* buffer, int len, int bufPo
endPos = bufPos + len; endPos = bufPos + len;
while (bufPos < endPos) { while (bufPos < endPos)
{
uint8_t tag = buffer[bufPos++]; uint8_t tag = buffer[bufPos++];
int length; int length;
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, endPos); bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, endPos);
if (bufPos < 0) { if (bufPos < 0)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: wrong parameter length\n"); printf("PRES: wrong parameter length\n");
return -1; return -1;
} }
switch (tag) { switch (tag)
{
case 0x02: /* presentation-context-identifier */ case 0x02: /* presentation-context-identifier */
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: presentation-context-identifier\n"); printf("PRES: presentation-context-identifier\n");
@ -262,7 +267,8 @@ parseFullyEncodedData(IsoPresentation* self, uint8_t* buffer, int len, int bufPo
} }
} }
if (!userDataPresent) { if (!userDataPresent)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: user-data not present\n"); printf("PRES: user-data not present\n");
return -1; return -1;
@ -280,19 +286,22 @@ parsePCDLEntry(IsoPresentation* self, uint8_t* buffer, int totalLength, int bufP
bool isAcse = false; bool isAcse = false;
bool isMms = false; bool isMms = false;
while (bufPos < endPos) { while (bufPos < endPos)
{
uint8_t tag = buffer[bufPos++]; uint8_t tag = buffer[bufPos++];
int len; int len;
bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, endPos); bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, endPos);
if (bufPos < 0) { if (bufPos < 0)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: Invalid PDU\n"); printf("PRES: Invalid PDU\n");
return -1; return -1;
} }
switch (tag) { switch (tag)
{
case 0x02: /* presentation-context-identifier */ case 0x02: /* presentation-context-identifier */
contextId = BerDecoder_decodeUint32(buffer, len, bufPos); contextId = BerDecoder_decodeUint32(buffer, len, bufPos);
bufPos += len; bufPos += len;
@ -302,11 +311,13 @@ parsePCDLEntry(IsoPresentation* self, uint8_t* buffer, int totalLength, int bufP
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: abstract-syntax-name with len %i\n", len); printf("PRES: abstract-syntax-name with len %i\n", len);
if (len == 5) { if (len == 5)
{
if (memcmp(buffer + bufPos, asn_id_mms, 5) == 0) if (memcmp(buffer + bufPos, asn_id_mms, 5) == 0)
isMms = true; isMms = true;
} }
else if (len == 4) { else if (len == 4)
{
if (memcmp(buffer + bufPos, asn_id_as_acse, 4) == 0) if (memcmp(buffer + bufPos, asn_id_as_acse, 4) == 0)
isAcse = true; isAcse = true;
} }
@ -333,25 +344,29 @@ parsePCDLEntry(IsoPresentation* self, uint8_t* buffer, int totalLength, int bufP
} }
} }
if (contextId < 0) { if (contextId < 0)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: ContextId not defined!\n"); printf("PRES: ContextId not defined!\n");
return -1; return -1;
} }
if ((isAcse == false) && (isMms == false)) { if ((isAcse == false) && (isMms == false))
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: not an ACSE or MMS context definition\n"); printf("PRES: not an ACSE or MMS context definition\n");
return -1; return -1;
} }
if (isMms) { if (isMms)
{
self->mmsContextId = (uint8_t)contextId; self->mmsContextId = (uint8_t)contextId;
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: MMS context id is %i\n", contextId); printf("PRES: MMS context id is %i\n", contextId);
} }
else { else
{
self->acseContextId = (uint8_t)contextId; self->acseContextId = (uint8_t)contextId;
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: ACSE context id is %i\n", contextId); printf("PRES: ACSE context id is %i\n", contextId);
@ -365,7 +380,8 @@ parsePresentationContextDefinitionList(IsoPresentation* self, uint8_t* buffer, i
{ {
int endPos = bufPos + totalLength; int endPos = bufPos + totalLength;
while (bufPos < endPos) { while (bufPos < endPos)
{
uint8_t tag = buffer[bufPos++]; uint8_t tag = buffer[bufPos++];
int len; int len;
@ -373,7 +389,8 @@ parsePresentationContextDefinitionList(IsoPresentation* self, uint8_t* buffer, i
if (bufPos < 0) if (bufPos < 0)
return -1; return -1;
switch (tag) { switch (tag)
{
case 0x30: case 0x30:
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: parse pcd entry\n"); printf("PRES: parse pcd entry\n");
@ -381,8 +398,10 @@ parsePresentationContextDefinitionList(IsoPresentation* self, uint8_t* buffer, i
if (bufPos < 0) if (bufPos < 0)
return -1; return -1;
break; break;
case 0x00: /* indefinite length end tag -> ignore */ case 0x00: /* indefinite length end tag -> ignore */
break; break;
default: default:
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: unknown tag in presentation-context-definition-list\n"); printf("PRES: unknown tag in presentation-context-definition-list\n");
@ -404,11 +423,13 @@ parseNormalModeParameters(IsoPresentation* self, uint8_t* buffer, int totalLengt
bool hasUserData = false; bool hasUserData = false;
while (bufPos < endPos) { while (bufPos < endPos)
{
uint8_t tag = buffer[bufPos++]; uint8_t tag = buffer[bufPos++];
int len; int len;
if (bufPos == endPos) { if (bufPos == endPos)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: invalid message\n"); printf("PRES: invalid message\n");
return -1; return -1;
@ -416,20 +437,24 @@ parseNormalModeParameters(IsoPresentation* self, uint8_t* buffer, int totalLengt
bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, endPos); bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, endPos);
if (bufPos < 0) { if (bufPos < 0)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: wrong parameter length\n"); printf("PRES: wrong parameter length\n");
return -1; return -1;
} }
switch (tag) { switch (tag)
{
case 0x81: /* calling-presentation-selector */ case 0x81: /* calling-presentation-selector */
if (len > 16) { if (len > 16)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: calling-presentation-sel too large\n"); printf("PRES: calling-presentation-sel too large\n");
} }
else { else
{
self->callingPresentationSelector.size = len; self->callingPresentationSelector.size = len;
int i; int i;
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
@ -441,11 +466,13 @@ parseNormalModeParameters(IsoPresentation* self, uint8_t* buffer, int totalLengt
case 0x82: /* called-presentation-selector */ case 0x82: /* called-presentation-selector */
if (len > 16) { if (len > 16)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: called-presentation-sel too large\n"); printf("PRES: called-presentation-sel too large\n");
} }
else { else
{
self->calledPresentationSelector.size = len; self->calledPresentationSelector.size = len;
int i; int i;
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
@ -457,7 +484,8 @@ parseNormalModeParameters(IsoPresentation* self, uint8_t* buffer, int totalLengt
case 0x83: /* responding-presentation-selector */ case 0x83: /* responding-presentation-selector */
if (len > 16) { if (len > 16)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: responding-presentation-sel too large\n"); printf("PRES: responding-presentation-sel too large\n");
} }
@ -505,7 +533,8 @@ parseNormalModeParameters(IsoPresentation* self, uint8_t* buffer, int totalLengt
} }
} }
if (hasUserData == false) { if (hasUserData == false)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: user-data is missing\n"); printf("PRES: user-data is missing\n");
@ -525,7 +554,8 @@ IsoPresentation_parseAcceptMessage(IsoPresentation* self, ByteBuffer* byteBuffer
uint8_t cpTag = buffer[bufPos++]; uint8_t cpTag = buffer[bufPos++];
if (cpTag != 0x31) { if (cpTag != 0x31)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: not a CPA message\n"); printf("PRES: not a CPA message\n");
return 0; return 0;
@ -535,31 +565,36 @@ IsoPresentation_parseAcceptMessage(IsoPresentation* self, ByteBuffer* byteBuffer
bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos);
if (bufPos < 0) { if (bufPos < 0)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: Invalid message\n"); printf("PRES: Invalid message\n");
return 0; return 0;
} }
while (bufPos < maxBufPos) { while (bufPos < maxBufPos)
{
uint8_t tag = buffer[bufPos++]; uint8_t tag = buffer[bufPos++];
bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos);
if (bufPos < 0) { if (bufPos < 0)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: wrong parameter length\n"); printf("PRES: wrong parameter length\n");
return 0; return 0;
} }
switch (tag) { switch (tag)
{
case 0xa0: /* mode-selector */ case 0xa0: /* mode-selector */
bufPos += len; /* ignore content since only normal mode is allowed */ bufPos += len; /* ignore content since only normal mode is allowed */
break; break;
case 0xa2: /* normal-mode-parameters */ case 0xa2: /* normal-mode-parameters */
bufPos = parseNormalModeParameters(self, buffer, len, bufPos); bufPos = parseNormalModeParameters(self, buffer, len, bufPos);
if (bufPos < 0) { if (bufPos < 0)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: error parsing normal-mode-parameters\n"); printf("PRES: error parsing normal-mode-parameters\n");
return 0; return 0;
@ -568,6 +603,7 @@ IsoPresentation_parseAcceptMessage(IsoPresentation* self, ByteBuffer* byteBuffer
break; break;
case 0x00: /* indefinite length end tag -> ignore */ case 0x00: /* indefinite length end tag -> ignore */
break; break;
default: default:
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: CPA unknown tag %i\n", tag); printf("PRES: CPA unknown tag %i\n", tag);
@ -582,7 +618,13 @@ IsoPresentation_parseAcceptMessage(IsoPresentation* self, ByteBuffer* byteBuffer
void void
IsoPresentation_init(IsoPresentation* self) IsoPresentation_init(IsoPresentation* self)
{ {
(void)self; self->checkCalledPSelector = NULL;
}
void
IsoPresentation_setCalledPSelector(IsoPresentation* self, const PSelector* calledPSelector)
{
self->checkCalledPSelector = calledPSelector;
} }
void void
@ -670,7 +712,7 @@ IsoPresentation_parseUserData(IsoPresentation* self, ByteBuffer* readBuffer)
return 0; return 0;
} }
if (buffer[bufPos++] != 0x30) if (buffer[bufPos++] != 0x30) /* PDV list */
return 0; return 0;
bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos);
@ -703,10 +745,10 @@ IsoPresentation_parseUserData(IsoPresentation* self, ByteBuffer* readBuffer)
case 0x06: /* transfer-syntax-name */ case 0x06: /* transfer-syntax-name */
{ {
/* check if basic-encoding (2.1.1 - 51 01) */ /* check if basic-encoding (2.1.1 - 51 01) */
if ((buffer[bufPos] != 0x51) || (buffer[bufPos + 1] != 0x01)) { if ((buffer[bufPos] != 0x51) || (buffer[bufPos + 1] != 0x01))
if (DEBUG_PRES) { {
if (DEBUG_PRES)
printf("PRES: unknown transfer-syntax-name\n"); printf("PRES: unknown transfer-syntax-name\n");
}
return 0; return 0;
} }
@ -715,7 +757,6 @@ IsoPresentation_parseUserData(IsoPresentation* self, ByteBuffer* readBuffer)
} }
break; break;
case 0xa0: /* presentation data */ case 0xa0: /* presentation data */
{ {
if (hasAbstractSyntaxName == false) { if (hasAbstractSyntaxName == false) {
@ -741,7 +782,26 @@ IsoPresentation_parseUserData(IsoPresentation* self, ByteBuffer* readBuffer)
return 0; return 0;
} }
int static bool
checkCalledPSelector(IsoPresentation* self)
{
if (self->checkCalledPSelector == NULL)
return true;
if (self->calledPresentationSelector.size != self->checkCalledPSelector->size)
return false;
int i;
for (i = 0; i < self->calledPresentationSelector.size; i++)
{
if (self->calledPresentationSelector.value[i] != self->checkCalledPSelector->value[i])
return false;
}
return true;
}
bool
IsoPresentation_parseConnect(IsoPresentation* self, ByteBuffer* byteBuffer) IsoPresentation_parseConnect(IsoPresentation* self, ByteBuffer* byteBuffer)
{ {
uint8_t* buffer = byteBuffer->buffer; uint8_t* buffer = byteBuffer->buffer;
@ -752,51 +812,58 @@ IsoPresentation_parseConnect(IsoPresentation* self, ByteBuffer* byteBuffer)
uint8_t cpTag = buffer[bufPos++]; uint8_t cpTag = buffer[bufPos++];
if (cpTag != 0x31) { if (cpTag != 0x31)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: not a CP type\n"); printf("PRES: not a CP type\n");
return 0; return false;
} }
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_PRES) if (DEBUG_PRES)
printf("PRES: invalid message!\n"); printf("PRES: invalid message!\n");
return 0; return false;
} }
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: CPType with len %i\n", len); printf("PRES: CPType with len %i\n", len);
while (bufPos < maxBufPos) { while (bufPos < maxBufPos)
{
uint8_t tag = buffer[bufPos++]; uint8_t tag = buffer[bufPos++];
bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos);
if (bufPos < 0) { if (bufPos < 0)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: invalid message!\n"); printf("PRES: invalid message!\n");
return 0; return false;
} }
switch (tag) { switch (tag)
{
case 0xa0: /* mode-selection */ case 0xa0: /* mode-selection */
{ {
if (buffer[bufPos++] != 0x80) { if (buffer[bufPos++] != 0x80)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: mode-value of wrong type!\n"); printf("PRES: mode-value of wrong type!\n");
return 0; return false;
} }
bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos);
if (bufPos < 0) { if (bufPos < 0)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: invalid message!\n"); printf("PRES: invalid message!\n");
return 0; return false;
} }
uint32_t modeSelector = BerDecoder_decodeUint32(buffer, len, bufPos); uint32_t modeSelector = BerDecoder_decodeUint32(buffer, len, bufPos);
@ -810,12 +877,22 @@ IsoPresentation_parseConnect(IsoPresentation* self, ByteBuffer* byteBuffer)
case 0xa2: /* normal-mode-parameters */ case 0xa2: /* normal-mode-parameters */
bufPos = parseNormalModeParameters(self, buffer, len, bufPos); bufPos = parseNormalModeParameters(self, buffer, len, bufPos);
if (bufPos < 0) { if (bufPos < 0)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: error parsing normal-mode-parameters\n"); printf("PRES: error parsing normal-mode-parameters\n");
return 0; return false;
}
else
{
if (checkCalledPSelector(self) == false)
{
if (DEBUG_PRES)
printf("PRES: called presentation selector not matching\n");
return false;
} }
else {
hasNormalModeParameters = true; hasNormalModeParameters = true;
} }
@ -830,14 +907,15 @@ IsoPresentation_parseConnect(IsoPresentation* self, ByteBuffer* byteBuffer)
} }
} }
if (hasNormalModeParameters == false) { if (hasNormalModeParameters == false)
{
if (DEBUG_PRES) if (DEBUG_PRES)
printf("PRES: error - normal mode parameters are missing\n"); printf("PRES: error - normal mode parameters are missing\n");
return 0; return false;
} }
return 1; return true;
} }
void void

@ -1,7 +1,7 @@
/* /*
* iso_connection.c * iso_connection.c
* *
* Copyright 2013-2023 Michael Zillgith * Copyright 2013-2024 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -171,8 +171,8 @@ void
IsoConnection_handleTcpConnection(IsoConnection self, bool isSingleThread) IsoConnection_handleTcpConnection(IsoConnection self, bool isSingleThread)
{ {
#if (CONFIG_MMS_SINGLE_THREADED != 1) #if (CONFIG_MMS_SINGLE_THREADED != 1)
if (isSingleThread == false) { if (isSingleThread == false)
{
IsoConnection_callTickHandler(self); IsoConnection_callTickHandler(self);
if (Handleset_waitReady(self->handleSet, 10) < 1) if (Handleset_waitReady(self->handleSet, 10) < 1)
@ -220,12 +220,14 @@ IsoConnection_handleTcpConnection(IsoConnection self, bool isSingleThread)
ByteBuffer* sessionUserData = IsoSession_getUserData(self->session); ByteBuffer* sessionUserData = IsoSession_getUserData(self->session);
switch (sIndication) { switch (sIndication)
{
case SESSION_CONNECT: case SESSION_CONNECT:
if (DEBUG_ISO_SERVER) if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: session connect indication\n"); printf("ISO_SERVER: iso_connection: session connect indication\n");
if (IsoPresentation_parseConnect(self->presentation, sessionUserData)) { if (IsoPresentation_parseConnect(self->presentation, sessionUserData))
{
if (DEBUG_ISO_SERVER) if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: presentation ok\n"); printf("ISO_SERVER: iso_connection: presentation ok\n");
@ -233,8 +235,8 @@ IsoConnection_handleTcpConnection(IsoConnection self, bool isSingleThread)
AcseIndication aIndication = AcseConnection_parseMessage(self->acseConnection, acseBuffer); AcseIndication aIndication = AcseConnection_parseMessage(self->acseConnection, acseBuffer);
if (aIndication == ACSE_ASSOCIATE) { if (aIndication == ACSE_ASSOCIATE)
{
#if (CONFIG_MMS_THREADLESS_STACK != 1) #if (CONFIG_MMS_THREADLESS_STACK != 1)
IsoConnection_lock(self); IsoConnection_lock(self);
#endif #endif
@ -250,7 +252,8 @@ IsoConnection_handleTcpConnection(IsoConnection self, bool isSingleThread)
ByteBuffer_wrap(&mmsResponseBuffer, self->sendBuffer, 0, SEND_BUF_SIZE); ByteBuffer_wrap(&mmsResponseBuffer, self->sendBuffer, 0, SEND_BUF_SIZE);
if (self->msgRcvdHandler != NULL) { if (self->msgRcvdHandler != NULL)
{
self->msgRcvdHandler(self->handlerParameter, self->msgRcvdHandler(self->handlerParameter,
&mmsRequest, &mmsResponseBuffer); &mmsRequest, &mmsResponseBuffer);
} }
@ -261,7 +264,8 @@ IsoConnection_handleTcpConnection(IsoConnection self, bool isSingleThread)
BufferChain_init(mmsBufferPart, mmsResponseBuffer.size, mmsResponseBuffer.size, NULL, BufferChain_init(mmsBufferPart, mmsResponseBuffer.size, mmsResponseBuffer.size, NULL,
self->sendBuffer); self->sendBuffer);
if (mmsResponseBuffer.size > 0) { if (mmsResponseBuffer.size > 0)
{
if (DEBUG_ISO_SERVER) if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: application payload size: %i\n", printf("ISO_SERVER: iso_connection: application payload size: %i\n",
mmsResponseBuffer.size); mmsResponseBuffer.size);
@ -293,7 +297,8 @@ IsoConnection_handleTcpConnection(IsoConnection self, bool isSingleThread)
CotpConnection_sendDataMessage(self->cotpConnection, sessionBufferPart); CotpConnection_sendDataMessage(self->cotpConnection, sessionBufferPart);
} }
else { else
{
if (DEBUG_ISO_SERVER) if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: association error. No response from application!\n"); printf("ISO_SERVER: iso_connection: association error. No response from application!\n");
} }
@ -302,12 +307,12 @@ IsoConnection_handleTcpConnection(IsoConnection self, bool isSingleThread)
IsoConnection_unlock(self); IsoConnection_unlock(self);
#endif #endif
} }
else { else
{
if (DEBUG_ISO_SERVER) if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: acse association failed\n"); printf("ISO_SERVER: iso_connection: acse association failed\n");
self->state = ISO_CON_STATE_STOPPED; self->state = ISO_CON_STATE_STOPPED;
} }
} }
else { else {
self->state = ISO_CON_STATE_STOPPED; self->state = ISO_CON_STATE_STOPPED;
@ -318,14 +323,16 @@ IsoConnection_handleTcpConnection(IsoConnection self, bool isSingleThread)
if (DEBUG_ISO_SERVER) if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: session data indication\n"); printf("ISO_SERVER: iso_connection: session data indication\n");
if (!IsoPresentation_parseUserData(self->presentation, sessionUserData)) { if (!IsoPresentation_parseUserData(self->presentation, sessionUserData))
{
if (DEBUG_ISO_SERVER) if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: presentation layer error\n"); printf("ISO_SERVER: presentation layer error\n");
self->state = ISO_CON_STATE_STOPPED; self->state = ISO_CON_STATE_STOPPED;
break; break;
} }
if (self->presentation->nextContextId == self->presentation->mmsContextId) { if (self->presentation->nextContextId == self->presentation->mmsContextId)
{
if (DEBUG_ISO_SERVER) if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: mms message\n"); printf("ISO_SERVER: iso_connection: mms message\n");
@ -339,15 +346,15 @@ IsoConnection_handleTcpConnection(IsoConnection self, bool isSingleThread)
ByteBuffer_wrap(&mmsResponseBuffer, self->sendBuffer, 0, SEND_BUF_SIZE); ByteBuffer_wrap(&mmsResponseBuffer, self->sendBuffer, 0, SEND_BUF_SIZE);
if (self->msgRcvdHandler != NULL) { if (self->msgRcvdHandler != NULL)
{
self->msgRcvdHandler(self->handlerParameter, self->msgRcvdHandler(self->handlerParameter,
mmsRequest, &mmsResponseBuffer); mmsRequest, &mmsResponseBuffer);
} }
/* send a response if required */ /* send a response if required */
if (mmsResponseBuffer.size > 0) { if (mmsResponseBuffer.size > 0)
{
struct sBufferChain mmsBufferPartStruct; struct sBufferChain mmsBufferPartStruct;
BufferChain mmsBufferPart = &mmsBufferPartStruct; BufferChain mmsBufferPart = &mmsBufferPartStruct;
@ -376,7 +383,8 @@ IsoConnection_handleTcpConnection(IsoConnection self, bool isSingleThread)
IsoConnection_unlock(self); IsoConnection_unlock(self);
#endif #endif
} }
else { else
{
if (DEBUG_ISO_SERVER) if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: unknown presentation layer context!"); printf("ISO_SERVER: iso_connection: unknown presentation layer context!");
} }
@ -387,7 +395,8 @@ IsoConnection_handleTcpConnection(IsoConnection self, bool isSingleThread)
if (DEBUG_ISO_SERVER) if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: session finish indication\n"); printf("ISO_SERVER: iso_connection: session finish indication\n");
if (IsoPresentation_parseUserData(self->presentation, sessionUserData)) { if (IsoPresentation_parseUserData(self->presentation, sessionUserData))
{
if (DEBUG_ISO_SERVER) if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: presentation ok\n"); printf("ISO_SERVER: iso_connection: presentation ok\n");
@ -491,11 +500,13 @@ IsoConnection_create(Socket socket, IsoServer isoServer, bool isSingleThread)
{ {
IsoConnection self = (IsoConnection) GLOBAL_CALLOC(1, sizeof(struct sIsoConnection)); IsoConnection self = (IsoConnection) GLOBAL_CALLOC(1, sizeof(struct sIsoConnection));
if (self) { if (self)
{
self->socket = socket; self->socket = socket;
#if (CONFIG_MMS_SUPPORT_TLS == 1) #if (CONFIG_MMS_SUPPORT_TLS == 1)
if (IsoServer_getTLSConfiguration(isoServer) != NULL) { if (IsoServer_getTLSConfiguration(isoServer) != NULL)
{
self->tlsSocket = TLSSocket_create(socket, IsoServer_getTLSConfiguration(isoServer), true); self->tlsSocket = TLSSocket_create(socket, IsoServer_getTLSConfiguration(isoServer), true);
if (self->tlsSocket == NULL) { if (self->tlsSocket == NULL) {
@ -537,6 +548,11 @@ IsoConnection_create(Socket socket, IsoServer isoServer, bool isSingleThread)
CotpConnection_init(self->cotpConnection, self->socket, &(self->rcvBuffer), &(self->cotpReadBuffer), &(self->cotpWriteBuffer), CotpConnection_init(self->cotpConnection, self->socket, &(self->rcvBuffer), &(self->cotpReadBuffer), &(self->cotpWriteBuffer),
socketExtensionBuffer, socketExtensionBufferSize); socketExtensionBuffer, socketExtensionBufferSize);
const TSelector* tSel = private_IsoServer_getLocalTSelector(isoServer);
if (tSel)
CotpConnection_setCheckDstSelector(self->cotpConnection, tSel);
#if (CONFIG_MMS_SUPPORT_TLS == 1) #if (CONFIG_MMS_SUPPORT_TLS == 1)
if (self->tlsSocket) if (self->tlsSocket)
self->cotpConnection->tlsSocket = self->tlsSocket; self->cotpConnection->tlsSocket = self->tlsSocket;
@ -545,9 +561,19 @@ IsoConnection_create(Socket socket, IsoServer isoServer, bool isSingleThread)
self->session = (IsoSession*) GLOBAL_CALLOC(1, sizeof(IsoSession)); self->session = (IsoSession*) GLOBAL_CALLOC(1, sizeof(IsoSession));
IsoSession_init(self->session); IsoSession_init(self->session);
const SSelector* sSel = private_IsoServer_getLocalSSelector(isoServer);
if (sSel)
IsoSession_setCalledSSelector(self->session, sSel);
self->presentation = (IsoPresentation*) GLOBAL_CALLOC(1, sizeof(IsoPresentation)); self->presentation = (IsoPresentation*) GLOBAL_CALLOC(1, sizeof(IsoPresentation));
IsoPresentation_init(self->presentation); IsoPresentation_init(self->presentation);
PSelector* pSel = (PSelector*) private_IsoServer_getLocalPSelector(isoServer);
if (pSel)
IsoPresentation_setCalledPSelector(self->presentation, pSel);
self->acseConnection = (AcseConnection*) GLOBAL_CALLOC(1, sizeof(AcseConnection)); self->acseConnection = (AcseConnection*) GLOBAL_CALLOC(1, sizeof(AcseConnection));
#if (CONFIG_MMS_SUPPORT_TLS == 1) #if (CONFIG_MMS_SUPPORT_TLS == 1)
@ -563,7 +589,8 @@ IsoConnection_create(Socket socket, IsoServer isoServer, bool isSingleThread)
#if (CONFIG_MMS_SINGLE_THREADED == 0) #if (CONFIG_MMS_SINGLE_THREADED == 0)
#if (CONFIG_MMS_THREADLESS_STACK == 0) #if (CONFIG_MMS_THREADLESS_STACK == 0)
if (isSingleThread == false) { if (isSingleThread == false)
{
self->handleSet = Handleset_new(); self->handleSet = Handleset_new();
Handleset_addSocket(self->handleSet, self->socket); Handleset_addSocket(self->handleSet, self->socket);
self->thread = Thread_create((ThreadExecutionFunction) handleTcpConnection, self, false); self->thread = Thread_create((ThreadExecutionFunction) handleTcpConnection, self, false);
@ -607,7 +634,8 @@ IsoConnection_destroy(IsoConnection self)
Handleset_destroy(self->handleSet); Handleset_destroy(self->handleSet);
#endif #endif
if (self->cotpConnection) { if (self->cotpConnection)
{
if (self->cotpConnection->handleSet) if (self->cotpConnection->handleSet)
Handleset_destroy(self->cotpConnection->handleSet); Handleset_destroy(self->cotpConnection->handleSet);
@ -650,7 +678,8 @@ IsoConnection_sendMessage(IsoConnection self, ByteBuffer* message)
{ {
bool success = false; bool success = false;
if (self->state == ISO_CON_STATE_STOPPED) { if (self->state == ISO_CON_STATE_STOPPED)
{
if (DEBUG_ISO_SERVER) if (DEBUG_ISO_SERVER)
printf("DEBUG_ISO_SERVER: sendMessage: connection already stopped!\n"); printf("DEBUG_ISO_SERVER: sendMessage: connection already stopped!\n");
goto exit_error; goto exit_error;
@ -682,7 +711,8 @@ IsoConnection_sendMessage(IsoConnection self, ByteBuffer* message)
indication = CotpConnection_sendDataMessage(self->cotpConnection, sessionBuffer); indication = CotpConnection_sendDataMessage(self->cotpConnection, sessionBuffer);
if (DEBUG_ISO_SERVER) { if (DEBUG_ISO_SERVER)
{
if (indication != COTP_OK) if (indication != COTP_OK)
printf("ISO_SERVER: IsoConnection_sendMessage failed!\n"); printf("ISO_SERVER: IsoConnection_sendMessage failed!\n");
else else
@ -699,16 +729,19 @@ exit_error:
void void
IsoConnection_close(IsoConnection self) IsoConnection_close(IsoConnection self)
{ {
if (self->state != ISO_CON_STATE_TERMINATED) { if (self->state != ISO_CON_STATE_TERMINATED)
{
self->state = ISO_CON_STATE_STOPPED; self->state = ISO_CON_STATE_STOPPED;
#if (CONFIG_MMS_THREADLESS_STACK != 1) && (CONFIG_MMS_SINGLE_THREADED != 1) #if (CONFIG_MMS_THREADLESS_STACK != 1) && (CONFIG_MMS_SINGLE_THREADED != 1)
/* wait for connection thread to terminate */ /* wait for connection thread to terminate */
if (self->thread) { if (self->thread)
{
Thread_destroy(self->thread); Thread_destroy(self->thread);
self->thread = NULL; self->thread = NULL;
} }
else { else
{
finalizeIsoConnection(self); finalizeIsoConnection(self);
self->state = ISO_CON_STATE_TERMINATED; self->state = ISO_CON_STATE_TERMINATED;
} }

@ -90,6 +90,10 @@ struct sIsoServer {
#endif #endif
int connectionCounter; int connectionCounter;
const PSelector* localPSel;
const SSelector* localSSel;
const TSelector* localTSel;
}; };
static void static void
@ -421,7 +425,8 @@ setupIsoServer(IsoServer self)
self->serverSocket = (Socket) TcpServerSocket_create(self->localIpAddress, self->tcpPort); self->serverSocket = (Socket) TcpServerSocket_create(self->localIpAddress, self->tcpPort);
if (self->serverSocket == NULL) { if (self->serverSocket == NULL)
{
setState(self, ISO_SVR_STATE_ERROR); setState(self, ISO_SVR_STATE_ERROR);
success = false; success = false;
@ -462,7 +467,8 @@ exit_function:
static void static void
handleIsoConnections(IsoServer self, bool isSingleThread) handleIsoConnections(IsoServer self, bool isSingleThread)
{ {
if (isSingleThread) { if (isSingleThread)
{
/* /*
* NOTE: when running in multi thread mode the tick handler is called * NOTE: when running in multi thread mode the tick handler is called
* by the connection thread. * by the connection thread.
@ -475,11 +481,13 @@ handleIsoConnections(IsoServer self, bool isSingleThread)
Socket connectionSocket; Socket connectionSocket;
if ((connectionSocket = ServerSocket_accept((ServerSocket) self->serverSocket)) != NULL) { if ((connectionSocket = ServerSocket_accept((ServerSocket) self->serverSocket)) != NULL)
{
#if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) #if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1)
if (self->maxConnections > -1) { if (self->maxConnections > -1)
if (private_IsoServer_getConnectionCounter(self) >= self->maxConnections) { {
if (private_IsoServer_getConnectionCounter(self) >= self->maxConnections)
{
if (DEBUG_ISO_SERVER) if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: maximum number of connections reached -> reject connection attempt.\n"); printf("ISO_SERVER: maximum number of connections reached -> reject connection attempt.\n");
@ -491,7 +499,8 @@ handleIsoConnections(IsoServer self, bool isSingleThread)
#endif /* (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) */ #endif /* (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) */
#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS != -1) #if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS != -1)
if (private_IsoServer_getConnectionCounter(self) >= CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS) { if (private_IsoServer_getConnectionCounter(self) >= CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS)
{
if (DEBUG_ISO_SERVER) if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: maximum number of connections reached -> reject connection attempt.\n"); printf("ISO_SERVER: maximum number of connections reached -> reject connection attempt.\n");
@ -506,7 +515,8 @@ handleIsoConnections(IsoServer self, bool isSingleThread)
IsoConnection isoConnection = IsoConnection_create(connectionSocket, self, isSingleThread); IsoConnection isoConnection = IsoConnection_create(connectionSocket, self, isSingleThread);
if (isoConnection) { if (isoConnection)
{
addClientConnection(self, isoConnection); addClientConnection(self, isoConnection);
if (isSingleThread) if (isSingleThread)
@ -518,7 +528,8 @@ handleIsoConnections(IsoServer self, bool isSingleThread)
if (isSingleThread == false) if (isSingleThread == false)
IsoConnection_start(isoConnection); IsoConnection_start(isoConnection);
} }
else { else
{
Socket_destroy(connectionSocket); Socket_destroy(connectionSocket);
} }
} }
@ -534,7 +545,8 @@ isoServerThread(void* isoServerParam)
{ {
IsoServer self = (IsoServer) isoServerParam; IsoServer self = (IsoServer) isoServerParam;
if (!setupIsoServer(self)) { if (!setupIsoServer(self))
{
if (DEBUG_ISO_SERVER) if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: starting server failed!\n"); printf("ISO_SERVER: starting server failed!\n");
@ -569,7 +581,8 @@ IsoServer_create(TLSConfiguration tlsConfiguration)
{ {
IsoServer self = (IsoServer) GLOBAL_CALLOC(1, sizeof(struct sIsoServer)); IsoServer self = (IsoServer) GLOBAL_CALLOC(1, sizeof(struct sIsoServer));
if (self) { if (self)
{
self->state = ISO_SVR_STATE_IDLE; self->state = ISO_SVR_STATE_IDLE;
if (tlsConfiguration == NULL) if (tlsConfiguration == NULL)
@ -597,6 +610,10 @@ IsoServer_create(TLSConfiguration tlsConfiguration)
#endif /* (CONFIG_MMS_THREADLESS_STACK != 1) */ #endif /* (CONFIG_MMS_THREADLESS_STACK != 1) */
self->connectionCounter = 0; self->connectionCounter = 0;
self->localPSel = NULL;
self->localSSel = NULL;
self->localTSel = NULL;
} }
return self; return self;
@ -627,6 +644,15 @@ IsoServer_setLocalIpAddress(IsoServer self, const char* ipAddress)
self->localIpAddress = NULL; self->localIpAddress = NULL;
} }
void
IsoServer_setLocalAddresses(IsoServer self, const PSelector* pSel, const SSelector* sSel,
const TSelector* tSel)
{
self->localPSel = pSel;
self->localSSel = sSel;
self->localTSel = tSel;
}
IsoServerState IsoServerState
IsoServer_getState(IsoServer self) IsoServer_getState(IsoServer self)
{ {
@ -662,7 +688,8 @@ IsoServer_getTLSConfiguration(IsoServer self)
void void
IsoServer_startListening(IsoServer self) IsoServer_startListening(IsoServer self)
{ {
if (self->state == ISO_SVR_STATE_RUNNING) { if (self->state == ISO_SVR_STATE_RUNNING)
{
if (DEBUG_ISO_SERVER) if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: server already in RUNNING state!\n"); printf("ISO_SERVER: server already in RUNNING state!\n");
@ -695,13 +722,15 @@ exit_function:
void void
IsoServer_startListeningThreadless(IsoServer self) IsoServer_startListeningThreadless(IsoServer self)
{ {
if (!setupIsoServer(self)) { if (!setupIsoServer(self))
{
if (DEBUG_ISO_SERVER) if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: starting server failed!\n"); printf("ISO_SERVER: starting server failed!\n");
self->serverSocket = NULL; self->serverSocket = NULL;
} }
else { else
{
setState(self, ISO_SVR_STATE_RUNNING); setState(self, ISO_SVR_STATE_RUNNING);
if (DEBUG_ISO_SERVER) if (DEBUG_ISO_SERVER)
@ -714,16 +743,17 @@ IsoServer_waitReady(IsoServer self, unsigned int timeoutMs)
{ {
int result = -1; int result = -1;
if (getState(self) == ISO_SVR_STATE_RUNNING) { if (getState(self) == ISO_SVR_STATE_RUNNING)
{
if (self->handleset) { if (self->handleset)
{
result = Handleset_waitReady(self->handleset, timeoutMs); result = Handleset_waitReady(self->handleset, timeoutMs);
} }
else { else
{
if (DEBUG_ISO_SERVER) if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: internal error - no handleset!\n"); printf("ISO_SERVER: internal error - no handleset!\n");
} }
} }
return result; return result;
@ -747,7 +777,8 @@ stopListening(IsoServer self)
{ {
setState(self, ISO_SVR_STATE_STOPPED); setState(self, ISO_SVR_STATE_STOPPED);
if (self->serverSocket != NULL) { if (self->serverSocket)
{
ServerSocket_destroy((ServerSocket) self->serverSocket); ServerSocket_destroy((ServerSocket) self->serverSocket);
self->serverSocket = NULL; self->serverSocket = NULL;
} }
@ -760,7 +791,8 @@ IsoServer_stopListeningThreadless(IsoServer self)
closeAllOpenClientConnections(self); closeAllOpenClientConnections(self);
if (self->handleset) { if (self->handleset)
{
Handleset_destroy(self->handleset); Handleset_destroy(self->handleset);
self->handleset = NULL; self->handleset = NULL;
} }
@ -778,7 +810,8 @@ IsoServer_stopListening(IsoServer self)
if (self->serverThread != NULL) if (self->serverThread != NULL)
Thread_destroy(self->serverThread); Thread_destroy(self->serverThread);
if (self->serverSocket != NULL) { if (self->serverSocket != NULL)
{
ServerSocket_destroy((ServerSocket)self->serverSocket); ServerSocket_destroy((ServerSocket)self->serverSocket);
self->serverSocket = NULL; self->serverSocket = NULL;
} }
@ -789,7 +822,8 @@ IsoServer_stopListening(IsoServer self)
while (private_IsoServer_getConnectionCounter(self) > 0) while (private_IsoServer_getConnectionCounter(self) > 0)
Thread_sleep(10); Thread_sleep(10);
if (self->handleset) { if (self->handleset)
{
Handleset_destroy(self->handleset); Handleset_destroy(self->handleset);
self->handleset = NULL; self->handleset = NULL;
} }
@ -819,8 +853,8 @@ IsoServer_setConnectionHandler(IsoServer self, ConnectionIndicationHandler handl
void void
IsoServer_destroy(IsoServer self) IsoServer_destroy(IsoServer self)
{ {
if (self) { if (self)
{
#if (CONFIG_MMS_THREADLESS_STACK != 1) #if (CONFIG_MMS_THREADLESS_STACK != 1)
if (self->state == ISO_SVR_STATE_RUNNING) if (self->state == ISO_SVR_STATE_RUNNING)
IsoServer_stopListening(self); IsoServer_stopListening(self);
@ -895,3 +929,20 @@ private_IsoServer_getConnectionCounter(IsoServer self)
return connectionCounter; return connectionCounter;
} }
const PSelector*
private_IsoServer_getLocalPSelector(IsoServer self)
{
return self->localPSel;
}
const SSelector*
private_IsoServer_getLocalSSelector(IsoServer self)
{
return self->localSSel;
}
const TSelector*
private_IsoServer_getLocalTSelector(IsoServer self)
{
return self->localTSel;
}

@ -507,6 +507,14 @@ IsoSession_init(IsoSession* session)
session->calledSessionSelector.size = 2; session->calledSessionSelector.size = 2;
session->calledSessionSelector.value[0] = 0; session->calledSessionSelector.value[0] = 0;
session->calledSessionSelector.value[1] = 1; session->calledSessionSelector.value[1] = 1;
session->checkCalledSSelector = NULL;
}
void
IsoSession_setCalledSSelector(IsoSession* session, const SSelector* calledSSelector)
{
session->checkCalledSSelector = calledSSelector;
} }
ByteBuffer* ByteBuffer*
@ -515,6 +523,25 @@ IsoSession_getUserData(IsoSession* session)
return &session->userData; return &session->userData;
} }
static bool
checkCalledSSelector(IsoSession* self)
{
if (self->checkCalledSSelector == NULL)
return true;
if (self->calledSessionSelector.size != self->checkCalledSSelector->size)
return false;
int i;
for (i = 0; i < self->calledSessionSelector.size; i++)
{
if (self->calledSessionSelector.value[i] != self->checkCalledSSelector->value[i])
return false;
}
return true;
}
IsoSessionIndication IsoSessionIndication
IsoSession_parseMessage(IsoSession* self, ByteBuffer* message) IsoSession_parseMessage(IsoSession* self, ByteBuffer* message)
{ {
@ -537,10 +564,18 @@ IsoSession_parseMessage(IsoSession* self, ByteBuffer* message)
return SESSION_ERROR; return SESSION_ERROR;
if (parseSessionHeaderParameters(self, message, length) == SESSION_OK) if (parseSessionHeaderParameters(self, message, length) == SESSION_OK)
{ {
//TODO check called S-selector when configured if (checkCalledSSelector(self))
{
return SESSION_CONNECT; return SESSION_CONNECT;
} }
else else
{
if (DEBUG_SESSION)
printf("SESSION: wrong called S-selector value\n");
return SESSION_ERROR;
}
}
else
{ {
if (DEBUG_SESSION) if (DEBUG_SESSION)
printf("SESSION: error parsing connect spdu\n"); printf("SESSION: error parsing connect spdu\n");

Loading…
Cancel
Save