diff --git a/examples/mms_utility/mms_utility.c b/examples/mms_utility/mms_utility.c index f505348e..0d1e9753 100644 --- a/examples/mms_utility/mms_utility.c +++ b/examples/mms_utility/mms_utility.c @@ -18,6 +18,7 @@ print_help() printf("-i show server identity\n"); printf("-t show domain directory\n"); printf("-r read domain variable\n"); + printf("-c specify component name for variable read\n"); printf("-a specify domain for read or write command\n"); printf("-f show file list\n"); printf("-g get file attributes\n"); @@ -105,6 +106,7 @@ int main(int argc, char** argv) { char* domainName = NULL; char* variableName = NULL; + char* componentName = NULL; char* filename = NULL; char* journalName = NULL; @@ -122,7 +124,7 @@ int main(int argc, char** argv) { int c; - while ((c = getopt(argc, argv, "mifdh:p:l:t:a:r:g:j:x:v:")) != -1) + while ((c = getopt(argc, argv, "mifdh:p:l:t:a:r:g:j:x:v:c:")) != -1) switch (c) { case 'm': printRawMmsMessages = 1; @@ -155,6 +157,9 @@ int main(int argc, char** argv) { readVariable = 1; variableName = StringUtils_copyString(optarg); break; + case 'c': + componentName = StringUtils_copyString(optarg); + break; case 'v': readVariableList = 1; variableName = StringUtils_copyString(optarg); @@ -323,7 +328,13 @@ int main(int argc, char** argv) { if (readVariable) { if (readWriteHasDomain) { - MmsValue* result = MmsConnection_readVariable(con, &error, domainName, variableName); + + MmsValue* result; + + if (componentName == NULL) + result = MmsConnection_readVariable(con, &error, domainName, variableName); + else + result = MmsConnection_readVariableComponent(con, &error, domainName, variableName, componentName); if (error != MMS_ERROR_NONE) { printf("Reading variable failed: (ERROR %i)\n", error); diff --git a/pyiec61850/CMakeLists.txt b/pyiec61850/CMakeLists.txt index 00c256f1..159ef4bc 100644 --- a/pyiec61850/CMakeLists.txt +++ b/pyiec61850/CMakeLists.txt @@ -34,7 +34,7 @@ swig_link_libraries(iec61850 ${PYTHON_LIBRARIES} ${LIBS}) # Finding python modules install path execute_process( COMMAND ${PYTHON_EXECUTABLE} -c - "from distutils.sysconfig import get_python_lib; import.sys; sys.stdout.write(get_python_lib())" + "from distutils.sysconfig import get_python_lib; import sys; sys.stdout.write(get_python_lib())" OUTPUT_VARIABLE PYTHON_SITE_DIR ) diff --git a/src/iec61850/client/client_report.c b/src/iec61850/client/client_report.c index f8139357..ec009e5f 100644 --- a/src/iec61850/client/client_report.c +++ b/src/iec61850/client/client_report.c @@ -43,6 +43,8 @@ struct sClientReport char* dataSetName; int dataSetNameSize; /* size of the dataSetName buffer */ + int dataSetSize; + MmsValue* entryId; MmsValue* dataReferences; MmsValue* dataSetValues; @@ -93,6 +95,8 @@ ClientReport_create() { ClientReport self = (ClientReport) GLOBAL_CALLOC(1, sizeof(struct sClientReport)); + self->dataSetSize = -1; + return self; } @@ -607,6 +611,18 @@ private_IedConnection_handleReport(IedConnection self, MmsValue* value) 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); if (DEBUG_IED_CLIENT) @@ -692,7 +708,7 @@ private_IedConnection_handleReport(IedConnection self, MmsValue* value) MmsValue_update(dataSetElement, newElementValue); if (DEBUG_IED_CLIENT) - printf("IED_CLIENT: update element value type: %i\n", MmsValue_getType(newElementValue)); + printf("IED_CLIENT: update element value type: %i\n", MmsValue_getType(newElementValue)); valueIndex++; diff --git a/src/iec61850/client/ied_connection.c b/src/iec61850/client/ied_connection.c index de323ef4..12195040 100644 --- a/src/iec61850/client/ied_connection.c +++ b/src/iec61850/client/ied_connection.c @@ -95,6 +95,9 @@ iedConnection_mapMmsErrorToIedError(MmsError mmsError) case MMS_ERROR_ACCESS_OBJECT_VALUE_INVALID: return IED_ERROR_OBJECT_VALUE_INVALID; + case MMS_ERROR_PARSING_RESPONSE: + return IED_ERROR_OBJECT_VALUE_INVALID; + default: return IED_ERROR_UNKNOWN; } @@ -434,39 +437,41 @@ informationReportHandler(void* parameter, char* domainName, if (DEBUG_IED_CLIENT) printf("DEBUG_IED_CLIENT: received information report for %s\n", variableListName); - if (domainName == NULL) { + if (value) { + if (domainName == NULL) { - if (isVariableListName) { - private_IedConnection_handleReport(self, value); - } - else { - if (strcmp(variableListName, "LastApplError") == 0) - handleLastApplErrorMessage(self, value); + if (isVariableListName) { + private_IedConnection_handleReport(self, value); + } else { - if (DEBUG_IED_CLIENT) - printf("IED_CLIENT: Received unknown variable list report for list: %s\n", variableListName); + if (strcmp(variableListName, "LastApplError") == 0) + handleLastApplErrorMessage(self, value); + else { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: Received unknown variable list report for list: %s\n", variableListName); + } } } - } - else { - if (DEBUG_IED_CLIENT) - printf("IED_CLIENT: RCVD CommandTermination for %s/%s\n", domainName, variableListName); + else { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: RCVD CommandTermination for %s/%s\n", domainName, variableListName); - LinkedList control = LinkedList_getNext(self->clientControls); + LinkedList control = LinkedList_getNext(self->clientControls); - while (control != NULL) { - ControlObjectClient object = (ControlObjectClient) control->data; + while (control != NULL) { + ControlObjectClient object = (ControlObjectClient) control->data; - char* objectRef = ControlObjectClient_getObjectReference(object); + char* objectRef = ControlObjectClient_getObjectReference(object); - if (doesReportMatchControlObject(domainName, variableListName, objectRef)) - private_ControlObjectClient_invokeCommandTerminationHandler(object); + if (doesReportMatchControlObject(domainName, variableListName, objectRef)) + private_ControlObjectClient_invokeCommandTerminationHandler(object); - control = LinkedList_getNext(control); + control = LinkedList_getNext(control); + } } - } - MmsValue_delete(value); + MmsValue_delete(value); + } } static IedConnection @@ -2291,7 +2296,7 @@ exit_function: } ClientDataSet -IedConnection_readDataSetValues(IedConnection self, IedClientError* error, const char* dataSetReference, +IedConnection_readDataSetValues(IedConnection self, IedClientError* err, const char* dataSetReference, ClientDataSet dataSet) { char domainIdBuffer[65]; @@ -2316,14 +2321,14 @@ IedConnection_readDataSetValues(IedConnection self, IedClientError* error, const domainId = MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainIdBuffer); if (domainId == NULL) { - *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + *err = IED_ERROR_OBJECT_REFERENCE_INVALID; goto exit_function; } const char* itemIdRefOrig = dataSetReference + strlen(domainId) + 1; if (strlen(itemIdRefOrig) > DATA_SET_MAX_NAME_LENGTH) { - *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + *err = IED_ERROR_OBJECT_REFERENCE_INVALID; goto exit_function; } @@ -2346,15 +2351,15 @@ IedConnection_readDataSetValues(IedConnection self, IedClientError* error, const dataSetVal = MmsConnection_readNamedVariableListValuesAssociationSpecific(self->connection, &mmsError, itemId, true); else - dataSetVal= MmsConnection_readNamedVariableListValues(self->connection, &mmsError, + dataSetVal = MmsConnection_readNamedVariableListValues(self->connection, &mmsError, domainId, itemId, true); if (dataSetVal == NULL) { - *error = iedConnection_mapMmsErrorToIedError(mmsError); + *err = iedConnection_mapMmsErrorToIedError(mmsError); goto exit_function; } else - *error = IED_ERROR_OK; + *err = IED_ERROR_OK; if (dataSet == NULL) { dataSet = ClientDataSet_create(dataSetReference); diff --git a/src/iec61850/server/mms_mapping/control.c b/src/iec61850/server/mms_mapping/control.c index 2febf484..b411f777 100644 --- a/src/iec61850/server/mms_mapping/control.c +++ b/src/iec61850/server/mms_mapping/control.c @@ -316,10 +316,12 @@ ControlObject_create(IedServer iedServer, MmsDomain* domain, char* lnName, char* self->iedServer = iedServer; MmsVariableSpecification* ctlValSpec = MmsVariableSpecification_getChildSpecificationByName(operSpec, "ctlVal", NULL); - self->ctlVal = MmsValue_newDefaultValue(ctlValSpec); + if (ctlValSpec != NULL) + self->ctlVal = MmsValue_newDefaultValue(ctlValSpec); MmsVariableSpecification* originSpec = MmsVariableSpecification_getChildSpecificationByName(operSpec, "origin", NULL); - self->origin = MmsValue_newDefaultValue(originSpec); + if (originSpec != NULL) + self->origin = MmsValue_newDefaultValue(originSpec); self->ctlNum = MmsValue_newUnsigned(8); diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index b8d7ee8e..d47f18eb 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -2608,7 +2608,7 @@ variableListChangedHandler (void* parameter, bool create, MmsVariableListType li if (listType == MMS_DOMAIN_SPECIFIC) { if (rc->dataSet->logicalDeviceName != NULL) { if (strcmp(rc->dataSet->name, listName) == 0) { - if (strcmp(rc->dataSet->logicalDeviceName, MmsDomain_getName(domain)) == 0) { + if (strcmp(rc->dataSet->logicalDeviceName, MmsDomain_getName(domain) + strlen(self->model->name)) == 0) { allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT; break; } @@ -2650,7 +2650,7 @@ variableListChangedHandler (void* parameter, bool create, MmsVariableListType li if (listType == MMS_DOMAIN_SPECIFIC) { if (lc->dataSet->logicalDeviceName != NULL) { if (strcmp(lc->dataSet->name, listName) == 0) { - if (strcmp(lc->dataSet->logicalDeviceName, MmsDomain_getName(domain)) == 0) { + if (strcmp(lc->dataSet->logicalDeviceName, MmsDomain_getName(domain) + strlen(self->model->name)) == 0) { allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT; break; } @@ -3196,7 +3196,7 @@ MmsMapping_createDataSetByNamedVariableList(MmsMapping* self, MmsNamedVariableLi DataSet* dataSet = (DataSet*) GLOBAL_MALLOC(sizeof(DataSet)); if (variableList->domain != NULL) - dataSet->logicalDeviceName = MmsDomain_getName(variableList->domain); + dataSet->logicalDeviceName = MmsDomain_getName(variableList->domain) + strlen(self->model->name); else dataSet->logicalDeviceName = NULL; /* name is not relevant for association specific data sets */ diff --git a/src/mms/inc/mms_client_connection.h b/src/mms/inc/mms_client_connection.h index f4d631b3..a4a7e837 100644 --- a/src/mms/inc/mms_client_connection.h +++ b/src/mms/inc/mms_client_connection.h @@ -373,6 +373,23 @@ MmsConnection_getVariableListNamesAssociationSpecific(MmsConnection self, MmsErr MmsValue* MmsConnection_readVariable(MmsConnection self, MmsError* mmsError, const char* domainId, const char* itemId); +/** + * \brief Read a component of a single variable from the server. + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param domainId the domain name of the variable to be read or NULL to read a VMD specific named variable + * \param itemId name of the variable to be read + * \param componentId the component name + * + * \return Returns a MmsValue object or NULL if the request failed. The MmsValue object can + * either be a simple value or a complex value or array. It is also possible that the return value is NULL + * even if mmsError = MMS_ERROR_NON. This is the case when the servers returns an empty result list. + */ +MmsValue* +MmsConnection_readVariableComponent(MmsConnection self, MmsError* mmsError, + const char* domainId, const char* itemId, const char* componentId); + /** * \brief Read one or more elements of a single array variable from the server. * diff --git a/src/mms/inc_private/mms_client_internal.h b/src/mms/inc_private/mms_client_internal.h index 9ffdb731..6b53a5e4 100644 --- a/src/mms/inc_private/mms_client_internal.h +++ b/src/mms/inc_private/mms_client_internal.h @@ -160,6 +160,9 @@ mmsClient_parseReadResponse(ByteBuffer* message, uint32_t* invokeId, bool create int mmsClient_createReadRequest(uint32_t invokeId, const char* domainId, const char* itemId, ByteBuffer* writeBuffer); +int +mmsClient_createReadRequestComponent(uint32_t invokeId, const char* domainId, const char* itemId, const char* component, ByteBuffer* writeBuffer); + int mmsClient_createReadRequestAlternateAccessIndex(uint32_t invokeId, const char* domainId, const char* itemId, uint32_t index, uint32_t elementCount, ByteBuffer* writeBuffer); diff --git a/src/mms/inc_private/mms_server_internal.h b/src/mms/inc_private/mms_server_internal.h index 7a9155f4..eef28d1f 100644 --- a/src/mms/inc_private/mms_server_internal.h +++ b/src/mms/inc_private/mms_server_internal.h @@ -357,9 +357,13 @@ mmsServer_handleObtainFileRequest( uint32_t invokeId, ByteBuffer* response); -int + +bool mmsServer_isIndexAccess(AlternateAccess_t* alternateAccess); +bool +mmsServer_isComponentAccess(AlternateAccess_t* alternateAccess); + int mmsServer_getLowIndex(AlternateAccess_t* alternateAccess); diff --git a/src/mms/iso_mms/client/mms_client_connection.c b/src/mms/iso_mms/client/mms_client_connection.c index b6a05546..d88aba2f 100644 --- a/src/mms/iso_mms/client/mms_client_connection.c +++ b/src/mms/iso_mms/client/mms_client_connection.c @@ -1589,6 +1589,34 @@ MmsConnection_readVariable(MmsConnection self, MmsError* mmsError, return value; } +MmsValue* +MmsConnection_readVariableComponent(MmsConnection self, MmsError* mmsError, + const char* domainId, const char* itemId, const char* componentId) +{ + MmsValue* value = NULL; + + if (getAssociationState(self) != MMS_STATE_CONNECTED) { + *mmsError = MMS_ERROR_CONNECTION_LOST; + goto exit_function; + } + + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + uint32_t invokeId = getNextInvokeId(self); + + mmsClient_createReadRequestComponent(invokeId, domainId, itemId, componentId, payload); + + ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload, mmsError); + + if (responseMessage != NULL) + value = mmsClient_parseReadResponse(self->lastResponse, NULL, false); + + releaseResponse(self); + + exit_function: + return value; +} + MmsValue* MmsConnection_readArrayElements(MmsConnection self, MmsError* mmsError, const char* domainId, const char* itemId, @@ -1697,9 +1725,13 @@ MmsConnection_readNamedVariableListValues(MmsConnection self, MmsError* mmsError ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload, mmsError); - if (responseMessage != NULL) + if (responseMessage != NULL) { value = mmsClient_parseReadResponse(self->lastResponse, NULL, true); + if (value == NULL) + *mmsError = MMS_ERROR_PARSING_RESPONSE; + } + releaseResponse(self); exit_function: diff --git a/src/mms/iso_mms/client/mms_client_get_var_access.c b/src/mms/iso_mms/client/mms_client_get_var_access.c index d66f5f22..9da333a2 100644 --- a/src/mms/iso_mms/client/mms_client_get_var_access.c +++ b/src/mms/iso_mms/client/mms_client_get_var_access.c @@ -138,23 +138,23 @@ mmsClient_parseGetVariableAccessAttributesResponse(ByteBuffer* message, uint32_t asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu, (void**) &mmsPdu, ByteBuffer_getBuffer(message), ByteBuffer_getSize(message)); - if (rval.code != RC_OK) - return NULL; + if (rval.code == RC_OK) { - if (mmsPdu->present == MmsPdu_PR_confirmedResponsePdu) { + if (mmsPdu->present == MmsPdu_PR_confirmedResponsePdu) { - if (invokeId != NULL) - *invokeId = mmsClient_getInvokeId(&mmsPdu->choice.confirmedResponsePdu); + if (invokeId != NULL) + *invokeId = mmsClient_getInvokeId(&mmsPdu->choice.confirmedResponsePdu); - if (mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present == - ConfirmedServiceResponse_PR_getVariableAccessAttributes) - { - GetVariableAccessAttributesResponse_t* response; + if (mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present == + ConfirmedServiceResponse_PR_getVariableAccessAttributes) + { + GetVariableAccessAttributesResponse_t* response; - response = &(mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.choice.getVariableAccessAttributes); - TypeSpecification_t* asnTypeSpec = &response->typeSpecification; + response = &(mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.choice.getVariableAccessAttributes); + TypeSpecification_t* asnTypeSpec = &response->typeSpecification; - typeSpec = createTypeSpecification(asnTypeSpec); + typeSpec = createTypeSpecification(asnTypeSpec); + } } } diff --git a/src/mms/iso_mms/client/mms_client_read.c b/src/mms/iso_mms/client/mms_client_read.c index 30a211c6..fbd97672 100644 --- a/src/mms/iso_mms/client/mms_client_read.c +++ b/src/mms/iso_mms/client/mms_client_read.c @@ -46,6 +46,9 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi int i = 0; for (i = 0; i < elementCount; i++) { + + value = NULL; + AccessResult_PR presentType = accessResultList[i]->present; if (presentType == AccessResult_PR_failure) { @@ -66,72 +69,138 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi value = MmsValue_newDataAccessError(DATA_ACCESS_ERROR_UNKNOWN); } else if (presentType == AccessResult_PR_array) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_ARRAY; int arrayElementCount = accessResultList[i]->choice.array.list.count; - value->value.structure.size = arrayElementCount; - value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(arrayElementCount, sizeof(MmsValue*)); - - int j; - - for (j = 0; j < arrayElementCount; j++) { - value->value.structure.components[j] = mmsMsg_parseDataElement( - accessResultList[i]->choice.array.list.array[j]); + if (arrayElementCount > 0) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_ARRAY; + value->value.structure.size = arrayElementCount; + value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(arrayElementCount, sizeof(MmsValue*)); + + int j; + + for (j = 0; j < arrayElementCount; j++) { + value->value.structure.components[j] = mmsMsg_parseDataElement( + 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) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_STRUCTURE; int componentCount = accessResultList[i]->choice.structure.list.count; - value->value.structure.size = componentCount; - value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); - - int j; - for (j = 0; j < componentCount; j++) { - value->value.structure.components[j] = mmsMsg_parseDataElement( - accessResultList[i]->choice.structure.list.array[j]); + if (componentCount > 0) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_STRUCTURE; + value->value.structure.size = componentCount; + value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); + + int j; + for (j = 0; j < componentCount; j++) { + value->value.structure.components[j] = mmsMsg_parseDataElement( + 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) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_BIT_STRING; + int size = accessResultList[i]->choice.bitstring.size; - value->value.bitString.size = (size * 8) - - accessResultList[i]->choice.bitstring.bits_unused; + if (size > 0) { + + int maxSize = (size * 8); + int bitSize = maxSize - accessResultList[i]->choice.bitstring.bits_unused; + + if ((bitSize > 0) && (maxSize >= bitSize)) { - value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size); - memcpy(value->value.bitString.buf, - accessResultList[i]->choice.bitstring.buf, size); + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_BIT_STRING; + + + value->value.bitString.size = (size * 8) + - accessResultList[i]->choice.bitstring.bits_unused; + + value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size); + memcpy(value->value.bitString.buf, + 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) { - Asn1PrimitiveValue* berInteger = - BerInteger_createFromBuffer(accessResultList[i]->choice.integer.buf, - accessResultList[i]->choice.integer.size); - value = MmsValue_newIntegerFromBerInteger(berInteger); + int size = accessResultList[i]->choice.integer.size; + + if (size > 0) { + Asn1PrimitiveValue* berInteger = + BerInteger_createFromBuffer(accessResultList[i]->choice.integer.buf, size); + + 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) { - Asn1PrimitiveValue* berInteger = - BerInteger_createFromBuffer(accessResultList[i]->choice.Unsigned.buf, - accessResultList[i]->choice.Unsigned.size); - value = MmsValue_newUnsignedFromBerInteger(berInteger); + int size = accessResultList[i]->choice.Unsigned.size; + + if (size > 0) { + Asn1PrimitiveValue* berInteger = + BerInteger_createFromBuffer(accessResultList[i]->choice.Unsigned.buf, + accessResultList[i]->choice.Unsigned.size); + + 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) { - int size = accessResultList[i]->choice.floatingpoint.size; - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_FLOAT; + int size = accessResultList[i]->choice.floatingpoint.size; if (size == 5) { /* FLOAT32 */ + + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_FLOAT; + value->value.floatingPoint.formatWidth = 32; value->value.floatingPoint.exponentWidth = accessResultList[i]->choice.floatingpoint.buf[0]; @@ -146,8 +215,11 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi #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.exponentWidth = accessResultList[i]->choice.floatingpoint.buf[0]; @@ -161,46 +233,70 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi memcpy(value->value.floatingPoint.buf, floatBuf, 8); #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) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - - value->type = MMS_VISIBLE_STRING; int strSize = accessResultList[i]->choice.visiblestring.size; - value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1); - value->value.visibleString.size = strSize; + 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.size = strSize; - memcpy(value->value.visibleString.buf, - accessResultList[i]->choice.visiblestring.buf, - strSize); + memcpy(value->value.visibleString.buf, + accessResultList[i]->choice.visiblestring.buf, + strSize); + + value->value.visibleString.buf[strSize] = 0; + } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing access result (invalid visible-string size)\n"); + } - value->value.visibleString.buf[strSize] = 0; } else if (presentType == AccessResult_PR_mMSString) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - - value->type = MMS_STRING; int strSize = accessResultList[i]->choice.mMSString.size; - value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1); - value->value.visibleString.size = strSize; + if (strSize >= 0) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - memcpy(value->value.visibleString.buf, - accessResultList[i]->choice.mMSString.buf, strSize); + value->type = MMS_STRING; + value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1); + value->value.visibleString.size = strSize; - value->value.visibleString.buf[strSize] = 0; + memcpy(value->value.visibleString.buf, + accessResultList[i]->choice.mMSString.buf, strSize); + 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) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_UTC_TIME; - memcpy(value->value.utcTime, - accessResultList[i]->choice.utctime.buf, 8); + int size = accessResultList[i]->choice.utctime.size; + + if (size == 8) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + value->type = MMS_UTC_TIME; + memcpy(value->value.utcTime, 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) { value = MmsValue_newBoolean(accessResultList[i]->choice.boolean); @@ -208,25 +304,36 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi else if (presentType == AccessResult_PR_binarytime) { int size = accessResultList[i]->choice.binarytime.size; - if (size <= 6) { + if ((size == 4) || (size == 6)) { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_BINARY_TIME; value->value.binaryTime.size = 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) { int size = accessResultList[i]->choice.octetstring.size; - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_OCTET_STRING; - value->value.octetString.maxSize = size; - value->value.octetString.size = size; - value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size); - memcpy(value->value.octetString.buf, accessResultList[i]->choice.octetstring.buf, size); + if (size >= 0) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_OCTET_STRING; + value->value.octetString.maxSize = size; + value->value.octetString.size = size; + value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size); + memcpy(value->value.octetString.buf, accessResultList[i]->choice.octetstring.buf, size); + } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing access result (invalid octet-string size)\n"); + } } else { - printf("unknown type %i\n", presentType); + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: unknown type %i in access result\n", presentType); value = MmsValue_newDataAccessError(DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID); } @@ -254,21 +361,20 @@ mmsClient_parseReadResponse(ByteBuffer* message, uint32_t* invokeId, bool create asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu, (void**) &mmsPdu, ByteBuffer_getBuffer(message), ByteBuffer_getSize(message)); - if (rval.code != RC_OK) - return NULL; - - if (mmsPdu->present == MmsPdu_PR_confirmedResponsePdu) { + if (rval.code == RC_OK) { + if (mmsPdu->present == MmsPdu_PR_confirmedResponsePdu) { - if (invokeId != NULL) - *invokeId = mmsClient_getInvokeId(&mmsPdu->choice.confirmedResponsePdu); + if (invokeId != NULL) + *invokeId = mmsClient_getInvokeId(&mmsPdu->choice.confirmedResponsePdu); - if (mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present == ConfirmedServiceResponse_PR_read) { - ReadResponse_t* response = &(mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.choice.read); + if (mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present == ConfirmedServiceResponse_PR_read) { + ReadResponse_t* response = &(mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.choice.read); - int elementCount = response->listOfAccessResult.list.count; + int elementCount = response->listOfAccessResult.list.count; - valueList = mmsClient_parseListOfAccessResults(response->listOfAccessResult.list.array, - elementCount, createArray); + valueList = mmsClient_parseListOfAccessResults(response->listOfAccessResult.list.array, + elementCount, createArray); + } } } @@ -422,7 +528,7 @@ mmsClient_createReadRequest(uint32_t invokeId, const char* domainId, const char* } static AlternateAccess_t* -createAlternateAccess(uint32_t index, uint32_t elementCount) +createAlternateAccessComponent(const char* componentName) { AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t)); alternateAccess->list.count = 1; @@ -432,37 +538,114 @@ createAlternateAccess(uint32_t index, uint32_t elementCount) alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t)); - alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess; - - if (elementCount > 0) { - alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present = - AlternateAccessSelection__selectAccess_PR_indexRange; + const char* separator = strchr(componentName, '$'); - INTEGER_t* asnIndex = - &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex); + if (separator) { + int size = separator - componentName; - asn_long2INTEGER(asnIndex, index); + alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAlternateAccess; + alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.present = + AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_component; - asnIndex = - &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements); + alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.choice.component.buf = + (uint8_t*) StringUtils_copySubString((char*) componentName, (char*) separator); + alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.choice.component.size = size; - asn_long2INTEGER(asnIndex, elementCount); + alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess = createAlternateAccessComponent(separator + 1); } else { - alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present = - AlternateAccessSelection__selectAccess_PR_index; + int size = strlen(componentName); - INTEGER_t* asnIndex = - &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index); + alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess; - asn_long2INTEGER(asnIndex, index); + alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present = + AlternateAccessSelection__selectAccess_PR_component; + + alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.component.buf = + (uint8_t*) StringUtils_copyString(componentName); + alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.component.size = size; } return alternateAccess; } +static void +deleteAlternateAccessComponent(AlternateAccess_t* alternateAccess) +{ + GLOBAL_FREEMEM(alternateAccess->list.array[0]->choice.unnamed); + GLOBAL_FREEMEM(alternateAccess->list.array[0]); + GLOBAL_FREEMEM(alternateAccess->list.array); + GLOBAL_FREEMEM(alternateAccess); +} + +static ListOfVariableSeq_t* +createNewVariableSpecification(const char* domainId, const char* itemId, const char* componentName, bool associationSpecific) +{ + ListOfVariableSeq_t* varSpec = (ListOfVariableSeq_t*) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t)); + + varSpec->variableSpecification.present = VariableSpecification_PR_name; + + if (domainId) { + varSpec->variableSpecification.choice.name.present = ObjectName_PR_domainspecific; + varSpec->variableSpecification.choice.name.choice.domainspecific.domainId.buf = (uint8_t*) domainId; + varSpec->variableSpecification.choice.name.choice.domainspecific.domainId.size = strlen(domainId); + varSpec->variableSpecification.choice.name.choice.domainspecific.itemId.buf = (uint8_t*) itemId; + varSpec->variableSpecification.choice.name.choice.domainspecific.itemId.size = strlen(itemId); + } + else if (associationSpecific) { + varSpec->variableSpecification.choice.name.present = ObjectName_PR_aaspecific; + varSpec->variableSpecification.choice.name.choice.aaspecific.buf = (uint8_t*) itemId; + varSpec->variableSpecification.choice.name.choice.aaspecific.size = strlen(itemId); + } + else { + varSpec->variableSpecification.choice.name.present = ObjectName_PR_vmdspecific; + varSpec->variableSpecification.choice.name.choice.vmdspecific.buf = (uint8_t*) itemId; + varSpec->variableSpecification.choice.name.choice.vmdspecific.size = strlen(itemId); + } + + if (componentName) + varSpec->alternateAccess = createAlternateAccessComponent(componentName); + + return varSpec; +} + +/** + * Request a single value with optional component + */ +int +mmsClient_createReadRequestComponent(uint32_t invokeId, const char* domainId, const char* itemId, const char* component, ByteBuffer* writeBuffer) +{ + MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); + + ReadRequest_t* readRequest = createReadRequest(mmsPdu); + + readRequest->specificationWithResult = NULL; + + readRequest->variableAccessSpecification.present = VariableAccessSpecification_PR_listOfVariable; + readRequest->variableAccessSpecification.choice.listOfVariable.list.count = 1; + readRequest->variableAccessSpecification.choice.listOfVariable.list.size = 1; + readRequest->variableAccessSpecification.choice.listOfVariable.list.array = + (ListOfVariableSeq_t**) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t*)); + readRequest->variableAccessSpecification.choice.listOfVariable.list.array[0] = createNewVariableSpecification(domainId, itemId, component, false); + + asn_enc_rval_t rval; + + rval = der_encode(&asn_DEF_MmsPdu, mmsPdu, + (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); + + /* clean up data structures */ + deleteAlternateAccessComponent(readRequest->variableAccessSpecification.choice.listOfVariable.list.array[0]->alternateAccess); + + GLOBAL_FREEMEM(readRequest->variableAccessSpecification.choice.listOfVariable.list.array); + readRequest->variableAccessSpecification.choice.listOfVariable.list.array = NULL; + readRequest->variableAccessSpecification.choice.listOfVariable.list.count = 0; + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + + return rval.encoded; +} + static AlternateAccess_t* -createAlternateAccessComponent(const char* componentName) +createAlternateAccess(uint32_t index, uint32_t elementCount) { AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t)); alternateAccess->list.count = 1; @@ -472,32 +655,30 @@ createAlternateAccessComponent(const char* componentName) alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t)); - const char* separator = strchr(componentName, '$'); + alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess; - if (separator) { - int size = separator - componentName; + if (elementCount > 0) { + alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present = + AlternateAccessSelection__selectAccess_PR_indexRange; - alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAlternateAccess; - alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.present = - AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_component; + INTEGER_t* asnIndex = + &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex); - alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.choice.component.buf = - (uint8_t*) StringUtils_copySubString((char*) componentName, (char*) separator); - alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.choice.component.size = size; + asn_long2INTEGER(asnIndex, index); - alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess = createAlternateAccessComponent(separator + 1); + asnIndex = + &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements); + + asn_long2INTEGER(asnIndex, elementCount); } else { - int size = strlen(componentName); - - alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess; - alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present = - AlternateAccessSelection__selectAccess_PR_component; + AlternateAccessSelection__selectAccess_PR_index; - alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.component.buf = - (uint8_t*) StringUtils_copyString(componentName); - alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.component.size = size; + INTEGER_t* asnIndex = + &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index); + + asn_long2INTEGER(asnIndex, index); } return alternateAccess; diff --git a/src/mms/iso_mms/common/mms_common_msg.c b/src/mms/iso_mms/common/mms_common_msg.c index 47673a48..38cb34f9 100644 --- a/src/mms/iso_mms/common/mms_common_msg.c +++ b/src/mms/iso_mms/common/mms_common_msg.c @@ -185,80 +185,175 @@ mmsMsg_parseDataElement(Data_t* dataElement) { MmsValue* value = NULL; - if (dataElement->present == Data_PR_structure) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + if (dataElement->present == Data_PR_array) { + + int componentCount = dataElement->choice.array->list.count; + + if (componentCount > 0) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + value->type = MMS_ARRAY; + value->value.structure.size = componentCount; + value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); + + int i; + + for (i = 0; i < componentCount; i++) { + value->value.structure.components[i] = + mmsMsg_parseDataElement(dataElement->choice.array->list.array[i]); + + if (value->value.structure.components[i] == NULL) { + MmsValue_delete(value); + value = NULL; + break; + } + } + } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing data element (invalid array size)!\n"); + } + + } + else if (dataElement->present == Data_PR_structure) { int componentCount = dataElement->choice.structure->list.count; - value->type = MMS_STRUCTURE; - value->value.structure.size = componentCount; - value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); + if (componentCount > 0) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + value->type = MMS_STRUCTURE; + value->value.structure.size = componentCount; + value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); + + int i; - int i; + for (i = 0; i < componentCount; i++) { + value->value.structure.components[i] = + mmsMsg_parseDataElement(dataElement->choice.structure->list.array[i]); - for (i = 0; i < componentCount; i++) { - value->value.structure.components[i] = - mmsMsg_parseDataElement(dataElement->choice.structure->list.array[i]); + if (value->value.structure.components[i] == NULL) { + MmsValue_delete(value); + value = NULL; + break; + } + } + } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing data element (invalid structure size)!\n"); } } else if (dataElement->present == Data_PR_array) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); int componentCount = dataElement->choice.array->list.count; - value->type = MMS_ARRAY; - value->value.structure.size = componentCount; - value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); + if (componentCount > 0) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - int i; + value->type = MMS_ARRAY; + value->value.structure.size = componentCount; + value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); - for (i = 0; i < componentCount; i++) { - value->value.structure.components[i] = - mmsMsg_parseDataElement(dataElement->choice.array->list.array[i]); + int i; + + for (i = 0; i < componentCount; i++) { + value->value.structure.components[i] = + mmsMsg_parseDataElement(dataElement->choice.array->list.array[i]); + + if (value->value.structure.components[i] == NULL) { + MmsValue_delete(value); + value = NULL; + break; + } + } + } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing data element (invalid array size)!\n"); } + } else { if (dataElement->present == Data_PR_integer) { - Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer( - dataElement->choice.integer.buf, dataElement->choice.integer.size); - value = MmsValue_newIntegerFromBerInteger(berInteger); + if (dataElement->choice.integer.size > 0) { + Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer( + dataElement->choice.integer.buf, dataElement->choice.integer.size); + + 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) { - Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer( - dataElement->choice.Unsigned.buf, dataElement->choice.Unsigned.size); - value = MmsValue_newUnsignedFromBerInteger(berInteger); + if (dataElement->choice.Unsigned.size > 0) { + Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer( + dataElement->choice.Unsigned.buf, dataElement->choice.Unsigned.size); + + 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) { - value = MmsValue_newVisibleStringFromByteArray(dataElement->choice.visiblestring.buf, - dataElement->choice.visiblestring.size); + + if (dataElement->choice.visiblestring.size >= 0) { + value = MmsValue_newVisibleStringFromByteArray(dataElement->choice.visiblestring.buf, + dataElement->choice.visiblestring.size); + } } else if (dataElement->present == Data_PR_mMSString) { - value = MmsValue_newMmsStringFromByteArray(dataElement->choice.mMSString.buf, - dataElement->choice.mMSString.size); + + if ( dataElement->choice.mMSString.size >= 0) { + value = MmsValue_newMmsStringFromByteArray(dataElement->choice.mMSString.buf, + dataElement->choice.mMSString.size); + } } else if (dataElement->present == Data_PR_bitstring) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_BIT_STRING; int size = dataElement->choice.bitstring.size; - value->value.bitString.size = (size * 8) - - dataElement->choice.bitstring.bits_unused; + if (size > 0) { + + int maxSize = (size * 8); + int bitSize = maxSize - dataElement->choice.bitstring.bits_unused; - value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size); - memcpy(value->value.bitString.buf, - dataElement->choice.bitstring.buf, size); + if ((bitSize > 0) && (maxSize >= bitSize)) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_BIT_STRING; + + value->value.bitString.size = bitSize; + + value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size); + memcpy(value->value.bitString.buf, + 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) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - int size = dataElement->choice.floatingpoint.size; - value->type = MMS_FLOAT; + int size = dataElement->choice.floatingpoint.size; if (size == 5) { /* FLOAT32 */ + + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_FLOAT; + value->value.floatingPoint.formatWidth = 32; value->value.floatingPoint.exponentWidth = dataElement->choice.floatingpoint.buf[0]; @@ -273,6 +368,10 @@ mmsMsg_parseDataElement(Data_t* dataElement) } if (size == 9) { /* FLOAT64 */ + + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_FLOAT; + value->value.floatingPoint.formatWidth = 64; value->value.floatingPoint.exponentWidth = dataElement->choice.floatingpoint.buf[0]; @@ -287,33 +386,58 @@ mmsMsg_parseDataElement(Data_t* dataElement) } } else if (dataElement->present == Data_PR_utctime) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_UTC_TIME; - memcpy(value->value.utcTime, dataElement->choice.utctime.buf, 8); + + int size = dataElement->choice.utctime.size; + + if (size == 8) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_UTC_TIME; + 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) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_OCTET_STRING; - int size = dataElement->choice.octetstring.size; - value->value.octetString.size = size; - value->value.octetString.maxSize = size; - value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size); - memcpy(value->value.octetString.buf, dataElement->choice.octetstring.buf, size); + + if (dataElement->choice.octetstring.size >= 0) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_OCTET_STRING; + int size = dataElement->choice.octetstring.size; + value->value.octetString.size = size; + value->value.octetString.maxSize = size; + value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size); + memcpy(value->value.octetString.buf, dataElement->choice.octetstring.buf, size); + } + } else if (dataElement->present == Data_PR_binarytime) { int size = dataElement->choice.binarytime.size; - if (size <= 6) { + if ((size == 4) || (size == 6)) { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_BINARY_TIME; value->value.binaryTime.size = 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) { value = MmsValue_newBoolean(dataElement->choice.boolean); } + else if (dataElement->present == Data_PR_booleanArray) { + + } + + } + if (DEBUG_MMS_CLIENT) { + if (value == NULL) + printf("MMS CLIENT: error parsing data element\n"); } return value; @@ -350,7 +474,6 @@ void mmsMsg_createExtendedFilename(const char* basepath, char* extendedFileName, char* fileName) { #if (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1) - // strncpy(extendedFileName, MmsServerConnection_getFilesystemBasepath(self), 512); strncpy(extendedFileName, basepath, 512); strncat(extendedFileName, fileName, 512); #else diff --git a/src/mms/iso_mms/common/mms_value.c b/src/mms/iso_mms/common/mms_value.c index 1d8485e2..f2453907 100644 --- a/src/mms/iso_mms/common/mms_value.c +++ b/src/mms/iso_mms/common/mms_value.c @@ -1081,10 +1081,12 @@ MmsValue_cloneToBuffer(const MmsValue* self, uint8_t* destinationAddress) return destinationAddress; } -// create a deep clone MmsValue* MmsValue_clone(const MmsValue* self) { + if (self == NULL) + return NULL; + MmsValue* newValue = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); if (newValue == NULL) @@ -1188,6 +1190,9 @@ MmsValue_deleteIfNotNull(MmsValue* self) void MmsValue_delete(MmsValue* self) { + if (self == NULL) + return; + switch (self->type) { case MMS_INTEGER: @@ -2010,6 +2015,16 @@ MmsValue_getTypeString(MmsValue* self) const char* 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)) { case MMS_STRUCTURE: diff --git a/src/mms/iso_mms/server/mms_read_service.c b/src/mms/iso_mms/server/mms_read_service.c index 5a7a62d2..caee6785 100644 --- a/src/mms/iso_mms/server/mms_read_service.c +++ b/src/mms/iso_mms/server/mms_read_service.c @@ -155,6 +155,51 @@ isAccessToArrayComponent(AlternateAccess_t* alternateAccess) return false; } +static MmsValue* +getComponent(AlternateAccess_t* alternateAccess, MmsVariableSpecification* namedVariable, MmsValue* variableValue) +{ + MmsValue* retValue = NULL; + + if (mmsServer_isComponentAccess(alternateAccess)) { + Identifier_t component = + alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.component; + + if (component.size > 129) + goto exit_function; + + if (namedVariable->type == MMS_STRUCTURE) { + + int i; + + for (i = 0; i < namedVariable->typeSpec.structure.elementCount; + i++) { + + if (strlen(namedVariable->typeSpec.structure.elements[i]->name) + == component.size) { + if (strncmp( + namedVariable->typeSpec.structure.elements[i]->name, + (char*) component.buf, component.size) == 0) { + MmsValue* value = MmsValue_getElement(variableValue, i); + + if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess + != NULL) { + retValue = + getComponent( + alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess, + namedVariable->typeSpec.structure.elements[i], + value); + } + else + retValue = value; + } + } + } + } + } + + exit_function: return retValue; +} + static MmsValue* getComponentOfArrayElement(AlternateAccess_t* alternateAccess, MmsVariableSpecification* namedVariable, MmsValue* structuredValue) @@ -180,19 +225,26 @@ getComponentOfArrayElement(AlternateAccess_t* alternateAccess, MmsVariableSpecif int i; for (i = 0; i < structSpec->typeSpec.structure.elementCount; i++) { - if (strncmp (structSpec->typeSpec.structure.elements[i]->name, (char*) component.buf, - component.size) == 0) - { - MmsValue* value = MmsValue_getElement(structuredValue, i); - - if (isAccessToArrayComponent(alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess)) { - retValue = getComponentOfArrayElement(alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess, - structSpec->typeSpec.structure.elements[i], value); - } - else - retValue = value; - goto exit_function; + if (strlen(structSpec->typeSpec.structure.elements[i]->name) + == component.size) { + if (strncmp(structSpec->typeSpec.structure.elements[i]->name, + (char*) component.buf, component.size) == 0) { + MmsValue* value = MmsValue_getElement(structuredValue, i); + + if (isAccessToArrayComponent( + alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess)) { + retValue = + getComponentOfArrayElement( + alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess, + structSpec->typeSpec.structure.elements[i], + value); + } + else + retValue = value; + + goto exit_function; + } } } } @@ -288,12 +340,24 @@ addNamedVariableToResultList(MmsVariableSpecification* namedVariable, MmsDomain* MmsValue* value = mmsServer_getValue(connection->server, domain, nameIdStr, connection); - if (value != NULL) { - appendValueToResultList(value, values); + if (alternateAccess != NULL) { + value = getComponent(alternateAccess, namedVariable, value); + + if (value != NULL) { + appendValueToResultList(value, values); + } + else { + appendErrorToResultList(values, DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT); + } } else { - addComplexValueToResultList(namedVariable, - values, connection, domain, nameIdStr); + if (value != NULL) { + appendValueToResultList(value, values); + } + else { + addComplexValueToResultList(namedVariable, + values, connection, domain, nameIdStr); + } } } else if (namedVariable->type == MMS_ARRAY) { diff --git a/src/mms/iso_mms/server/mms_server_common.c b/src/mms/iso_mms/server/mms_server_common.c index e6522bf4..c2400a60 100644 --- a/src/mms/iso_mms/server/mms_server_common.c +++ b/src/mms/iso_mms/server/mms_server_common.c @@ -208,7 +208,7 @@ mmsMsg_createServiceErrorPdu(uint32_t invokeId, ByteBuffer* response, MmsError e mmsServer_createServiceErrorPduWithServiceSpecificInfo(invokeId, response, errorType, NULL, 0); } -int +bool mmsServer_isIndexAccess(AlternateAccess_t* alternateAccess) { if (alternateAccess->list.array[0]->present == AlternateAccess__Member_PR_unnamed) { @@ -217,13 +217,25 @@ mmsServer_isIndexAccess(AlternateAccess_t* alternateAccess) (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present == AlternateAccessSelection__selectAccess_PR_indexRange)) { - return 1; + return true; } - else - return 0; } - else - return 0; + + return false; +} + +bool +mmsServer_isComponentAccess(AlternateAccess_t* alternateAccess) +{ + if (alternateAccess->list.array[0]->present + == AlternateAccess__Member_PR_unnamed) { + if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present + == AlternateAccessSelection__selectAccess_PR_component) { + return true; + } + } + + return false; } int diff --git a/tools/model_generator/src/com/libiec61850/scl/model/OptionFields.java b/tools/model_generator/src/com/libiec61850/scl/model/OptionFields.java index 226f1188..28b3d453 100644 --- a/tools/model_generator/src/com/libiec61850/scl/model/OptionFields.java +++ b/tools/model_generator/src/com/libiec61850/scl/model/OptionFields.java @@ -94,7 +94,7 @@ public class OptionFields { if (boolVal != null) this.configRef = boolVal; - boolVal = ParserUtils.parseBooleanAttribute(optFieldsNode, "bufOvlf"); + boolVal = ParserUtils.parseBooleanAttribute(optFieldsNode, "bufOvfl"); if (boolVal != null) this.bufOvfl = boolVal; }