- MMS client: improved handling of malformed messages when reading data

- MMS client: improved handling of malformed messages when receiving reports
- MMS client: fixed potential memory leak when receiving malformed messages
pull/119/head
Michael Zillgith 7 years ago
parent 1c461009c2
commit 3d8ab44a49

@ -95,13 +95,15 @@ namespace IEC61850
private IntPtr self = IntPtr.Zero; private IntPtr self = IntPtr.Zero;
private bool selfDestroy = false; private bool selfDestroy = false;
public MmsConnection() { public MmsConnection()
{
selfDestroy = true; selfDestroy = true;
self = MmsConnection_create(); self = MmsConnection_create();
} }
internal MmsConnection(IntPtr mmsConnection) { internal MmsConnection(IntPtr mmsConnection)
{
self = mmsConnection; self = mmsConnection;
} }
@ -125,7 +127,8 @@ namespace IEC61850
{ {
int mmsError; int mmsError;
if (self == IntPtr.Zero) { if (self == IntPtr.Zero)
{
throw new IedConnectionException("Pointer is Zero!"); throw new IedConnectionException("Pointer is Zero!");
} }
@ -149,7 +152,8 @@ namespace IEC61850
/// Sets the local detail (maximum MMS PDU size) /// Sets the local detail (maximum MMS PDU size)
/// </summary> /// </summary>
/// <param name="localDetail">maximum accepted MMS PDU size in bytes</param> /// <param name="localDetail">maximum accepted MMS PDU size in bytes</param>
public void SetLocalDetail(int localDetail) { public void SetLocalDetail(int localDetail)
{
MmsConnection_setLocalDetail(self, localDetail); MmsConnection_setLocalDetail(self, localDetail);
} }
@ -157,7 +161,8 @@ namespace IEC61850
/// Gets the local detail (maximum MMS PDU size) /// Gets the local detail (maximum MMS PDU size)
/// </summary> /// </summary>
/// <returns>maximum accepted MMS PDU size in bytes</returns> /// <returns>maximum accepted MMS PDU size in bytes</returns>
public int GetLocalDetail() { public int GetLocalDetail()
{
return MmsConnection_getLocalDetail(self); return MmsConnection_getLocalDetail(self);
} }
@ -171,7 +176,8 @@ namespace IEC61850
{ {
IntPtr linkedList = LinkedList_create(); IntPtr linkedList = LinkedList_create();
foreach (string variableName in variables) { foreach (string variableName in variables)
{
IntPtr handle = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(variableName); IntPtr handle = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(variableName);
LinkedList_add(linkedList, handle); LinkedList_add(linkedList, handle);
@ -261,7 +267,8 @@ namespace IEC61850
public List<MmsJournalVariable> GetJournalVariables() public List<MmsJournalVariable> GetJournalVariables()
{ {
if (variables == null) { if (variables == null)
{
IntPtr linkedList = MmsJournalEntry_getJournalVariables(self); IntPtr linkedList = MmsJournalEntry_getJournalVariables(self);
@ -269,7 +276,8 @@ namespace IEC61850
variables = new List<MmsJournalVariable>(); variables = new List<MmsJournalVariable>();
while (element != IntPtr.Zero) { while (element != IntPtr.Zero)
{
MmsJournalVariable journalVariable = new MmsJournalVariable(LinkedList_getData(element)); MmsJournalVariable journalVariable = new MmsJournalVariable(LinkedList_getData(element));
variables.Add(journalVariable); variables.Add(journalVariable);
@ -304,7 +312,8 @@ namespace IEC61850
public void Dispose() public void Dispose()
{ {
if (self != IntPtr.Zero) { if (self != IntPtr.Zero)
{
MmsJournalEntry_destroy(self); MmsJournalEntry_destroy(self);
self = IntPtr.Zero; self = IntPtr.Zero;
} }
@ -675,7 +684,8 @@ namespace IEC61850
/// so the garbage collector can reclaim the memory that the <see cref="IEC61850.Client.IedConnection"/> was occupying.</remarks> /// so the garbage collector can reclaim the memory that the <see cref="IEC61850.Client.IedConnection"/> was occupying.</remarks>
public void Dispose() public void Dispose()
{ {
if (connection != IntPtr.Zero) { if (connection != IntPtr.Zero)
{
IedConnection_destroy(connection); IedConnection_destroy(connection);
@ -722,10 +732,12 @@ namespace IEC61850
/// <value>The connect timeout in milliseconds</value> /// <value>The connect timeout in milliseconds</value>
public UInt32 ConnectTimeout public UInt32 ConnectTimeout
{ {
get { get
{
return connectTimeout; return connectTimeout;
} }
set { set
{
connectTimeout = value; connectTimeout = value;
} }
} }
@ -736,10 +748,12 @@ namespace IEC61850
/// <value>The maximum allowed size of an MMS PDU.</value> /// <value>The maximum allowed size of an MMS PDU.</value>
public int MaxPduSize public int MaxPduSize
{ {
get { get
{
return GetMmsConnection().GetLocalDetail(); return GetMmsConnection().GetLocalDetail();
} }
set { set
{
GetMmsConnection().SetLocalDetail(value); GetMmsConnection().SetLocalDetail(value);
} }
} }
@ -860,11 +874,13 @@ namespace IEC61850
List<string> newList = new List<string>(); List<string> newList = new List<string>();
if (fileDirectory == false) { if (fileDirectory == false)
{
IntPtr element = LinkedList_getNext(linkedList); IntPtr element = LinkedList_getNext(linkedList);
while (element != IntPtr.Zero) { while (element != IntPtr.Zero)
{
string ld = Marshal.PtrToStringAnsi(LinkedList_getData(element)); string ld = Marshal.PtrToStringAnsi(LinkedList_getData(element));
newList.Add(ld); newList.Add(ld);
@ -874,7 +890,8 @@ namespace IEC61850
LinkedList_destroy(linkedList); LinkedList_destroy(linkedList);
} }
else { else
{
IntPtr element = LinkedList_getNext(linkedList); IntPtr element = LinkedList_getNext(linkedList);
@ -911,7 +928,8 @@ namespace IEC61850
List<string> newList = new List<string>(); List<string> newList = new List<string>();
while (element != IntPtr.Zero) { while (element != IntPtr.Zero)
{
string ln = Marshal.PtrToStringAnsi(LinkedList_getData(element)); string ln = Marshal.PtrToStringAnsi(LinkedList_getData(element));
newList.Add(ln); newList.Add(ln);
@ -944,7 +962,8 @@ namespace IEC61850
List<string> newList = new List<string>(); List<string> newList = new List<string>();
while (element != IntPtr.Zero) { while (element != IntPtr.Zero)
{
string dataObject = Marshal.PtrToStringAnsi(LinkedList_getData(element)); string dataObject = Marshal.PtrToStringAnsi(LinkedList_getData(element));
newList.Add(dataObject); newList.Add(dataObject);
@ -973,7 +992,8 @@ namespace IEC61850
List<string> newList = new List<string>(); List<string> newList = new List<string>();
while (element != IntPtr.Zero) { while (element != IntPtr.Zero)
{
string dataObject = Marshal.PtrToStringAnsi(LinkedList_getData(element)); string dataObject = Marshal.PtrToStringAnsi(LinkedList_getData(element));
newList.Add(dataObject); newList.Add(dataObject);
@ -1003,7 +1023,8 @@ namespace IEC61850
List<string> newList = new List<string>(); List<string> newList = new List<string>();
while (element != IntPtr.Zero) { while (element != IntPtr.Zero)
{
string dataObject = Marshal.PtrToStringAnsi(LinkedList_getData(element)); string dataObject = Marshal.PtrToStringAnsi(LinkedList_getData(element));
newList.Add(dataObject); newList.Add(dataObject);
@ -1034,7 +1055,8 @@ namespace IEC61850
List<string> newList = new List<string>(); List<string> newList = new List<string>();
while (element != IntPtr.Zero) { while (element != IntPtr.Zero)
{
string dataObject = Marshal.PtrToStringAnsi(LinkedList_getData(element)); string dataObject = Marshal.PtrToStringAnsi(LinkedList_getData(element));
newList.Add(dataObject); newList.Add(dataObject);
@ -1053,7 +1075,8 @@ namespace IEC61850
IntPtr element = LinkedList_getNext(linkedList); IntPtr element = LinkedList_getNext(linkedList);
while (element != IntPtr.Zero) { while (element != IntPtr.Zero)
{
MmsJournalEntry journalEntry = new MmsJournalEntry(LinkedList_getData(element)); MmsJournalEntry journalEntry = new MmsJournalEntry(LinkedList_getData(element));
@ -1182,7 +1205,8 @@ namespace IEC61850
{ {
IntPtr mmsValue = readObjectInternal(objectReference, fc); IntPtr mmsValue = readObjectInternal(objectReference, fc);
if (MmsValue_getType(mmsValue) == (int) MmsType.MMS_DATA_ACCESS_ERROR) { if (MmsValue_getType(mmsValue) == (int)MmsType.MMS_DATA_ACCESS_ERROR)
{
int dataAccessError = MmsValue_getDataAccessError(mmsValue); int dataAccessError = MmsValue_getDataAccessError(mmsValue);
@ -1203,7 +1227,8 @@ namespace IEC61850
{ {
IntPtr mmsValue = readObjectInternalAndCheckDataAccessError(objectReference, fc); IntPtr mmsValue = readObjectInternalAndCheckDataAccessError(objectReference, fc);
if (MmsValue_getType (mmsValue) != (int) MmsType.MMS_BOOLEAN) { if (MmsValue_getType(mmsValue) != (int)MmsType.MMS_BOOLEAN)
{
MmsValue_delete(mmsValue); MmsValue_delete(mmsValue);
throw new IedConnectionException("Result is not of type boolean (MMS_BOOLEAN)", 0); throw new IedConnectionException("Result is not of type boolean (MMS_BOOLEAN)", 0);
} }
@ -1223,7 +1248,8 @@ namespace IEC61850
{ {
IntPtr mmsValue = readObjectInternalAndCheckDataAccessError(objectReference, fc); IntPtr mmsValue = readObjectInternalAndCheckDataAccessError(objectReference, fc);
if (MmsValue_getType (mmsValue) != (int)MmsType.MMS_FLOAT) { if (MmsValue_getType(mmsValue) != (int)MmsType.MMS_FLOAT)
{
MmsValue_delete(mmsValue); MmsValue_delete(mmsValue);
throw new IedConnectionException("Result is not of type float (MMS_FLOAT)", 0); throw new IedConnectionException("Result is not of type float (MMS_FLOAT)", 0);
} }
@ -1243,7 +1269,8 @@ namespace IEC61850
{ {
IntPtr mmsValue = readObjectInternalAndCheckDataAccessError(objectReference, fc); IntPtr mmsValue = readObjectInternalAndCheckDataAccessError(objectReference, fc);
if (!((MmsValue_getType (mmsValue) == (int)MmsType.MMS_VISIBLE_STRING) || (MmsValue_getType (mmsValue) == (int)MmsType.MMS_STRING))) { if (!((MmsValue_getType(mmsValue) == (int)MmsType.MMS_VISIBLE_STRING) || (MmsValue_getType(mmsValue) == (int)MmsType.MMS_STRING)))
{
MmsValue_delete(mmsValue); MmsValue_delete(mmsValue);
throw new IedConnectionException("Result is not of type string", 0); throw new IedConnectionException("Result is not of type string", 0);
} }
@ -1265,12 +1292,15 @@ namespace IEC61850
{ {
IntPtr mmsValue = readObjectInternalAndCheckDataAccessError(objectReference, fc); IntPtr mmsValue = readObjectInternalAndCheckDataAccessError(objectReference, fc);
if (MmsValue_getType (mmsValue) == (int)MmsType.MMS_BIT_STRING) { if (MmsValue_getType(mmsValue) == (int)MmsType.MMS_BIT_STRING)
{
int bitStringValue = (int)MmsValue_getBitStringAsInteger(mmsValue); int bitStringValue = (int)MmsValue_getBitStringAsInteger(mmsValue);
MmsValue_delete(mmsValue); MmsValue_delete(mmsValue);
return new Quality(bitStringValue); return new Quality(bitStringValue);
} else { }
else
{
MmsValue_delete(mmsValue); MmsValue_delete(mmsValue);
throw new IedConnectionException("Result is not of type bit string(Quality)", 0); throw new IedConnectionException("Result is not of type bit string(Quality)", 0);
} }
@ -1284,12 +1314,15 @@ namespace IEC61850
{ {
IntPtr mmsValue = readObjectInternalAndCheckDataAccessError(objectReference, fc); IntPtr mmsValue = readObjectInternalAndCheckDataAccessError(objectReference, fc);
if (MmsValue_getType (mmsValue) == (int)MmsType.MMS_BIT_STRING) { if (MmsValue_getType(mmsValue) == (int)MmsType.MMS_BIT_STRING)
{
int bitStringValue = (int)MmsValue_getBitStringAsInteger(mmsValue); int bitStringValue = (int)MmsValue_getBitStringAsInteger(mmsValue);
MmsValue_delete(mmsValue); MmsValue_delete(mmsValue);
return bitStringValue; return bitStringValue;
} else { }
else
{
MmsValue_delete(mmsValue); MmsValue_delete(mmsValue);
throw new IedConnectionException("Result is not of type bit string", 0); throw new IedConnectionException("Result is not of type bit string", 0);
} }
@ -1806,7 +1839,8 @@ namespace IEC61850
IntPtr valueList = LinkedList_create(); IntPtr valueList = LinkedList_create();
foreach (MmsValue mmsValue in values) { foreach (MmsValue mmsValue in values)
{
LinkedList_add(valueList, mmsValue.valueReference); LinkedList_add(valueList, mmsValue.valueReference);
} }
@ -1818,11 +1852,13 @@ namespace IEC61850
List<MmsDataAccessError> accessResultList = null; List<MmsDataAccessError> accessResultList = null;
if (accessResults != IntPtr.Zero) { if (accessResults != IntPtr.Zero)
{
IntPtr element = LinkedList_getNext(accessResults); IntPtr element = LinkedList_getNext(accessResults);
while (element != IntPtr.Zero) { while (element != IntPtr.Zero)
{
IntPtr elementData = LinkedList_getData(element); IntPtr elementData = LinkedList_getData(element);
MmsValue accessResultValue = new MmsValue(elementData, true); MmsValue accessResultValue = new MmsValue(elementData, true);
@ -1855,7 +1891,8 @@ namespace IEC61850
{ {
IntPtr linkedList = LinkedList_create(); IntPtr linkedList = LinkedList_create();
foreach (string dataSetElement in dataSetElements) { foreach (string dataSetElement in dataSetElements)
{
IntPtr handle = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(dataSetElement); IntPtr handle = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(dataSetElement);
LinkedList_add(linkedList, handle); LinkedList_add(linkedList, handle);
@ -1927,7 +1964,8 @@ namespace IEC61850
List<string> newList = new List<string>(); List<string> newList = new List<string>();
while (element != IntPtr.Zero) { while (element != IntPtr.Zero)
{
string dataObject = Marshal.PtrToStringAnsi(LinkedList_getData(element)); string dataObject = Marshal.PtrToStringAnsi(LinkedList_getData(element));
newList.Add(dataObject); newList.Add(dataObject);
@ -2376,32 +2414,40 @@ namespace IEC61850
internal void UninstallReportHandler(string objectReference) internal void UninstallReportHandler(string objectReference)
{ {
if (connection != IntPtr.Zero) { if (connection != IntPtr.Zero)
{
IedConnection_uninstallReportHandler(connection, objectReference); IedConnection_uninstallReportHandler(connection, objectReference);
} }
} }
internal void InstallReportHandler(string objectReference, string reportId, InternalReportHandler internalHandler) internal void InstallReportHandler(string objectReference, string reportId, InternalReportHandler internalHandler)
{ {
if (connection != IntPtr.Zero) { if (connection != IntPtr.Zero)
{
IedConnection_installReportHandler(connection, objectReference, reportId, internalHandler, IntPtr.Zero); IedConnection_installReportHandler(connection, objectReference, reportId, internalHandler, IntPtr.Zero);
} }
} }
internal void GetRCBValues(out int error, string objectReference, IntPtr updateRcb) internal void GetRCBValues(out int error, string objectReference, IntPtr updateRcb)
{ {
if (connection != IntPtr.Zero) { if (connection != IntPtr.Zero)
{
IedConnection_getRCBValues(connection, out error, objectReference, updateRcb); IedConnection_getRCBValues(connection, out error, objectReference, updateRcb);
} else { }
else
{
error = 1; /* not connected */ error = 1; /* not connected */
} }
} }
internal void SetRCBValues(out int error, IntPtr rcb, UInt32 parametersMask, bool singleRequest) internal void SetRCBValues(out int error, IntPtr rcb, UInt32 parametersMask, bool singleRequest)
{ {
if (connection != IntPtr.Zero) { if (connection != IntPtr.Zero)
{
IedConnection_setRCBValues(connection, out error, rcb, parametersMask, singleRequest); IedConnection_setRCBValues(connection, out error, rcb, parametersMask, singleRequest);
} else { }
else
{
error = 1; /* not connected */ error = 1; /* not connected */
} }
} }
@ -2486,12 +2532,14 @@ namespace IEC61850
private int errorCode; private int errorCode;
public IedConnectionException (string message, int errorCode) : base(message) public IedConnectionException(string message, int errorCode)
: base(message)
{ {
this.errorCode = errorCode; this.errorCode = errorCode;
} }
public IedConnectionException (string message) : base(message) public IedConnectionException(string message)
: base(message)
{ {
this.errorCode = 0; this.errorCode = 0;
} }
@ -2653,6 +2701,12 @@ namespace IEC61850
/** The object is invalidated (returned by server) */ /** The object is invalidated (returned by server) */
IED_ERROR_OBJECT_INVALIDATED = 33, IED_ERROR_OBJECT_INVALIDATED = 33,
/** Received an invalid response message from the server */
IED_ERROR_MALFORMED_MESSAGE = 34,
/** Service not implemented */
IED_ERROR_SERVICE_NOT_IMPLEMENTED = 98,
/* unknown error */ /* unknown error */
IED_ERROR_UNKNOWN = 99 IED_ERROR_UNKNOWN = 99
} }

@ -3,7 +3,7 @@
* *
* Client implementation for IEC 61850 reporting. * Client implementation for IEC 61850 reporting.
* *
* Copyright 2013-2018 Michael Zillgith * Copyright 2013-2019 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -43,6 +43,8 @@ struct sClientReport
char* dataSetName; char* dataSetName;
int dataSetNameSize; /* size of the dataSetName buffer */ int dataSetNameSize; /* size of the dataSetName buffer */
int dataSetSize;
MmsValue* entryId; MmsValue* entryId;
MmsValue* dataReferences; MmsValue* dataReferences;
MmsValue* dataSetValues; MmsValue* dataSetValues;
@ -93,6 +95,8 @@ ClientReport_create()
{ {
ClientReport self = (ClientReport) GLOBAL_CALLOC(1, sizeof(struct sClientReport)); ClientReport self = (ClientReport) GLOBAL_CALLOC(1, sizeof(struct sClientReport));
self->dataSetSize = -1;
return self; return self;
} }
@ -607,6 +611,18 @@ iedConnection_handleReport(IedConnection self, MmsValue* value)
int dataSetSize = MmsValue_getBitStringSize(inclusion); int dataSetSize = MmsValue_getBitStringSize(inclusion);
if (matchingReport->dataSetSize == -1) {
matchingReport->dataSetSize = dataSetSize;
}
else {
if (dataSetSize != matchingReport->dataSetSize) {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: received malformed report (inclusion has no plausible size)\n");
goto exit_function;
}
}
int includedElements = MmsValue_getNumberOfSetBits(inclusion); int includedElements = MmsValue_getNumberOfSetBits(inclusion);
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)

@ -1,7 +1,7 @@
/* /*
* ied_connection.c * ied_connection.c
* *
* Copyright 2013-2018 Michael Zillgith * Copyright 2013-2019 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -96,6 +96,9 @@ iedConnection_mapMmsErrorToIedError(MmsError mmsError)
case MMS_ERROR_ACCESS_OBJECT_VALUE_INVALID: case MMS_ERROR_ACCESS_OBJECT_VALUE_INVALID:
return IED_ERROR_OBJECT_VALUE_INVALID; return IED_ERROR_OBJECT_VALUE_INVALID;
case MMS_ERROR_PARSING_RESPONSE:
return IED_ERROR_MALFORMED_MESSAGE;
default: default:
return IED_ERROR_UNKNOWN; return IED_ERROR_UNKNOWN;
} }
@ -484,8 +487,9 @@ informationReportHandler(void* parameter, char* domainName,
{ {
IedConnection self = (IedConnection) parameter; IedConnection self = (IedConnection) parameter;
if (value) {
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: received information report for %s\n", variableListName); printf("IED_CLIENT: received information report for %s\n", variableListName);
if (domainName == NULL) { if (domainName == NULL) {
@ -521,6 +525,11 @@ informationReportHandler(void* parameter, char* domainName,
MmsValue_delete(value); MmsValue_delete(value);
} }
else {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: report for %s/%s: value invalid\n", domainName, variableListName);
}
}
static void static void
IedConnection_setState(IedConnection self, IedConnectionState newState) IedConnection_setState(IedConnection self, IedConnectionState newState)

@ -1,7 +1,7 @@
/* /*
* iec61850_client.h * iec61850_client.h
* *
* Copyright 2013-2018 Michael Zillgith * Copyright 2013-2019 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -159,6 +159,9 @@ typedef enum {
/** The object is invalidated (returned by server) */ /** The object is invalidated (returned by server) */
IED_ERROR_OBJECT_INVALIDATED = 33, IED_ERROR_OBJECT_INVALIDATED = 33,
/** Received an invalid response message from the server */
IED_ERROR_MALFORMED_MESSAGE = 34,
/** Service not implemented */ /** Service not implemented */
IED_ERROR_SERVICE_NOT_IMPLEMENTED = 98, IED_ERROR_SERVICE_NOT_IMPLEMENTED = 98,

@ -1,7 +1,7 @@
/* /*
* control.c * control.c
* *
* Copyright 2013-2018 Michael Zillgith * Copyright 2013-2019 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -316,10 +316,25 @@ ControlObject_create(IedServer iedServer, MmsDomain* domain, char* lnName, char*
self->iedServer = iedServer; self->iedServer = iedServer;
MmsVariableSpecification* ctlValSpec = MmsVariableSpecification_getChildSpecificationByName(operSpec, "ctlVal", NULL); MmsVariableSpecification* ctlValSpec = MmsVariableSpecification_getChildSpecificationByName(operSpec, "ctlVal", NULL);
if (ctlValSpec) {
self->ctlVal = MmsValue_newDefaultValue(ctlValSpec); self->ctlVal = MmsValue_newDefaultValue(ctlValSpec);
}
else {
if (DEBUG_IED_SERVER)
printf("IED_SERVER: control object %s/%s.%s has no ctlVal element!\n", domain->domainName, lnName, name);
}
MmsVariableSpecification* originSpec = MmsVariableSpecification_getChildSpecificationByName(operSpec, "origin", NULL); MmsVariableSpecification* originSpec = MmsVariableSpecification_getChildSpecificationByName(operSpec, "origin", NULL);
if (originSpec) {
self->origin = MmsValue_newDefaultValue(originSpec); self->origin = MmsValue_newDefaultValue(originSpec);
}
else {
if (DEBUG_IED_SERVER)
printf("IED_SERVER: control object %s/%s.%s has no origin element!\n", domain->domainName, lnName, name);
}
self->ctlNum = MmsValue_newUnsigned(8); self->ctlNum = MmsValue_newUnsigned(8);

@ -1,7 +1,7 @@
/* /*
* mms_client_connection.c * mms_client_connection.c
* *
* Copyright 2013-2018 Michael Zillgith * Copyright 2013-2019 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -657,7 +657,10 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M
if (response) { if (response) {
MmsValue* value = mmsClient_parseReadResponse(response, NULL, false); MmsValue* value = mmsClient_parseReadResponse(response, NULL, false);
handler(outstandingCall->invokeId, outstandingCall->userParameter, MMS_ERROR_NONE, value); if (value == NULL)
err = MMS_ERROR_PARSING_RESPONSE;
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, value);
} }
} }
@ -673,7 +676,10 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M
if (response) { if (response) {
MmsValue* value = mmsClient_parseReadResponse(response, NULL, true); MmsValue* value = mmsClient_parseReadResponse(response, NULL, true);
handler(outstandingCall->invokeId, outstandingCall->userParameter, MMS_ERROR_NONE, value); if (value == NULL)
err = MMS_ERROR_PARSING_RESPONSE;
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, value);
} }
} }
@ -726,7 +732,7 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M
LinkedList accessSpec = mmsClient_parseGetNamedVariableListAttributesResponse(response, &deletable); LinkedList accessSpec = mmsClient_parseGetNamedVariableListAttributesResponse(response, &deletable);
if (accessSpec == false) if (accessSpec == NULL)
err = MMS_ERROR_PARSING_RESPONSE; err = MMS_ERROR_PARSING_RESPONSE;
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, accessSpec, deletable); handler(outstandingCall->invokeId, outstandingCall->userParameter, err, accessSpec, deletable);
@ -779,6 +785,9 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M
else { else {
MmsVariableSpecification* typeSpec = mmsClient_parseGetVariableAccessAttributesResponse(response, NULL); MmsVariableSpecification* typeSpec = mmsClient_parseGetVariableAccessAttributesResponse(response, NULL);
if (typeSpec == NULL)
err = MMS_ERROR_PARSING_RESPONSE;
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, typeSpec); handler(outstandingCall->invokeId, outstandingCall->userParameter, err, typeSpec);
} }
} }

@ -138,8 +138,7 @@ mmsClient_parseGetVariableAccessAttributesResponse(ByteBuffer* message, uint32_t
asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu, asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu,
(void**) &mmsPdu, ByteBuffer_getBuffer(message), ByteBuffer_getSize(message)); (void**) &mmsPdu, ByteBuffer_getBuffer(message), ByteBuffer_getSize(message));
if (rval.code != RC_OK) if (rval.code == RC_OK) {
return NULL;
if (mmsPdu->present == MmsPdu_PR_confirmedResponsePdu) { if (mmsPdu->present == MmsPdu_PR_confirmedResponsePdu) {
@ -158,6 +157,8 @@ mmsClient_parseGetVariableAccessAttributesResponse(ByteBuffer* message, uint32_t
} }
} }
}
asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0);
return typeSpec; return typeSpec;

@ -1,7 +1,7 @@
/* /*
* mms_client_read.c * mms_client_read.c
* *
* Copyright 2013-2018 Michael Zillgith * Copyright 2013-2019 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -46,11 +46,14 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
int i = 0; int i = 0;
for (i = 0; i < elementCount; i++) { for (i = 0; i < elementCount; i++) {
value = NULL;
AccessResult_PR presentType = accessResultList[i]->present; AccessResult_PR presentType = accessResultList[i]->present;
if (presentType == AccessResult_PR_failure) { if (presentType == AccessResult_PR_failure) {
if (DEBUG_MMS_CLIENT) if (DEBUG_MMS_CLIENT)
printf("access error!\n"); printf("MMS CLIENT: received access error!\n");
if (accessResultList[i]->choice.failure.size > 0) { if (accessResultList[i]->choice.failure.size > 0) {
int errorCode = (int) accessResultList[i]->choice.failure.buf[0]; int errorCode = (int) accessResultList[i]->choice.failure.buf[0];
@ -66,12 +69,13 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
value = MmsValue_newDataAccessError(DATA_ACCESS_ERROR_UNKNOWN); value = MmsValue_newDataAccessError(DATA_ACCESS_ERROR_UNKNOWN);
} }
else if (presentType == AccessResult_PR_array) { else if (presentType == AccessResult_PR_array) {
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_ARRAY;
int arrayElementCount = int arrayElementCount =
accessResultList[i]->choice.array.list.count; accessResultList[i]->choice.array.list.count;
if (arrayElementCount > 0) {
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_ARRAY;
value->value.structure.size = arrayElementCount; value->value.structure.size = arrayElementCount;
value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(arrayElementCount, sizeof(MmsValue*)); value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(arrayElementCount, sizeof(MmsValue*));
@ -80,15 +84,28 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
for (j = 0; j < arrayElementCount; j++) { for (j = 0; j < arrayElementCount; j++) {
value->value.structure.components[j] = mmsMsg_parseDataElement( value->value.structure.components[j] = mmsMsg_parseDataElement(
accessResultList[i]->choice.array.list.array[j]); accessResultList[i]->choice.array.list.array[j]);
if (value->value.structure.components[j] == NULL) {
MmsValue_delete(value);
value = NULL;
break;
} }
} }
}
else {
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing access result (invalid array size)!\n");
}
}
else if (presentType == AccessResult_PR_structure) { else if (presentType == AccessResult_PR_structure) {
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_STRUCTURE;
int componentCount = int componentCount =
accessResultList[i]->choice.structure.list.count; accessResultList[i]->choice.structure.list.count;
if (componentCount > 0) {
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_STRUCTURE;
value->value.structure.size = componentCount; value->value.structure.size = componentCount;
value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*));
@ -96,12 +113,34 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
for (j = 0; j < componentCount; j++) { for (j = 0; j < componentCount; j++) {
value->value.structure.components[j] = mmsMsg_parseDataElement( value->value.structure.components[j] = mmsMsg_parseDataElement(
accessResultList[i]->choice.structure.list.array[j]); accessResultList[i]->choice.structure.list.array[j]);
if (value->value.structure.components[j] == NULL) {
MmsValue_delete(value);
value = NULL;
break;
}
} }
} }
else {
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing access result (invalid structure size)!\n");
}
}
else if (presentType == AccessResult_PR_bitstring) { else if (presentType == AccessResult_PR_bitstring) {
int size = accessResultList[i]->choice.bitstring.size;
if (size > 0) {
int maxSize = (size * 8);
int bitSize = maxSize - accessResultList[i]->choice.bitstring.bits_unused;
if ((bitSize > 0) && (maxSize >= bitSize)) {
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_BIT_STRING; value->type = MMS_BIT_STRING;
int size = accessResultList[i]->choice.bitstring.size;
value->value.bitString.size = (size * 8) value->value.bitString.size = (size * 8)
- accessResultList[i]->choice.bitstring.bits_unused; - accessResultList[i]->choice.bitstring.bits_unused;
@ -109,29 +148,59 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size); value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size);
memcpy(value->value.bitString.buf, memcpy(value->value.bitString.buf,
accessResultList[i]->choice.bitstring.buf, size); accessResultList[i]->choice.bitstring.buf, size);
}
else {
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing access result (bit string padding problem)!\n");
}
}
else {
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing access result (bit string size 0 or negative)!\n");
}
} }
else if (presentType == AccessResult_PR_integer) { else if (presentType == AccessResult_PR_integer) {
int size = accessResultList[i]->choice.integer.size;
if (size > 0) {
Asn1PrimitiveValue* berInteger = Asn1PrimitiveValue* berInteger =
BerInteger_createFromBuffer(accessResultList[i]->choice.integer.buf, BerInteger_createFromBuffer(accessResultList[i]->choice.integer.buf, size);
accessResultList[i]->choice.integer.size);
value = MmsValue_newIntegerFromBerInteger(berInteger); value = MmsValue_newIntegerFromBerInteger(berInteger);
} }
else {
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing access result (invalid integer size)!\n");
}
}
else if (presentType == AccessResult_PR_unsigned) { else if (presentType == AccessResult_PR_unsigned) {
int size = accessResultList[i]->choice.Unsigned.size;
if (size > 0) {
Asn1PrimitiveValue* berInteger = Asn1PrimitiveValue* berInteger =
BerInteger_createFromBuffer(accessResultList[i]->choice.Unsigned.buf, BerInteger_createFromBuffer(accessResultList[i]->choice.Unsigned.buf,
accessResultList[i]->choice.Unsigned.size); accessResultList[i]->choice.Unsigned.size);
value = MmsValue_newUnsignedFromBerInteger(berInteger); value = MmsValue_newUnsignedFromBerInteger(berInteger);
} }
else {
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing access result (invalid unsigned size)!\n");
}
}
else if (presentType == AccessResult_PR_floatingpoint) { else if (presentType == AccessResult_PR_floatingpoint) {
int size = accessResultList[i]->choice.floatingpoint.size; int size = accessResultList[i]->choice.floatingpoint.size;
if (size == 5) { /* FLOAT32 */
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_FLOAT; value->type = MMS_FLOAT;
if (size == 5) { /* FLOAT32 */
value->value.floatingPoint.formatWidth = 32; value->value.floatingPoint.formatWidth = 32;
value->value.floatingPoint.exponentWidth = accessResultList[i]->choice.floatingpoint.buf[0]; value->value.floatingPoint.exponentWidth = accessResultList[i]->choice.floatingpoint.buf[0];
@ -146,8 +215,11 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
#endif #endif
} }
else if (size == 9) { /* FLOAT64 */
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_FLOAT;
if (size == 9) { /* FLOAT64 */
value->value.floatingPoint.formatWidth = 64; value->value.floatingPoint.formatWidth = 64;
value->value.floatingPoint.exponentWidth = accessResultList[i]->choice.floatingpoint.buf[0]; value->value.floatingPoint.exponentWidth = accessResultList[i]->choice.floatingpoint.buf[0];
@ -161,15 +233,20 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
memcpy(value->value.floatingPoint.buf, floatBuf, 8); memcpy(value->value.floatingPoint.buf, floatBuf, 8);
#endif #endif
} }
else {
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing float (size must be 5 or 9, is %i)\n", size);
}
} }
else if (presentType == AccessResult_PR_visiblestring) { else if (presentType == AccessResult_PR_visiblestring) {
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_VISIBLE_STRING;
int strSize = accessResultList[i]->choice.visiblestring.size; int strSize = accessResultList[i]->choice.visiblestring.size;
if (strSize >= 0) {
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_VISIBLE_STRING;
value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1); value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1);
value->value.visibleString.size = strSize; value->value.visibleString.size = strSize;
@ -179,13 +256,20 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
value->value.visibleString.buf[strSize] = 0; value->value.visibleString.buf[strSize] = 0;
} }
else if (presentType == AccessResult_PR_mMSString) { else {
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing access result (invalid visible-string size)\n");
}
value->type = MMS_STRING; }
else if (presentType == AccessResult_PR_mMSString) {
int strSize = accessResultList[i]->choice.mMSString.size; int strSize = accessResultList[i]->choice.mMSString.size;
if (strSize >= 0) {
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_STRING;
value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1); value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1);
value->value.visibleString.size = strSize; value->value.visibleString.size = strSize;
@ -193,14 +277,26 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
accessResultList[i]->choice.mMSString.buf, strSize); accessResultList[i]->choice.mMSString.buf, strSize);
value->value.visibleString.buf[strSize] = 0; value->value.visibleString.buf[strSize] = 0;
}
else {
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing access result (invalid mms-string size)\n");
}
} }
else if (presentType == AccessResult_PR_utctime) { else if (presentType == AccessResult_PR_utctime) {
int size = accessResultList[i]->choice.utctime.size;
if (size == 8) {
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_UTC_TIME; value->type = MMS_UTC_TIME;
memcpy(value->value.utcTime, memcpy(value->value.utcTime, accessResultList[i]->choice.utctime.buf, 8);
accessResultList[i]->choice.utctime.buf, 8); }
else {
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing UTC time (size is %i instead of 8\n", size);
}
} }
else if (presentType == AccessResult_PR_boolean) { else if (presentType == AccessResult_PR_boolean) {
value = MmsValue_newBoolean(accessResultList[i]->choice.boolean); value = MmsValue_newBoolean(accessResultList[i]->choice.boolean);
@ -208,16 +304,21 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
else if (presentType == AccessResult_PR_binarytime) { else if (presentType == AccessResult_PR_binarytime) {
int size = accessResultList[i]->choice.binarytime.size; int size = accessResultList[i]->choice.binarytime.size;
if (size <= 6) { if ((size == 4) || (size == 6)) {
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_BINARY_TIME; value->type = MMS_BINARY_TIME;
value->value.binaryTime.size = size; value->value.binaryTime.size = size;
memcpy(value->value.binaryTime.buf, accessResultList[i]->choice.binarytime.buf, size); memcpy(value->value.binaryTime.buf, accessResultList[i]->choice.binarytime.buf, size);
} }
else {
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing binary time (size must be 4 or 6, is %i\n", size);
}
} }
else if (presentType == AccessResult_PR_octetstring) { else if (presentType == AccessResult_PR_octetstring) {
int size = accessResultList[i]->choice.octetstring.size; int size = accessResultList[i]->choice.octetstring.size;
if (size >= 0) {
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_OCTET_STRING; value->type = MMS_OCTET_STRING;
value->value.octetString.maxSize = size; value->value.octetString.maxSize = size;
@ -226,7 +327,13 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
memcpy(value->value.octetString.buf, accessResultList[i]->choice.octetstring.buf, size); memcpy(value->value.octetString.buf, accessResultList[i]->choice.octetstring.buf, size);
} }
else { else {
printf("unknown type %i\n", presentType); if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing access result (invalid octet-string size)\n");
}
}
else {
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: unknown type %i in access result\n", presentType);
value = MmsValue_newDataAccessError(DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID); value = MmsValue_newDataAccessError(DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID);
} }
@ -254,9 +361,7 @@ mmsClient_parseReadResponse(ByteBuffer* message, uint32_t* invokeId, bool create
asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu, asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu,
(void**) &mmsPdu, ByteBuffer_getBuffer(message), ByteBuffer_getSize(message)); (void**) &mmsPdu, ByteBuffer_getBuffer(message), ByteBuffer_getSize(message));
if (rval.code != RC_OK) if (rval.code == RC_OK) {
return NULL;
if (mmsPdu->present == MmsPdu_PR_confirmedResponsePdu) { if (mmsPdu->present == MmsPdu_PR_confirmedResponsePdu) {
if (invokeId != NULL) if (invokeId != NULL)
@ -271,6 +376,7 @@ mmsClient_parseReadResponse(ByteBuffer* message, uint32_t* invokeId, bool create
elementCount, createArray); elementCount, createArray);
} }
} }
}
asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0);

@ -1,7 +1,7 @@
/* /*
* mms_common_msg.c * mms_common_msg.c
* *
* Copyright 2013-2018 Michael Zillgith * Copyright 2013-2019 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -185,12 +185,14 @@ mmsMsg_parseDataElement(Data_t* dataElement)
{ {
MmsValue* value = NULL; MmsValue* value = NULL;
if (dataElement->present == Data_PR_structure) { if (dataElement->present == Data_PR_array) {
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
int componentCount = dataElement->choice.structure->list.count; int componentCount = dataElement->choice.array->list.count;
value->type = MMS_STRUCTURE; if (componentCount > 0) {
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_ARRAY;
value->value.structure.size = componentCount; value->value.structure.size = componentCount;
value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*));
@ -198,15 +200,29 @@ mmsMsg_parseDataElement(Data_t* dataElement)
for (i = 0; i < componentCount; i++) { for (i = 0; i < componentCount; i++) {
value->value.structure.components[i] = value->value.structure.components[i] =
mmsMsg_parseDataElement(dataElement->choice.structure->list.array[i]); mmsMsg_parseDataElement(dataElement->choice.array->list.array[i]);
if (value->value.structure.components[i] == NULL) {
MmsValue_delete(value);
value = NULL;
break;
} }
} }
else if (dataElement->present == Data_PR_array) { }
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); else {
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing data element (invalid array size)!\n");
}
int componentCount = dataElement->choice.array->list.count; }
else if (dataElement->present == Data_PR_structure) {
value->type = MMS_ARRAY; int componentCount = dataElement->choice.structure->list.count;
if (componentCount > 0) {
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_STRUCTURE;
value->value.structure.size = componentCount; value->value.structure.size = componentCount;
value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*));
@ -214,51 +230,99 @@ mmsMsg_parseDataElement(Data_t* dataElement)
for (i = 0; i < componentCount; i++) { for (i = 0; i < componentCount; i++) {
value->value.structure.components[i] = value->value.structure.components[i] =
mmsMsg_parseDataElement(dataElement->choice.array->list.array[i]); mmsMsg_parseDataElement(dataElement->choice.structure->list.array[i]);
if (value->value.structure.components[i] == NULL) {
MmsValue_delete(value);
value = NULL;
break;
}
} }
} }
else { else {
if (dataElement->present == Data_PR_integer) { if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing data element (invalid structure size)!\n");
}
}
else if (dataElement->present == Data_PR_integer) {
if (dataElement->choice.integer.size > 0) {
Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer( Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer(
dataElement->choice.integer.buf, dataElement->choice.integer.size); dataElement->choice.integer.buf, dataElement->choice.integer.size);
value = MmsValue_newIntegerFromBerInteger(berInteger); value = MmsValue_newIntegerFromBerInteger(berInteger);
} }
else {
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing data element (invalid integer size)!\n");
}
}
else if (dataElement->present == Data_PR_unsigned) { else if (dataElement->present == Data_PR_unsigned) {
if (dataElement->choice.Unsigned.size > 0) {
Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer( Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer(
dataElement->choice.Unsigned.buf, dataElement->choice.Unsigned.size); dataElement->choice.Unsigned.buf, dataElement->choice.Unsigned.size);
value = MmsValue_newUnsignedFromBerInteger(berInteger); value = MmsValue_newUnsignedFromBerInteger(berInteger);
} }
else {
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing data element (invalid unsigned size)!\n");
}
}
else if (dataElement->present == Data_PR_visiblestring) { else if (dataElement->present == Data_PR_visiblestring) {
if (dataElement->choice.visiblestring.size >= 0) {
value = MmsValue_newVisibleStringFromByteArray(dataElement->choice.visiblestring.buf, value = MmsValue_newVisibleStringFromByteArray(dataElement->choice.visiblestring.buf,
dataElement->choice.visiblestring.size); dataElement->choice.visiblestring.size);
} }
}
else if (dataElement->present == Data_PR_mMSString) { else if (dataElement->present == Data_PR_mMSString) {
if ( dataElement->choice.mMSString.size >= 0) {
value = MmsValue_newMmsStringFromByteArray(dataElement->choice.mMSString.buf, value = MmsValue_newMmsStringFromByteArray(dataElement->choice.mMSString.buf,
dataElement->choice.mMSString.size); dataElement->choice.mMSString.size);
} }
}
else if (dataElement->present == Data_PR_bitstring) { else if (dataElement->present == Data_PR_bitstring) {
int size = dataElement->choice.bitstring.size;
if (size > 0) {
int maxSize = (size * 8);
int bitSize = maxSize - dataElement->choice.bitstring.bits_unused;
if ((bitSize > 0) && (maxSize >= bitSize)) {
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_BIT_STRING; value->type = MMS_BIT_STRING;
int size = dataElement->choice.bitstring.size;
value->value.bitString.size = (size * 8) value->value.bitString.size = bitSize;
- dataElement->choice.bitstring.bits_unused;
value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size); value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size);
memcpy(value->value.bitString.buf, memcpy(value->value.bitString.buf,
dataElement->choice.bitstring.buf, size); dataElement->choice.bitstring.buf, size);
}
else {
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing data element (bit string padding problem)!\n");
}
}
else {
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing data element (bit string size 0 or negative)!\n");
}
} }
else if (dataElement->present == Data_PR_floatingpoint) { else if (dataElement->present == Data_PR_floatingpoint) {
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
int size = dataElement->choice.floatingpoint.size; int size = dataElement->choice.floatingpoint.size;
if (size == 5) { /* FLOAT32 */
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_FLOAT; value->type = MMS_FLOAT;
if (size == 5) { /* FLOAT32 */
value->value.floatingPoint.formatWidth = 32; value->value.floatingPoint.formatWidth = 32;
value->value.floatingPoint.exponentWidth = dataElement->choice.floatingpoint.buf[0]; value->value.floatingPoint.exponentWidth = dataElement->choice.floatingpoint.buf[0];
@ -273,6 +337,10 @@ mmsMsg_parseDataElement(Data_t* dataElement)
} }
if (size == 9) { /* FLOAT64 */ if (size == 9) { /* FLOAT64 */
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_FLOAT;
value->value.floatingPoint.formatWidth = 64; value->value.floatingPoint.formatWidth = 64;
value->value.floatingPoint.exponentWidth = dataElement->choice.floatingpoint.buf[0]; value->value.floatingPoint.exponentWidth = dataElement->choice.floatingpoint.buf[0];
@ -287,11 +355,22 @@ mmsMsg_parseDataElement(Data_t* dataElement)
} }
} }
else if (dataElement->present == Data_PR_utctime) { else if (dataElement->present == Data_PR_utctime) {
int size = dataElement->choice.utctime.size;
if (size == 8) {
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_UTC_TIME; value->type = MMS_UTC_TIME;
memcpy(value->value.utcTime, dataElement->choice.utctime.buf, 8); memcpy(value->value.utcTime, dataElement->choice.utctime.buf, 8);
} }
else {
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing UTC time (size is %i instead of 8\n", size);
}
}
else if (dataElement->present == Data_PR_octetstring) { else if (dataElement->present == Data_PR_octetstring) {
if (dataElement->choice.octetstring.size >= 0) {
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_OCTET_STRING; value->type = MMS_OCTET_STRING;
int size = dataElement->choice.octetstring.size; int size = dataElement->choice.octetstring.size;
@ -300,20 +379,33 @@ mmsMsg_parseDataElement(Data_t* dataElement)
value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size); value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size);
memcpy(value->value.octetString.buf, dataElement->choice.octetstring.buf, size); memcpy(value->value.octetString.buf, dataElement->choice.octetstring.buf, size);
} }
}
else if (dataElement->present == Data_PR_binarytime) { else if (dataElement->present == Data_PR_binarytime) {
int size = dataElement->choice.binarytime.size; int size = dataElement->choice.binarytime.size;
if (size <= 6) { if ((size == 4) || (size == 6)) {
value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_BINARY_TIME; value->type = MMS_BINARY_TIME;
value->value.binaryTime.size = size; value->value.binaryTime.size = size;
memcpy(value->value.binaryTime.buf, dataElement->choice.binarytime.buf, size); memcpy(value->value.binaryTime.buf, dataElement->choice.binarytime.buf, size);
} }
else {
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: error parsing binary time (size must be 4 or 6, is %i\n", size);
}
} }
else if (dataElement->present == Data_PR_boolean) { else if (dataElement->present == Data_PR_boolean) {
value = MmsValue_newBoolean(dataElement->choice.boolean); value = MmsValue_newBoolean(dataElement->choice.boolean);
} }
else if (dataElement->present == Data_PR_booleanArray) {
if (DEBUG_MMS_CLIENT)
printf("MMS CLIENT: unsupported type - boolean-array\n");
}
if (DEBUG_MMS_CLIENT) {
if (value == NULL)
printf("MMS CLIENT: error parsing data element\n");
} }
return value; return value;

@ -1,7 +1,7 @@
/* /*
* mms_value.c * mms_value.c
* *
* Copyright 2013-2018 Michael Zillgith * Copyright 2013-2019 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -1076,6 +1076,9 @@ MmsValue_cloneToBuffer(const MmsValue* self, uint8_t* destinationAddress)
MmsValue* MmsValue*
MmsValue_clone(const MmsValue* self) MmsValue_clone(const MmsValue* self)
{ {
if (self == NULL)
return NULL;
MmsValue* newValue = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); MmsValue* newValue = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
if (newValue == NULL) if (newValue == NULL)
@ -1179,6 +1182,9 @@ MmsValue_deleteIfNotNull(MmsValue* self)
void void
MmsValue_delete(MmsValue* self) MmsValue_delete(MmsValue* self)
{ {
if (self == NULL)
return;
switch (self->type) switch (self->type)
{ {
case MMS_INTEGER: case MMS_INTEGER:
@ -1997,6 +2003,16 @@ MmsValue_getTypeString(MmsValue* self)
const char* const char*
MmsValue_printToBuffer(const MmsValue* self, char* buffer, int bufferSize) MmsValue_printToBuffer(const MmsValue* self, char* buffer, int bufferSize)
{ {
if (self == NULL) {
strncpy(buffer, "(null)", bufferSize);
/* Ensure buffer is always 0 terminated */
if (bufferSize > 0)
buffer[bufferSize - 1] = 0;
return buffer;
}
switch (MmsValue_getType(self)) switch (MmsValue_getType(self))
{ {
case MMS_STRUCTURE: case MMS_STRUCTURE:

Loading…
Cancel
Save