// // -------------------------------------------------------------------------- // Gurux Ltd // // // // Filename: $HeadURL$ // // Version: $Revision$, // $Date$ // $Author$ // // Copyright (c) Gurux Ltd // //--------------------------------------------------------------------------- // // DESCRIPTION // // This file is a part of Gurux Device Framework. // // Gurux Device Framework is Open Source software; you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; version 2 of the License. // Gurux Device Framework is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details. // // This code is licensed under the GNU General Public License v2. // Full text may be retrieved at http://www.gnu.org/licenses/gpl-2.0.txt //--------------------------------------------------------------------------- #include "gxignore.h" #ifndef DLMS_IGNORE_SERVER #if defined(_WIN32) || defined(_WIN64) || defined(__linux__) #include #endif #include "gxmem.h" #if _MSC_VER > 1400 #include #endif #include #include "cosem.h" #include "dlms.h" #include "gxset.h" #include "gxinvoke.h" #include "helpers.h" #include "objectarray.h" #include "ciphering.h" #include "gxget.h" #include "gxkey.h" #include "serverevents.h" #ifndef DLMS_IGNORE_CHARGE int invoke_Charge( gxCharge* object, unsigned char index, dlmsVARIANT* value) { gxChargeTable* ct, * it; int ret = 0, pos; //Update unit charge. if (index == 1) { for (pos = 0; pos != object->unitChargePassive.chargeTables.size; ++pos) { #ifdef DLMS_IGNORE_MALLOC ret = arr_getByIndex(&object->unitChargePassive.chargeTables, pos, (void**)&ct, sizeof(gxCharge)); #else ret = arr_getByIndex(&object->unitChargePassive.chargeTables, pos, (void**)&ct); #endif //DLMS_IGNORE_MALLOC if (ret != 0) { return ret; } ct->chargePerUnit = (short)var_toInteger(value); } } //Activate passive unit charge. else if (index == 2) { object->unitChargeActive.chargePerUnitScaling = object->unitChargePassive.chargePerUnitScaling; object->unitChargeActive.commodity = object->unitChargePassive.commodity; for (pos = 0; pos != object->unitChargePassive.chargeTables.size; ++pos) { #ifdef DLMS_IGNORE_MALLOC if ((ret = arr_getByIndex(&object->unitChargePassive.chargeTables, pos, (void**)&ct, sizeof(gxChargeTable))) != 0 || (ret = arr_getByIndex(&object->unitChargeActive.chargeTables, object->unitChargeActive.chargeTables.size, (void**)&it, sizeof(gxChargeTable))) != 0) { break; } ++object->unitChargeActive.chargeTables.size; #else if ((ret = arr_getByIndex(&object->unitChargePassive.chargeTables, pos, (void**)&ct)) != 0) { break; } it = (gxChargeTable*)gxmalloc(sizeof(gxChargeTable)); arr_push(&object->unitChargeActive.chargeTables, it); #endif //DLMS_IGNORE_MALLOC it->chargePerUnit = ct->chargePerUnit; it->index = ct->index; } } //Update total amount remaining. else if (index == 4) { object->totalAmountRemaining += var_toInteger(value); } else { ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } return ret; } #endif //DLMS_IGNORE_CHARGE #ifndef DLMS_IGNORE_CREDIT int invoke_Credit( gxCredit* object, unsigned char index, dlmsVARIANT* value) { int ret = 0; //Update amount. if (index == 1) { object->currentCreditAmount += var_toInteger(value); } //Set amount to value. else if (index == 2) { object->currentCreditAmount = var_toInteger(value); } else if (index == 3) { // The mechanism for selecting the �Credit� is not in the scope of COSEM and // shall be specified by the implementer (e.g. button push, meter process, script etc.). object->status |= 4; } else { ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } return ret; } #endif //DLMS_IGNORE_CREDIT #ifndef DLMS_IGNORE_TOKEN_GATEWAY int invoke_gxTokenGateway( gxTokenGateway* object, unsigned char index, dlmsVARIANT* value) { int ret = 0; //Update token. if (index == 1) { bb_clear(&object->token); if (value->vt == DLMS_DATA_TYPE_OCTET_STRING) { bb_set(&object->token, value->byteArr->data, value->byteArr->size); } } else { ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } return ret; } #endif //DLMS_IGNORE_TOKEN_GATEWAY #ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME int invoke_AssociationLogicalName( dlmsServerSettings* settings, gxValueEventArg* e) { int ret = 0; gxAssociationLogicalName* object = (gxAssociationLogicalName*)e->target; // Check reply_to_HLS_authentication if (e->index == 1) { #ifndef DLMS_IGNORE_HIGH_GMAC unsigned char ch; gxByteBuffer tmp; #endif //DLMS_IGNORE_HIGH_GMAC unsigned char tmp2[64]; unsigned char equal; uint32_t ic = 0; gxByteBuffer bb; gxByteBuffer* readSecret; BYTE_BUFFER_INIT(&bb); #ifdef DLMS_IGNORE_MALLOC uint16_t count; if ((ret = bb_getUInt8(e->parameters.byteArr, &ch)) != 0) { return ret; } if (ch != DLMS_DATA_TYPE_OCTET_STRING) { #ifdef DLMS_DEBUG svr_notifyTrace("High authentication failed. ", DLMS_ERROR_CODE_INVALID_PARAMETER); #endif //DLMS_DEBUG return DLMS_ERROR_CODE_INVALID_PARAMETER; } if ((ret = hlp_getObjectCount2(e->parameters.byteArr, &count)) != 0) { #ifdef DLMS_DEBUG svr_notifyTrace("High authentication failed. ", DLMS_ERROR_CODE_INVALID_PARAMETER); #endif //DLMS_DEBUG return ret; } if (count > bb_available(e->parameters.byteArr)) { #ifdef DLMS_DEBUG svr_notifyTrace("High authentication failed. ", DLMS_ERROR_CODE_INVALID_PARAMETER); #endif //DLMS_DEBUG return DLMS_ERROR_CODE_INVALID_PARAMETER; } #endif //DLMS_IGNORE_MALLOC #ifndef DLMS_IGNORE_HIGH_GMAC if (settings->base.authentication == DLMS_AUTHENTICATION_HIGH_GMAC) { bb_attach(&tmp, settings->base.sourceSystemTitle, sizeof(settings->base.sourceSystemTitle), sizeof(settings->base.sourceSystemTitle)); if ((ret = bb_getUInt8(e->parameters.byteArr, &ch)) != 0 || (ret = bb_getUInt32(e->parameters.byteArr, &ic)) != 0) { return ret; } //IC is also compared. e->parameters.byteArr->position -= 5; readSecret = &tmp; } else #endif //DLMS_IGNORE_MALLOC { readSecret = &object->secret; } BYTE_BUFFER_INIT(&bb); bb_attach(&bb, tmp2, 0, sizeof(tmp2)); if ((ret = dlms_secure(&settings->base, ic, &settings->base.stoCChallenge, readSecret, &bb)) != 0) { return ret; } equal = bb_available(e->parameters.byteArr) != 0 && bb_compare(&bb, e->parameters.byteArr->data + e->parameters.byteArr->position, bb_available(e->parameters.byteArr)); bb_clear(&settings->info.data); if (equal) { #ifndef DLMS_IGNORE_HIGH_GMAC if (settings->base.authentication == DLMS_AUTHENTICATION_HIGH_GMAC) { #ifdef DLMS_IGNORE_MALLOC bb_attach(&tmp, settings->base.cipher.systemTitle, sizeof(settings->base.cipher.systemTitle), sizeof(settings->base.cipher.systemTitle)); readSecret = &tmp; #else readSecret = &settings->base.cipher.systemTitle; #endif //DLMS_IGNORE_MALLOC ic = settings->base.cipher.invocationCounter; } #endif //DLMS_IGNORE_HIGH_GMAC e->byteArray = 1; if ((ret = dlms_secure(&settings->base, ic, &settings->base.ctoSChallenge, readSecret, &settings->info.data)) != 0) { return ret; } bb_insertUInt8(&settings->info.data, 0, DLMS_DATA_TYPE_OCTET_STRING); bb_insertUInt8(&settings->info.data, 1, (unsigned char)(settings->info.data.size - 1)); object->associationStatus = DLMS_ASSOCIATION_STATUS_ASSOCIATED; } else { object->associationStatus = DLMS_ASSOCIATION_STATUS_NON_ASSOCIATED; ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; } } else if (e->index == 2) { #ifdef DLMS_IGNORE_MALLOC ret = cosem_getOctetString(e->parameters.byteArr, &object->secret); #else #if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) uint32_t size = bb_available(e->parameters.byteArr); #else uint16_t size = bb_available(e->parameters.byteArr); #endif if (size == 0) { ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; } else { bb_clear(&object->secret); ret = bb_set(&object->secret, e->parameters.byteArr->data + e->parameters.byteArr->position, size); } #endif //DLMS_IGNORE_MALLOC } else if (e->index == 5) { #ifdef DLMS_IGNORE_MALLOC gxUser* it; if (!(object->userList.size < arr_getCapacity(&object->userList))) { ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } else { ++object->userList.size; if ((ret = arr_getByIndex(&object->userList, object->userList.size - 1, (void**)&it, sizeof(gxUser))) == 0) { if ((ret = cosem_checkStructure(e->parameters.byteArr, 2)) != 0 || (ret = cosem_getUInt8(e->parameters.byteArr, &it->id)) != 0 || (ret = cosem_getString2(e->parameters.byteArr, it->name, sizeof(it->name))) != 0) { //Error code is returned at the end of the function. } } } #else if (e->parameters.vt != DLMS_DATA_TYPE_STRUCTURE || e->parameters.Arr->size != 2) { ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; } else { dlmsVARIANT* tmp; char* name; gxKey2* it = (gxKey2*)gxmalloc(sizeof(gxKey2)); if ((ret = va_getByIndex(e->parameters.Arr, 0, &tmp)) != 0) { gxfree(it); return ret; } it->key = tmp->bVal; if ((ret = va_getByIndex(e->parameters.Arr, 1, &tmp)) != 0) { gxfree(it); return ret; } name = gxmalloc(tmp->strVal->size + 1); it->value = name; *(name + tmp->strVal->size) = '\0'; memcpy(it->value, tmp->strVal->data, tmp->strVal->size); ret = arr_push(&((gxAssociationLogicalName*)e->target)->userList, it); } #endif //DLMS_IGNORE_MALLOC } else if (e->index == 6) { int pos; #ifdef DLMS_IGNORE_MALLOC gxUser* it; unsigned char id; char name[MAX_SAP_ITEM_NAME_LENGTH]; if ((ret = cosem_checkStructure(e->parameters.byteArr, 2)) == 0 && (ret = cosem_getUInt8(e->parameters.byteArr, &id)) == 0 && (ret = cosem_getString2(e->parameters.byteArr, name, sizeof(name))) == 0) { uint16_t size = (uint16_t)strlen(name); for (pos = 0; pos != ((gxAssociationLogicalName*)e->target)->userList.size; ++pos) { if ((ret = arr_getByIndex(&((gxAssociationLogicalName*)e->target)->userList, pos, (void**)&it, sizeof(gxUser))) != 0) { return ret; } if (it->id == id && memcmp(it->name, name, size) == 0) { int pos2; gxUser* it2; for (pos2 = pos + 1; pos2 < ((gxAssociationLogicalName*)e->target)->userList.size; ++pos2) { if ((ret = arr_getByIndex(&((gxAssociationLogicalName*)e->target)->userList, pos2, (void**)&it2, sizeof(gxUser))) != 0) { break; } memcpy(it, it2, sizeof(gxUser)); it = it2; } --((gxAssociationLogicalName*)e->target)->userList.size; break; } } } #else if (e->parameters.Arr->size != 2) { return DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; } else { gxKey2* it; unsigned char id; dlmsVARIANT* tmp; unsigned char* name; ret = va_getByIndex(e->parameters.Arr, 0, &tmp); id = tmp->bVal; ret = va_getByIndex(e->parameters.Arr, 1, &tmp); name = tmp->strVal->data; int len = tmp->strVal->size; for (pos = 0; pos != ((gxAssociationLogicalName*)e->target)->userList.size; ++pos) { ret = arr_getByIndex(&((gxAssociationLogicalName*)e->target)->userList, pos, (void**)&it); if (ret != 0) { return ret; } if (it->key == id && memcmp(it->value, name, len) == 0) { ret = arr_removeByIndex(&((gxAssociationLogicalName*)e->target)->userList, pos, (void**)&it); gxfree(it->value); gxfree(it); break; } } } #endif //DLMS_IGNORE_MALLOC } else { ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; } return ret; } #endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME #ifndef DLMS_IGNORE_IMAGE_TRANSFER int invoke_ImageTransfer( gxImageTransfer* target, gxValueEventArg* e) { int pos, ret = 0; //Image transfer initiate if (e->index == 1) { gxByteBuffer tmp; gxImageActivateInfo* it, * item = NULL; target->imageFirstNotTransferredBlockNumber = 0; ba_clear(&target->imageTransferredBlocksStatus); dlmsVARIANT* imageIdentifier, * size; #ifdef DLMS_IGNORE_MALLOC dlmsVARIANT imageIdentifier2, size2; uint16_t count; unsigned char ch; if ((ret = cosem_checkStructure(e->parameters.byteArr, 2)) != 0 || (ret = bb_getUInt8(e->parameters.byteArr, &ch)) != 0 || ch != DLMS_DATA_TYPE_OCTET_STRING || (ret = hlp_getObjectCount2(e->parameters.byteArr, &count)) != 0) { e->error = DLMS_ERROR_CODE_HARDWARE_FAULT; return ret; } imageIdentifier2.vt = DLMS_DATA_TYPE_OCTET_STRING; size2.vt = DLMS_DATA_TYPE_UINT32; //Attach image identifier so heap is not used. gxByteBuffer bb; bb_attach(&bb, e->parameters.byteArr->data + e->parameters.byteArr->position, count, count); imageIdentifier2.byteArr = &bb; e->parameters.byteArr->position += count; if ((ret = cosem_getUInt32(e->parameters.byteArr, &size2.ulVal)) != 0) { e->error = DLMS_ERROR_CODE_HARDWARE_FAULT; return ret; } imageIdentifier = &imageIdentifier2; size = &size2; #else if ((ret = va_getByIndex(e->parameters.Arr, 0, &imageIdentifier)) != 0 || (ret = va_getByIndex(e->parameters.Arr, 1, &size)) != 0) { e->error = DLMS_ERROR_CODE_HARDWARE_FAULT; return ret; } #endif //DLMS_IGNORE_MALLOC target->imageTransferStatus = DLMS_IMAGE_TRANSFER_STATUS_INITIATED; unsigned char exists = 0; for (pos = 0; pos != target->imageActivateInfo.size; ++pos) { #ifdef DLMS_IGNORE_MALLOC if ((ret = arr_getByIndex(&target->imageActivateInfo, pos, (void**)&it, sizeof(gxImageActivateInfo))) != 0) { return ret; } #else if ((ret = arr_getByIndex(&target->imageActivateInfo, pos, (void**)&it)) != 0) { return ret; } #endif //DLMS_IGNORE_MALLOC bb_attach(&tmp, it->identification.data, it->identification.size, it->identification.size); if (bb_size(imageIdentifier->byteArr) != 0 && bb_compare(&tmp, imageIdentifier->byteArr->data, imageIdentifier->byteArr->size)) { item = it; exists = 1; } } if (!exists) { #ifdef DLMS_IGNORE_MALLOC ++target->imageActivateInfo.size; if ((ret = arr_getByIndex(&target->imageActivateInfo, pos, (void**)&item, sizeof(gxImageActivateInfo))) != 0) { --target->imageActivateInfo.size; return ret; } #else item = (gxImageActivateInfo*)gxmalloc(sizeof(gxImageActivateInfo)); BYTE_BUFFER_INIT(&item->identification); BYTE_BUFFER_INIT(&item->signature); arr_push(&target->imageActivateInfo, item); #endif //DLMS_IGNORE_MALLOC item->size = var_toInteger(size); #ifdef DLMS_IGNORE_MALLOC item->identification.size = (uint16_t)imageIdentifier->byteArr->size; if ((ret = bb_get(imageIdentifier->byteArr, item->identification.data, imageIdentifier->byteArr->size)) != 0) { return ret; } #else item->identification.size = 0; if ((ret = bb_set2(&item->identification, imageIdentifier->byteArr, 0, bb_size(imageIdentifier->byteArr))) != 0) { return ret; } #endif //DLMS_IGNORE_MALLOC uint16_t cnt = (uint16_t)(item->size / target->imageBlockSize); if (item->size % target->imageBlockSize != 0) { ++cnt; } cnt = ba_getByteCount(cnt); #ifndef GX_DLMS_MICROCONTROLLER target->imageTransferredBlocksStatus.position = 0; #endif //GX_DLMS_MICROCONTROLLER #ifdef DLMS_IGNORE_MALLOC //Image transferred blocks status must handle in server side when malloc is not used if image size is huge. if (target->imageTransferredBlocksStatus.capacity != 0) { if (cnt > ba_getCapacity(&target->imageTransferredBlocksStatus)) { e->error = DLMS_ERROR_CODE_HARDWARE_FAULT; return ret; } else { target->imageTransferredBlocksStatus.size = 0; if ((ret = ba_capacity(&target->imageTransferredBlocksStatus, cnt)) == 0) { for (pos = 0; pos != cnt; ++pos) { ba_set(&target->imageTransferredBlocksStatus, 0); } } } } #else target->imageTransferredBlocksStatus.size = 0; if ((ret = ba_capacity(&target->imageTransferredBlocksStatus, cnt)) == 0) { for (pos = 0; pos != cnt; ++pos) { ba_set(&target->imageTransferredBlocksStatus, 0); } } #endif //DLMS_IGNORE_MALLOC } } //Image block transfer else if (e->index == 2) { uint32_t index; #ifdef DLMS_IGNORE_MALLOC if ((ret = cosem_checkStructure(e->parameters.byteArr, 2)) != 0 || (ret = cosem_getUInt32(e->parameters.byteArr, &index)) != 0) { e->error = DLMS_ERROR_CODE_HARDWARE_FAULT; return ret; } #else dlmsVARIANT* imageIndex; if ((ret = va_getByIndex(e->parameters.Arr, 0, &imageIndex)) != 0) { e->error = DLMS_ERROR_CODE_HARDWARE_FAULT; return ret; } index = (uint16_t)var_toInteger(imageIndex); #endif //DLMS_IGNORE_MALLOC if ((ret = ba_setByIndex(&target->imageTransferredBlocksStatus, (uint16_t)index, 1)) == 0) { target->imageFirstNotTransferredBlockNumber = index + 1; target->imageTransferStatus = DLMS_IMAGE_TRANSFER_STATUS_INITIATED; } #ifdef DLMS_IGNORE_MALLOC bb_clear(e->parameters.byteArr); #endif //DLMS_IGNORE_MALLOC } //Image verify else if (e->index == 3) { ret = 0; } //Image activate. else if (e->index == 4) { ret = 0; } else { ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; } return ret; } #endif //DLMS_IGNORE_IMAGE_TRANSFER #ifndef DLMS_IGNORE_SAP_ASSIGNMENT int invoke_SapAssigment( gxSapAssignment* target, gxValueEventArg* e) { int pos, ret = 0; uint16_t id; gxSapItem* it; //Image transfer initiate if (e->index == 1) { #ifdef DLMS_IGNORE_MALLOC if (e->parameters.vt != DLMS_DATA_TYPE_OCTET_STRING) { ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; } else if ((ret = cosem_checkStructure(e->parameters.byteArr, 2)) == 0 && (ret = cosem_getUInt16(e->parameters.byteArr, &id)) == 0) { if (id == 0) { uint16_t size; unsigned char name[MAX_SAP_ITEM_NAME_LENGTH]; if ((ret = cosem_getOctetString2(e->parameters.byteArr, name, sizeof(name), &size)) == 0) { name[size] = 0; for (pos = 0; pos != target->sapAssignmentList.size; ++pos) { if ((ret = arr_getByIndex(&target->sapAssignmentList, pos, (void**)&it, sizeof(gxSapItem))) != 0) { return ret; } if (it->name.size == size && memcmp(it->name.value, name, size) == 0) { if ((ret = arr_removeByIndex(&target->sapAssignmentList, pos, sizeof(gxSapItem))) == 0) { //arr_removeByIndex is decreasing amount already. break; } } } } } else { //If buffer is full. if (!(target->sapAssignmentList.size < target->sapAssignmentList.capacity)) { ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; } else { ++target->sapAssignmentList.size; if ((ret = arr_getByIndex(&target->sapAssignmentList, target->sapAssignmentList.size - 1, (void**)&it, sizeof(gxSapItem))) == 0 && (ret = cosem_getOctetString2(e->parameters.byteArr, it->name.value, sizeof(it->name.value), &it->name.size)) == 0) { it->id = id; } else { --target->sapAssignmentList.size; } } } } #else dlmsVARIANT* tmp; if ((ret = va_getByIndex(e->parameters.Arr, 0, &tmp)) != 0) { return ret; } id = tmp->uiVal; if ((ret = va_getByIndex(e->parameters.Arr, 1, &tmp)) != 0) { return ret; } gxByteBuffer* name; if (tmp->vt == DLMS_DATA_TYPE_OCTET_STRING) { name = tmp->byteArr; } else { name = tmp->strVal; } if (id == 0) { for (pos = 0; pos != target->sapAssignmentList.size; ++pos) { if ((ret = arr_getByIndex(&target->sapAssignmentList, pos, (void**)&it)) != 0) { return ret; } it->name.position = 0; if (name != NULL && bb_compare(&it->name, name->data, bb_size(name))) { ret = arr_removeByIndex(&target->sapAssignmentList, pos, (void**)&it); bb_clear(&it->name); gxfree(it); return ret; } } } else { it = (gxSapItem*)gxmalloc(sizeof(gxSapItem)); it->id = id; BYTE_BUFFER_INIT(&it->name); bb_set(&it->name, name->data, name->size); arr_push(&target->sapAssignmentList, it); } #endif //DLMS_IGNORE_MALLOC } else { ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; } return ret; } #endif //DLMS_IGNORE_SAP_ASSIGNMENT #ifndef DLMS_IGNORE_SECURITY_SETUP int invoke_SecuritySetup(dlmsServerSettings* settings, gxSecuritySetup* target, gxValueEventArg* e) { int ret = 0; #ifndef DLMS_IGNORE_HIGH_GMAC int pos; #endif //DLMS_IGNORE_HIGH_GMAC if (e->index == 1) { //The security policy can only be strengthened. if (target->securityPolicy > var_toInteger(&e->parameters)) { ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; } else { target->securityPolicy = var_toInteger(&e->parameters); } } else if (e->index == 2) { #ifdef DLMS_IGNORE_HIGH_GMAC ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; #else #ifdef DLMS_IGNORE_MALLOC if (e->parameters.vt != DLMS_DATA_TYPE_OCTET_STRING) { ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; } else { unsigned char TMP[24]; gxByteBuffer tmp; BB_ATTACH(tmp, TMP, 0); unsigned char BUFF[24]; gxByteBuffer bb; BB_ATTACH(bb, BUFF, 0); unsigned char type; uint16_t count = 10; if ((ret = cosem_checkArray(e->parameters.byteArr, &count)) == 0) { for (pos = 0; pos != count; ++pos) { if ((ret = cosem_checkStructure(e->parameters.byteArr, 2)) != 0 || (ret = cosem_getEnum(e->parameters.byteArr, &type)) != 0 || (ret = cosem_getOctetString(e->parameters.byteArr, &tmp)) != 0 || (ret = cip_decryptKey(settings->base.kek, sizeof(settings->base.kek), &tmp, &bb)) != 0) { break; } if (bb.size != 16) { e->error = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; break; } switch (type) { case DLMS_GLOBAL_KEY_TYPE_UNICAST_ENCRYPTION: memcpy(settings->base.cipher.blockCipherKey, BUFF, bb.size); break; case DLMS_GLOBAL_KEY_TYPE_BROADCAST_ENCRYPTION: //Invalid type ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; break; case DLMS_GLOBAL_KEY_TYPE_AUTHENTICATION: memcpy(settings->base.cipher.authenticationKey, BUFF, bb.size); break; case DLMS_GLOBAL_KEY_TYPE_KEK: memcpy(settings->base.kek, BUFF, bb.size); break; default: //Invalid type ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; break; } } } } #else dlmsVARIANT* it, * type, * data; if (e->parameters.vt != DLMS_DATA_TYPE_ARRAY) { ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; } else { gxByteBuffer bb; BYTE_BUFFER_INIT(&bb); for (pos = 0; pos != e->parameters.Arr->size; ++pos) { bb_clear(&bb); if ((ret = va_getByIndex(e->parameters.Arr, pos, &it)) != 0 || (ret = va_getByIndex(it->Arr, 0, &type)) != 0 || (ret = va_getByIndex(it->Arr, 1, &data)) != 0 || (ret = cip_decryptKey(settings->base.kek.data, (unsigned char)settings->base.kek.size, data->byteArr, &bb)) != 0) { break; } if (bb.size != 16) { e->error = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; break; } switch (type->cVal) { case DLMS_GLOBAL_KEY_TYPE_UNICAST_ENCRYPTION: bb_clear(&settings->base.cipher.blockCipherKey); bb_set(&settings->base.cipher.blockCipherKey, bb.data, bb.size); break; case DLMS_GLOBAL_KEY_TYPE_BROADCAST_ENCRYPTION: //Invalid type ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; break; case DLMS_GLOBAL_KEY_TYPE_AUTHENTICATION: bb_clear(&settings->base.cipher.authenticationKey); bb_set(&settings->base.cipher.authenticationKey, bb.data, bb.size); break; case DLMS_GLOBAL_KEY_TYPE_KEK: bb_clear(&settings->base.kek); bb_set(&settings->base.kek, bb.data, bb.size); break; default: //Invalid type ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; break; } } bb_clear(&bb); } #endif //DLMS_IGNORE_MALLOC #endif //DLMS_IGNORE_HIGH_GMAC } else { ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; } return ret; } #endif //DLMS_IGNORE_SECURITY_SETUP #ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME int invoke_AssociationShortName( dlmsServerSettings* settings, gxValueEventArg* e) { int ret; unsigned char equal; uint32_t ic = 0; #ifndef DLMS_IGNORE_HIGH_GMAC gxByteBuffer bb; #endif //DLMS_IGNORE_HIGH_GMAC gxByteBuffer* readSecret; // Check reply_to_HLS_authentication if (e->index == 8) { #ifndef DLMS_IGNORE_HIGH_GMAC if (settings->base.authentication == DLMS_AUTHENTICATION_HIGH_GMAC) { unsigned char ch; bb_attach(&bb, settings->base.sourceSystemTitle, sizeof(settings->base.sourceSystemTitle), sizeof(settings->base.sourceSystemTitle)); readSecret = &bb; if ((ret = bb_getUInt8(&settings->info.data, &ch)) != 0 || (ret = bb_getUInt32(&settings->info.data, &ic)) != 0) { bb_clear(&settings->info.data); return ret; } } else #endif //DLMS_IGNORE_HIGH_GMAC { readSecret = &((gxAssociationShortName*)e->target)->secret; } bb_clear(&settings->info.data); if ((ret = dlms_secure(&settings->base, ic, &settings->base.stoCChallenge, readSecret, &settings->info.data)) != 0) { bb_clear(&settings->info.data); return ret; } equal = bb_size(e->parameters.byteArr) != 0 && bb_compare(&settings->info.data, e->parameters.byteArr->data, e->parameters.byteArr->size); bb_clear(&settings->info.data); if (equal) { e->byteArray = 1; #ifndef DLMS_IGNORE_HIGH_GMAC if (settings->base.authentication == DLMS_AUTHENTICATION_HIGH_GMAC) { #ifdef DLMS_IGNORE_MALLOC bb_attach(&bb, settings->base.cipher.systemTitle, sizeof(settings->base.cipher.systemTitle), sizeof(settings->base.cipher.systemTitle)); readSecret = &bb; #else readSecret = &settings->base.cipher.systemTitle; #endif //DLMS_IGNORE_MALLOC ic = settings->base.cipher.invocationCounter; } #endif //DLMS_IGNORE_HIGH_GMAC if ((ret = dlms_secure(&settings->base, ic, &settings->base.ctoSChallenge, readSecret, &settings->info.data)) != 0) { return ret; } bb_insertUInt8(&settings->info.data, 0, DLMS_DATA_TYPE_OCTET_STRING); bb_insertUInt8(&settings->info.data, 1, (unsigned char)(settings->info.data.size - 1)); } else { return 0; } } else { return DLMS_ERROR_CODE_READ_WRITE_DENIED; } return 0; } #endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME #ifndef DLMS_IGNORE_SCRIPT_TABLE int invoke_ScriptTable( dlmsServerSettings* settings, gxValueEventArg* e) { gxScript* s; gxScriptAction* sa; gxValueEventArg* e1; int ret = 0, pos, pos2; unsigned char id = var_toInteger(&e->parameters); //Find index and execute it. if (e->index == 1) { gxValueEventCollection args; #ifdef DLMS_IGNORE_MALLOC gxValueEventArg tmp[1]; ve_init(&tmp[0]); vec_attach(&args, tmp, 1, 1); e1 = &tmp[0]; #else e1 = (gxValueEventArg*)gxmalloc(sizeof(gxValueEventArg)); ve_init(e1); vec_init(&args); vec_push(&args, e1); #endif //DLMS_IGNORE_MALLOC for (pos = 0; pos != ((gxScriptTable*)e->target)->scripts.size; ++pos) { #ifdef DLMS_IGNORE_MALLOC if ((ret = arr_getByIndex(&((gxScriptTable*)e->target)->scripts, pos, (void**)&s, sizeof(gxScript))) != 0) #else if ((ret = arr_getByIndex(&((gxScriptTable*)e->target)->scripts, pos, (void**)&s)) != 0) #endif //DLMS_IGNORE_MALLOC { break; } if (s->id == id) { for (pos2 = 0; pos2 != s->actions.size; ++pos2) { #ifdef DLMS_IGNORE_MALLOC if ((ret = arr_getByIndex(&s->actions, pos2, (void**)&sa, sizeof(gxScriptAction))) != 0) #else if ((ret = arr_getByIndex(&s->actions, pos2, (void**)&sa)) != 0) #endif //DLMS_IGNORE_MALLOC { break; } if (sa->type == DLMS_SCRIPT_ACTION_TYPE_WRITE) { e1->value = sa->parameter; } else { e1->parameters = sa->parameter; } e1->index = sa->index; #ifndef DLMS_IGNORE_OBJECT_POINTERS e1->target = sa->target; #else if ((ret = oa_findByLN(&settings->base.objects, sa->objectType, sa->logicalName, &e1->target)) != 0) { break; } if (e1->target == NULL) { ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; break; } #endif //DLMS_IGNORE_OBJECT_POINTERS if (sa->type == DLMS_SCRIPT_ACTION_TYPE_WRITE) { svr_preWrite(&settings->base, &args); if (e1->error != 0) { ret = e1->error; } else if (!e1->handled) { //Set action to true to indicate that this is called from the action method. e1->action = 1; if ((ret = cosem_setValue(&settings->base, e1)) != 0) { break; } svr_postWrite(&settings->base, &args); if (e1->error != 0) { ret = e1->error; } } } else if (sa->type == DLMS_SCRIPT_ACTION_TYPE_EXECUTE) { svr_preAction(&settings->base, &args); if (e1->error != 0) { ret = e1->error; } else if (!e1->handled) { if ((ret = cosem_invoke(settings, e1)) != 0) { break; } svr_postAction(&settings->base, &args); if (e1->error != 0) { ret = e1->error; } } } else { ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; } if (ret != 0) { break; } } } } vec_clear(&args); } else { ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; } var_clear(&e->value); return ret; } #endif //DLMS_IGNORE_SCRIPT_TABLE #ifndef DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL int invoke_zigbeeNetworkControl(gxZigBeeNetworkControl* object, unsigned char index, dlmsVARIANT* value) { int ret = 0, pos; #ifndef DLMS_IGNORE_MALLOC dlmsVARIANT* it; #endif //DLMS_IGNORE_MALLOC gxActiveDevice* ad; uint32_t v; //Register device. if (index == 1) { #ifdef DLMS_IGNORE_MALLOC if ((ret = arr_getByIndex(&object->activeDevices, object->activeDevices.size, (void**)&ad, sizeof(gxActiveDevice))) == 0) { ++object->activeDevices.size; BYTE_BUFFER_INIT(&ad->macAddress); if ((ret = cosem_getOctetString(value->byteArr, &ad->macAddress)) == 0 && (ret = cosem_getIntegerFromBitString(value->byteArr, &v)) == 0) { ad->status = (DLMS_ZIG_BEE_STATUS)v; } } #else if ((ret = va_getByIndex(value->Arr, 0, &it)) == 0) { ad = (gxActiveDevice*)gxcalloc(1, sizeof(gxActiveDevice)); BYTE_BUFFER_INIT(&ad->macAddress); if ((ret = bb_set(&ad->macAddress, it->byteArr->data, it->byteArr->size)) == 0 && (ret = cosem_getIntegerFromBitString(it->byteArr, &v)) == 0) { ad->status = (DLMS_ZIG_BEE_STATUS)v; arr_push(&object->activeDevices, ad); } else { gxfree(ad); } } #endif //DLMS_IGNORE_MALLOC } //Unregister device. else if (index == 2) { for (pos = 0; pos != object->activeDevices.size; ++pos) { #ifdef DLMS_IGNORE_MALLOC if ((ret = arr_getByIndex(&object->activeDevices, pos, (void**)&ad, sizeof(gxActiveDevice))) != 0) { break; } if (memcpy(&ad->macAddress, &value->byteArr, 8) == 0) { int pos2; gxActiveDevice* ad2; for (pos2 = pos + 1; pos2 < object->activeDevices.size; ++pos2) { if ((ret = arr_getByIndex(&object->activeDevices, pos2, (void**)&ad2, sizeof(gxActiveDevice))) != 0) { break; } memcpy(ad, ad2, sizeof(gxActiveDevice)); ad = ad2; } --object->activeDevices.size; break; } #else ret = arr_getByIndex(&object->activeDevices, pos, (void**)&ad); if (ret != 0) { return ret; } if (memcpy(&ad->macAddress, &value->byteArr, 8) == 0) { ret = arr_removeByIndex(&object->activeDevices, pos, (void**)&ad); if (ret != 0) { return ret; } gxfree(ad); break; } #endif //DLMS_IGNORE_MALLOC } } //Unregister all device. else if (index == 3) { ret = obj_clearActiveDevices(&object->activeDevices); } //backup PAN else if (index == 4) { } //Restore PAN, else if (index == 5) { // This method instructs the coordinator to restore a PAN using backup information. // The storage location of the back-up is not currently defined and is an internal function // of the DLMS/COSEM Server. } else { ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } return ret; } #endif //DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL #ifndef DLMS_IGNORE_EXTENDED_REGISTER int invoke_ExtendedRegister( dlmsServerSettings* settings, gxExtendedRegister* object, unsigned char index) { int ret = 0; //Reset. if (index == 1) { ret = var_clear(&object->value); if (ret != 0) { return ret; } if (settings->defaultClock != NULL) { object->captureTime = settings->defaultClock->time; } else { time_clear(&object->captureTime); } } else { ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } return ret; } #endif //DLMS_IGNORE_EXTENDED_REGISTER #ifndef DLMS_IGNORE_DEMAND_REGISTER int invoke_DemandRegister( dlmsServerSettings* settings, gxDemandRegister* object, unsigned char index) { int ret = 0; //Reset. if (index == 1) { if ((ret = var_clear(&object->currentAverageValue)) != 0 || (ret = var_clear(&object->lastAverageValue)) != 0) { return ret; } if (settings->defaultClock != NULL) { object->startTimeCurrent = object->captureTime = settings->defaultClock->time; } else { time_clear(&object->captureTime); time_clear(&object->startTimeCurrent); } } else if (index == 1) { if ((ret = var_copy(&object->lastAverageValue, &object->currentAverageValue)) != 0 || (ret = var_clear(&object->currentAverageValue)) != 0) { return ret; } if (settings->defaultClock != NULL) { object->startTimeCurrent = object->captureTime = settings->defaultClock->time; } else { time_clear(&object->captureTime); time_clear(&object->startTimeCurrent); } } else { ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } return ret; } #endif //DLMS_IGNORE_DEMAND_REGISTER #ifndef DLMS_IGNORE_CLOCK int invoke_Clock(gxClock* object, unsigned char index, dlmsVARIANT* value) { int ret = 0; #ifndef DLMS_IGNORE_MALLOC dlmsVARIANT* it; dlmsVARIANT tmp; #endif //DLMS_IGNORE_MALLOC // Resets the value to the default value. // The default value is an instance specific constant. if (index == 1) { #ifdef DLMS_USE_EPOCH_TIME int minutes = time_getMinutes(&object->time); #else int minutes = object->time.value.tm_min; #endif // DLMS_USE_EPOCH_TIME if (minutes < 8) { minutes = 0; } else if (minutes < 23) { minutes = 15; } else if (minutes < 38) { minutes = 30; } else if (minutes < 53) { minutes = 45; } else { minutes = 0; time_addHours(&object->time, 1); } #ifdef DLMS_USE_EPOCH_TIME time_addTime(&object->time, 0, -time_getMinutes(&object->time) + minutes, -time_getSeconds(&object->time)); #else time_addTime(&object->time, 0, -object->time.value.tm_min + minutes, -object->time.value.tm_sec); #endif // DLMS_USE_EPOCH_TIME } // Sets the meter's time to the nearest minute. else if (index == 3) { #ifdef DLMS_USE_EPOCH_TIME int s = time_getSeconds(&object->time); #else int s = object->time.value.tm_sec; #endif // DLMS_USE_EPOCH_TIME if (s > 30) { time_addTime(&object->time, 0, 1, 0); } time_addTime(&object->time, 0, 0, -s); } //Adjust to preset time. else if (index == 4) { object->time = object->presetTime; } // Presets the time to a new value (preset_time) and defines // avalidity_interval within which the new time can be activated. else if (index == 5) { #ifdef DLMS_IGNORE_MALLOC ret = cosem_getDateFromOctetString(value->byteArr, &object->presetTime); #else ret = var_init(&tmp); if (ret != 0) { return ret; } ret = va_getByIndex(value->Arr, 0, &it); if (ret != 0) { return ret; } ret = dlms_changeType2(it, DLMS_DATA_TYPE_DATETIME, &tmp); if (ret != 0) { return ret; } object->presetTime = *tmp.dateTime; #endif //DLMS_IGNORE_MALLOC } // Shifts the time. else if (index == 6) { time_addTime(&object->time, 0, 0, var_toInteger(value)); } else { ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } return ret; } #endif //DLMS_IGNORE_CLOCK #ifndef DLMS_IGNORE_REGISTER int invoke_Register( gxRegister* object, gxValueEventArg* e) { int ret = 0; //Reset. if (e->index == 1) { ret = var_clear(&object->value); } else { ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } return ret; } #endif //DLMS_IGNORE_REGISTER #ifndef DLMS_IGNORE_PROFILE_GENERIC /* * Copies the values of the objects to capture into the buffer by reading * capture objects. */ int capture(dlmsSettings* settings, gxProfileGeneric* object) { #ifdef DLMS_IGNORE_MALLOC gxValueEventArg e; gxValueEventCollection args; ve_init(&e); e.action = 1; e.target = &object->base; e.index = 2; gxValueEventArg p[1] = { e }; vec_attach(&args, p, 1, 1); svr_preGet(settings, &args); svr_postGet(settings, &args); vec_empty(&args); #else int ret, pos; gxKey* kv; dlmsVARIANT* value; variantArray* row; gxValueEventArg e; gxValueEventCollection args; ve_init(&e); e.action = 1; e.target = &object->base; e.index = 2; vec_init(&args); vec_push(&args, &e); svr_preGet(settings, &args); if (!e.handled) { gxValueEventArg e2; ve_init(&e2); row = (variantArray*)gxmalloc(sizeof(variantArray)); va_init(row); for (pos = 0; pos != object->captureObjects.size; ++pos) { ret = arr_getByIndex(&object->captureObjects, pos, (void**)&kv); if (ret != DLMS_ERROR_CODE_OK) { return ret; } e2.target = (gxObject*)kv->key; e2.index = ((gxTarget*)kv->value)->attributeIndex; if ((ret = cosem_getData(&e2)) != 0) { return ret; } value = (dlmsVARIANT*)gxmalloc(sizeof(dlmsVARIANT)); var_init(value); var_copy(value, &e.value); va_push(row, value); } // Remove first item if buffer is full. if (object->profileEntries == object->buffer.size) { variantArray* removedRow; arr_removeByIndex(&object->buffer, 0, (void**)&removedRow); va_clear(removedRow); } arr_push(&object->buffer, row); object->entriesInUse = object->buffer.size; } svr_postGet(settings, &args); vec_empty(&args); #endif //DLMS_IGNORE_MALLOC return 0; } int invoke_ProfileGeneric( dlmsServerSettings* settings, gxProfileGeneric* object, unsigned char index) { int ret = 0; //Reset. if (index == 1) { #ifndef DLMS_IGNORE_MALLOC ret = obj_clearProfileGenericBuffer(&object->buffer); #endif //DLMS_IGNORE_MALLOC } //Capture. else if (index == 2) { // Capture. ret = capture(&settings->base, object); } else { ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } return ret; } #endif //DLMS_IGNORE_PROFILE_GENERIC #ifndef DLMS_IGNORE_COMPACT_DATA int compactDataAppend(unsigned char byteArray, dlmsVARIANT* value3, gxByteBuffer* bb) { if (byteArray && value3->vt == DLMS_DATA_TYPE_OCTET_STRING) { if (bb_size(value3->byteArr) == 1) { bb_setUInt8(bb, 0); } else { bb_set(bb, value3->byteArr->data + 1, value3->byteArr->size - 1); } return 0; } int ret; uint16_t startPos = (uint16_t)bb->size; if ((ret = dlms_setData(bb, value3->vt, value3)) != 0) { return ret; } //If data is empty. if (bb->size - startPos == 1) { bb_setUInt8(bb, 0); } else { ret = bb_move(bb, startPos + 1, startPos, bb->size - startPos - 1); } return 0; } int compactDataAppendArray(dlmsVARIANT* value, gxByteBuffer* bb, uint16_t dataIndex) { int ret, pos; int cnt = value->Arr->size; if (dataIndex != 0) { cnt = dataIndex; --dataIndex; } dlmsVARIANT* value2; for (pos = dataIndex; pos != cnt; ++pos) { if ((ret = va_getByIndex(value->Arr, pos, &value2)) != 0) { return ret; } if (value2->vt == DLMS_DATA_TYPE_STRUCTURE) { dlmsVARIANT* value3; int pos1; for (pos1 = 0; pos1 != value2->Arr->size; ++pos1) { if ((ret = va_getByIndex(value2->Arr, pos1, &value3)) != 0 || (ret = compactDataAppend(0, value3, bb)) != 0) { return ret; } } } else { if ((ret = compactDataAppend(0, value2, bb)) != 0) { return ret; } } } return 0; } /* * Copies the values of the objects to capture into the buffer by reading * capture objects. */ int cosem_captureCompactData( dlmsSettings* settings, gxCompactData* object) { int ret = 0; uint16_t pos; #ifdef DLMS_IGNORE_MALLOC gxTarget* kv; #else gxKey* kv; #endif //DLMS_IGNORE_MALLOC gxValueEventArg e; gxValueEventCollection args; bb_clear(&object->buffer); ve_init(&e); e.action = 1; e.target = &object->base; e.index = 2; #ifdef DLMS_IGNORE_MALLOC //Allocate space where captured values are saved before they are added to the buffer. // We can't use server buffer because there might be transaction on progress when this is called. unsigned char tmp[MAX_CAPTURE_OBJECT_BUFFER_SIZE]; gxByteBuffer bb; bb_attach(&bb, tmp, 0, sizeof(tmp)); gxValueEventArg p[1] = { e }; vec_attach(&args, p, 1, 1); #else vec_init(&args); vec_push(&args, &e); #endif //DLMS_IGNORE_MALLOC svr_preGet(settings, &args); if (!e.handled) { uint16_t dataIndex; for (pos = 0; pos != object->captureObjects.size; ++pos) { #ifdef DLMS_IGNORE_MALLOC ret = arr_getByIndex(&object->captureObjects, pos, (void**)&kv, sizeof(gxTarget)); #else ret = arr_getByIndex(&object->captureObjects, pos, (void**)&kv); #endif //DLMS_IGNORE_MALLOC if (ret != DLMS_ERROR_CODE_OK) { bb_clear(&object->buffer); break; } #ifdef DLMS_IGNORE_MALLOC e.value.byteArr = &bb; e.value.vt = DLMS_DATA_TYPE_OCTET_STRING; e.target = kv->target; e.index = kv->attributeIndex; dataIndex = kv->dataIndex; #else e.target = (gxObject*)kv->key; e.index = ((gxTarget*)kv->value)->attributeIndex; dataIndex = ((gxTarget*)kv->value)->dataIndex; #endif //DLMS_IGNORE_MALLOC if ((ret = cosem_getValue(settings, &e)) != 0) { bb_clear(&object->buffer); break; } if (e.byteArray && e.value.vt == DLMS_DATA_TYPE_OCTET_STRING) { gxDataInfo info; dlmsVARIANT value; di_init(&info); var_init(&value); if ((ret = dlms_getData(e.value.byteArr, &info, &value)) != 0) { var_clear(&value); break; } if (value.vt == DLMS_DATA_TYPE_STRUCTURE || value.vt == DLMS_DATA_TYPE_ARRAY) { #ifdef DLMS_ITALIAN_STANDARD //Some meters require that there is a array count in data. if (value.vt == DLMS_DATA_TYPE_ARRAY && object->appendAA) { bb_setUInt8(&object->buffer, (unsigned char)value.Arr->size); } #endif //DLMS_ITALIAN_STANDARD if ((ret = compactDataAppendArray(&value, &object->buffer, dataIndex)) != 0) { var_clear(&value); break; } } else { if ((ret = compactDataAppend(1, &e.value, &object->buffer)) != 0) { var_clear(&value); break; } } var_clear(&value); } else if ((ret = compactDataAppend(0, &e.value, &object->buffer)) != 0) { break; } ve_clear(&e); } } svr_postGet(settings, &args); if (ret != 0) { bb_clear(&object->buffer); } vec_empty(&args); return ret; } int invoke_CompactData( dlmsServerSettings* settings, gxCompactData* object, unsigned char index) { int ret = 0; //Reset. if (index == 1) { ret = bb_clear(&object->buffer); } //Capture. else if (index == 2) { // Capture. ret = cosem_captureCompactData(&settings->base, object); } else { ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } return ret; } #endif //DLMS_IGNORE_COMPACT_DATA #ifndef DLMS_IGNORE_DISCONNECT_CONTROL int invoke_DisconnectControl( dlmsServerSettings* settings, gxDisconnectControl* object, unsigned char index) { int ret = 0; //Reset. if (index == 1) { object->controlState = DLMS_CONTROL_STATE_DISCONNECTED; object->outputState = 0; } //Capture. else if (index == 2) { object->controlState = DLMS_CONTROL_STATE_CONNECTED; object->outputState = 1; } else { ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } return ret; } #endif //DLMS_IGNORE_DISCONNECT_CONTROL #ifndef DLMS_IGNORE_LLC_SSCS_SETUP int invoke_LlcSscsSetup( gxLlcSscsSetup* object, unsigned char index) { int ret = 0; //Reset. if (index == 1) { object->serviceNodeAddress = 0xFFE; object->baseNodeAddress = 0; } else { ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } return ret; } #endif //DLMS_IGNORE_LLC_SSCS_SETUP #ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS int invoke_PrimeNbOfdmPlcPhysicalLayerCounters( gxPrimeNbOfdmPlcPhysicalLayerCounters* object, unsigned char index) { int ret = 0; //Reset. if (index == 1) { object->crcIncorrectCount = object->crcFailedCount = object->txDropCount = object->rxDropCount = 0; } else { ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } return ret; } #endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS #ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS int invoke_PrimeNbOfdmPlcMacCounters( gxPrimeNbOfdmPlcMacCounters* object, unsigned char index) { int ret = 0; //Reset. if (index == 1) { object->txDataPktCount = object->rxDataPktCount = object->txCtrlPktCount = object->rxCtrlPktCount = object->csmaFailCount = object->csmaChBusyCount = 0; } else { ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } return ret; } #endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS #ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA int invoke_PrimeNbOfdmPlcMacNetworkAdministrationData( gxPrimeNbOfdmPlcMacNetworkAdministrationData* object, unsigned char index) { int ret = 0; //Reset. if (index == 1) { arr_clear(&object->multicastEntries); arr_empty(&object->switchTable); arr_clear(&object->directTable); obj_clearAvailableSwitches(&object->availableSwitches); arr_clear(&object->communications); } else { ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } return ret; } #endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA #ifndef DLMS_IGNORE_SPECIAL_DAYS_TABLE int invoke_SpecialDaysTable( gxSpecialDaysTable* object, gxValueEventArg* e) { int ret = 0; uint16_t pos, index; gxSpecialDay* specialDay; //Insert. if (e->index == 1) { unsigned char append = 1; #ifdef DLMS_IGNORE_MALLOC if ((ret = cosem_checkStructure(e->parameters.byteArr, 3)) == 0 && (ret = cosem_getUInt16(e->parameters.byteArr, &index)) == 0) { for (pos = 0; pos != object->entries.size; ++pos) { if ((ret = arr_getByIndex(&object->entries, object->entries.size - 1, (void**)&specialDay, sizeof(gxSpecialDay))) != 0) { break; } //Overwrite existing item. if (specialDay->index == index) { if ((ret = cosem_getDateFromOctetString(e->parameters.byteArr, &specialDay->date)) != 0 || (ret = cosem_getUInt8(e->parameters.byteArr, &specialDay->dayId)) != 0) { } append = 0; break; } } if (ret == 0 && append) { ++object->entries.size; if ((ret = arr_getByIndex(&object->entries, object->entries.size - 1, (void**)&specialDay, sizeof(gxSpecialDay))) != 0) { --object->entries.size; } else { specialDay->index = index; if ((ret = cosem_getDateFromOctetString(e->parameters.byteArr, &specialDay->date)) != 0 || (ret = cosem_getUInt8(e->parameters.byteArr, &specialDay->dayId)) != 0) { } } } } #else dlmsVARIANT* tmp3; dlmsVARIANT tmp2; if (e->parameters.Arr != NULL) { ret = va_getByIndex(e->parameters.Arr, 0, &tmp3); if (ret != DLMS_ERROR_CODE_OK) { return ret; } index = (uint16_t)var_toInteger(tmp3); for (pos = 0; pos != object->entries.size; ++pos) { if ((ret = arr_getByIndex(&object->entries, object->entries.size - 1, (void**)&specialDay)) != 0) { break; } //Overwrite existing item. if (specialDay->index == index) { append = 0; break; } } if (append) { specialDay = (gxSpecialDay*)gxmalloc(sizeof(gxSpecialDay)); if (specialDay == NULL) { return DLMS_ERROR_CODE_OUTOFMEMORY; } arr_push(&object->entries, specialDay); } specialDay->index = index; ret = va_getByIndex(e->parameters.Arr, 1, &tmp3); if (ret != DLMS_ERROR_CODE_OK) { return ret; } var_init(&tmp2); ret = dlms_changeType2(tmp3, DLMS_DATA_TYPE_DATE, &tmp2); if (ret != DLMS_ERROR_CODE_OK) { return ret; } time_copy(&specialDay->date, tmp2.dateTime); var_clear(&tmp2); ret = va_getByIndex(e->parameters.Arr, 2, &tmp3); if (ret != DLMS_ERROR_CODE_OK) { return ret; } specialDay->dayId = (unsigned char)var_toInteger(tmp3); } #endif //DLMS_IGNORE_MALLOC } //Remove. else if (e->index == 2) { uint16_t pos, index = e->parameters.uiVal; for (pos = 0; pos != object->entries.size; ++pos) { #ifdef DLMS_IGNORE_MALLOC if ((ret = arr_getByIndex(&object->entries, pos, (void**)&specialDay, sizeof(gxSpecialDay))) != 0) #else if ((ret = arr_getByIndex(&object->entries, pos, (void**)&specialDay)) != 0) #endif //DLMS_IGNORE_MALLOC { break; } if (specialDay->index == index) { //Remove item. #ifdef DLMS_IGNORE_MALLOC ret = arr_removeByIndex(&object->entries, pos, sizeof(gxSpecialDay)); #else ret = arr_removeByIndex(&object->entries, pos, NULL); #endif //DLMS_IGNORE_MALLOC break; } } } else { ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } return ret; } #endif //DLMS_IGNORE_SPECIAL_DAYS_TABLE #ifndef DLMS_IGNORE_REGISTER_ACTIVATION int invoke_RegisterActivation( dlmsServerSettings* settings, gxRegisterActivation* object, gxValueEventArg* e) { int ret = 0; uint16_t count; gxRegisterActivationMask* k; uint16_t pos; #ifdef DLMS_IGNORE_OBJECT_POINTERS gxObjectDefinition* it; #else gxObject* it; #endif //DLMS_IGNORE_OBJECT_POINTERS //Add Register. if (e->index == 1) { #ifdef DLMS_IGNORE_MALLOC uint16_t ot; unsigned char ln[6]; #if !(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_MALLOC)) uint16_t count = oa_getCapacity(&object->registerAssignment); #else count = arr_getCapacity(&object->registerAssignment); if (!(object->registerAssignment.size < count)) { return DLMS_ERROR_CODE_OUTOFMEMORY; } #endif //!(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_MALLOC)) if ((ret = cosem_checkStructure(e->parameters.byteArr, 2)) != 0 || #ifndef DLMS_IGNORE_OBJECT_POINTERS (ret = cosem_getUInt16(e->parameters.byteArr, &ot)) != 0 || (ret = cosem_getOctetString2(e->parameters.byteArr, ln, 6, NULL)) != 0) { return ret; } if ((ret = oa_findByLN(&settings->base.objects, (DLMS_OBJECT_TYPE)ot, ln, &it)) != 0) { return ret; } if (it == NULL) { return DLMS_ERROR_CODE_OUTOFMEMORY; } if ((ret = arr_setByIndexRef(&object->registerAssignment, (void**)it)) != 0) { return ret; } #endif //DLMS_IGNORE_OBJECT_POINTERS #else dlmsVARIANT* tmp, * tmp3; if (e->parameters.Arr != NULL) { short type; ret = va_getByIndex(e->parameters.Arr, 0, &tmp); if (ret != DLMS_ERROR_CODE_OK) { return ret; } ret = va_getByIndex(tmp->Arr, 0, &tmp3); if (ret != DLMS_ERROR_CODE_OK) { return ret; } type = var_toInteger(tmp3); ret = va_getByIndex(tmp->Arr, 1, &tmp3); if (ret != DLMS_ERROR_CODE_OK) { return ret; } const unsigned char* ln = tmp3->byteArr->data; #ifdef DLMS_IGNORE_OBJECT_POINTERS it = (gxObjectDefinition*)gxmalloc(sizeof(gxObjectDefinition)); it->objectType = (DLMS_OBJECT_TYPE)type; memcpy(it->logicalName, ln, 6); #else if ((ret = oa_findByLN(&settings->base.objects, type, ln, &it)) != 0) { return ret; } if (it == NULL) { return DLMS_ERROR_CODE_OUTOFMEMORY; } #endif //DLMS_IGNORE_OBJECT_POINTERS #if !defined(DLMS_IGNORE_OBJECT_POINTERS) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) oa_push(&object->registerAssignment, it); #else arr_push(&object->registerAssignment, it); #endif //DLMS_IGNORE_OBJECT_POINTERS } #ifdef DLMS_IGNORE_OBJECT_POINTERS if (ret != 0 && objectDefinition != NULL) { gxfree(objectDefinition); } #endif //DLMS_IGNORE_OBJECT_POINTERS #endif //DLMS_IGNORE_MALLOC } else if (e->index == 2) { count = arr_getCapacity(&object->maskList); if (!(object->registerAssignment.size < count)) { return DLMS_ERROR_CODE_OUTOFMEMORY; } ++object->maskList.size; #ifdef DLMS_IGNORE_MALLOC uint16_t size; if ((ret = cosem_checkStructure(e->parameters.byteArr, 2)) == 0 && (ret = arr_getByIndex(&object->maskList, object->maskList.size - 1, (void**)&k, sizeof(gxRegisterActivationMask))) == 0 && (ret = cosem_getOctetString2(e->parameters.byteArr, k->name, sizeof(k->name), &size)) == 0) { k->length = (unsigned char)size; size = sizeof(k->indexes); if ((ret = cosem_checkArray(e->parameters.byteArr, &size)) == 0) { k->count = (unsigned char)size; for (pos = 0; pos != k->count; ++pos) { if ((ret = cosem_getUInt8(e->parameters.byteArr, &k->indexes[pos])) != 0) { break; } } } } #else #endif //DLMS_IGNORE_OBJECT_POINTERS } //Remove mask. else if (e->index == 3) { unsigned char ch; if ((ret = bb_getUInt8(e->parameters.byteArr, &ch)) == 0) { if (ch != DLMS_DATA_TYPE_OCTET_STRING) { ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } else { uint16_t count; if ((ret = hlp_getObjectCount2(e->parameters.byteArr, &count)) == 0) { for (pos = 0; pos != object->maskList.size; ++pos) { if ((ret = arr_getByIndex2(&object->maskList, pos, (void**)&k, sizeof(gxRegisterActivationMask))) != 0) { break; } #if defined(DLMS_IGNORE_MALLOC) if (bb_available(e->parameters.byteArr) == k->length && memcmp(k->name, e->parameters.byteArr->data + e->parameters.byteArr->position, count) == 0) { //arr_removeByIndex is decreasing amount already. ret = arr_removeByIndex(&object->maskList, pos, sizeof(gxRegisterActivationMask)); break; } #else if (bb_available(e->parameters.byteArr) == k->name.size && memcmp(k->name.data, e->parameters.byteArr->data + e->parameters.byteArr->position, count) == 0) { //arr_removeByIndex is decreasing amount already. if ((ret = arr_removeByIndex(&object->maskList, pos, (void**)&k)) == 0) { bb_clear(&k->name); bb_clear(&k->indexes); gxfree(k); } break; } #endif //defined(DLMS_IGNORE_MALLOC) e->parameters.byteArr->position += count; } } } } bb_clear(e->parameters.byteArr); } else { ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } return ret; } #endif //DLMS_IGNORE_REGISTER_ACTIVATION #ifndef DLMS_IGNORE_ACTIVITY_CALENDAR int invoke_copySeasonProfile(gxArray* target, gxArray* source) { int ret = obj_clearSeasonProfile(target); if (ret == 0) { int pos; gxSeasonProfile* sp, * it; #if defined(DLMS_IGNORE_MALLOC) target->size = source->size; #endif // for (pos = 0; pos != source->size; ++pos) { if (ret == 0) { if ((ret = arr_getByIndex2(source, pos, (void**)&sp, sizeof(gxSeasonProfile))) != 0) { break; } #if defined(DLMS_IGNORE_MALLOC) if ((ret = arr_getByIndex2(target, pos, (void**)&it, sizeof(gxSeasonProfile))) != 0) { break; } memcpy(&it->name, &sp->name, sizeof(gxSeasonProfileName)); it->start = sp->start; memcpy(&it->weekName, &sp->weekName, sizeof(gxSeasonProfileWeekName)); #else it = gxmalloc(sizeof(gxSeasonProfile)); arr_push(target, it); BYTE_BUFFER_INIT(&it->name); BYTE_BUFFER_INIT(&it->weekName); bb_set(&it->name, sp->name.data, sp->name.size); it->start = sp->start; bb_set(&it->weekName, sp->weekName.data, sp->weekName.size); #endif //#if defined(DLMS_IGNORE_MALLOC) } } } return ret; } int invoke_copyWeekProfileTable(gxArray* target, gxArray* source) { int ret = obj_clearWeekProfileTable(target); if (ret == 0) { int pos; gxWeekProfile* wp, * it; #if defined(DLMS_IGNORE_MALLOC) target->size = source->size; #endif // for (pos = 0; pos != source->size; ++pos) { if (ret == 0) { if ((ret = arr_getByIndex2(source, pos, (void**)&wp, sizeof(gxWeekProfile))) != 0) { break; } #if defined(DLMS_IGNORE_MALLOC) if ((ret = arr_getByIndex2(target, pos, (void**)&it, sizeof(gxWeekProfile))) != 0) { break; } memcpy(&it->name, &wp->name, sizeof(gxWeekProfileName)); #else it = gxmalloc(sizeof(gxWeekProfile)); arr_push(target, it); BYTE_BUFFER_INIT(&it->name); bb_set(&it->name, wp->name.data, wp->name.size); #endif //#if defined(DLMS_IGNORE_MALLOC) it->monday = wp->monday; it->tuesday = wp->tuesday; it->wednesday = wp->wednesday; it->thursday = wp->thursday; it->friday = wp->friday; it->saturday = wp->saturday; it->sunday = wp->sunday; } } } return ret; } int invoke_copyDayProfileTable(gxArray* target, gxArray* source) { int ret = obj_clearDayProfileTable(target); if (ret == 0) { int pos, pos2; gxDayProfile* it, * it2; gxDayProfileAction* dp, * dp2; #if defined(DLMS_IGNORE_MALLOC) target->size = source->size; #endif // for (pos = 0; pos != source->size; ++pos) { if (ret == 0) { if ((ret = arr_getByIndex2(source, pos, (void**)&it, sizeof(gxDayProfile))) != 0) { break; } #if defined(DLMS_IGNORE_MALLOC) if ((ret = arr_getByIndex2(target, pos, (void**)&it2, sizeof(gxDayProfile))) != 0) { break; } it2->daySchedules.size = it->daySchedules.size; #else it2 = gxmalloc(sizeof(gxDayProfile)); arr_push(target, it); #endif //#if defined(DLMS_IGNORE_MALLOC) it2->dayId = it->dayId; for (pos2 = 0; pos2 != it->daySchedules.size; ++pos2) { if ((ret = arr_getByIndex2(&it->daySchedules, pos2, (void**)&dp, sizeof(gxDayProfileAction))) != DLMS_ERROR_CODE_OK) { break; } #if defined(DLMS_IGNORE_MALLOC) if ((ret = arr_getByIndex2(&it2->daySchedules, pos2, (void**)&dp2, sizeof(gxDayProfileAction))) != DLMS_ERROR_CODE_OK) { break; } #else dp2 = gxmalloc(sizeof(gxDayProfileAction)); arr_push(&it2->daySchedules, dp2); #endif //#if defined(DLMS_IGNORE_MALLOC) dp2->startTime = dp->startTime; #ifndef DLMS_IGNORE_OBJECT_POINTERS dp2->script = dp->script; #else memcpy(dp2->scriptLogicalName, dp->scriptLogicalName, 6); #endif //DLMS_IGNORE_OBJECT_POINTERS dp2->scriptSelector = dp->scriptSelector; } } } } return ret; } int invoke_ActivityCalendar(gxValueEventArg* e) { int ret; if (e->index == 1) { //Copy all passive items to active. gxActivityCalendar* object = (gxActivityCalendar*)e->target; bb_clear(&object->calendarNameActive); if ((ret = bb_set(&object->calendarNameActive, object->calendarNamePassive.data, object->calendarNamePassive.size)) != 0 || (ret = invoke_copyDayProfileTable(&object->dayProfileTableActive, &object->dayProfileTablePassive)) != 0 || (ret = invoke_copyWeekProfileTable(&object->weekProfileTableActive, &object->weekProfileTablePassive)) != 0 || (ret = invoke_copySeasonProfile(&object->seasonProfileActive, &object->seasonProfilePassive)) != 0) { } } else { ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } return ret; } #endif //DLMS_IGNORE_ACTIVITY_CALENDAR #ifndef DLMS_IGNORE_ARRAY_MANAGER int invoke_ArrayManagerInsertEntry( dlmsServerSettings* settings, gxValueEventArg* e, uint16_t index) { int ret; uint16_t count, pos, totalCount; uint16_t origPos = 0; unsigned char ch; dlmsVARIANT value; gxDataInfo info; di_init(&info); var_init(&value); //Move new data to the begin of the buffer. ret = bb_move(e->value.byteArr, e->value.byteArr->position, 0, bb_available(e->value.byteArr)); uint16_t newDataSize = (uint16_t)e->value.byteArr->size; if ((ret = cosem_getValue(&settings->base, e)) == 0 && bb_size(e->value.byteArr) != 0) { if ((ret = bb_getUInt8(e->value.byteArr, &ch)) != 0 || ch != DLMS_DATA_TYPE_ARRAY) { return DLMS_ERROR_CODE_INVALID_PARAMETER; } if ((ret = hlp_getObjectCount2(e->value.byteArr, &totalCount)) != 0) { return ret; } //Change index to zero-based. count = (uint16_t)e->value.byteArr->size; e->value.byteArr->size = newDataSize + 1; if ((ret = hlp_setObjectCount(1 + totalCount, e->value.byteArr)) != 0) { return ret; } totalCount = 0; //Return original size. e->value.byteArr->size = count; for (pos = (uint16_t)e->value.byteArr->position; pos != bb_size(e->value.byteArr); ++pos) { //Get data type. if ((ret = bb_getUInt8ByIndex(e->value.byteArr, e->value.byteArr->position, &ch)) != 0) { break; } if (ch == DLMS_DATA_TYPE_ARRAY || ch == DLMS_DATA_TYPE_STRUCTURE) { if (index == 0) { //Save start position. origPos = (uint16_t)e->value.byteArr->position; } ++e->value.byteArr->position; if ((ret = hlp_getObjectCount2(e->value.byteArr, &count)) != 0) { break; } totalCount += 1 + count; } else { if ((ret = dlms_getData(e->value.byteArr, &info, &value)) != 0) { var_clear(&value); break; } #ifdef DLMS_IGNORE_MALLOC if (value.vt == DLMS_DATA_TYPE_OCTET_STRING) { ++e->value.byteArr->position; if ((ret = hlp_getObjectCount2(e->value.byteArr, &count)) != 0) { var_clear(&value); break; } if (e->value.byteArr->size < e->value.byteArr->position + count) { ret = DLMS_ERROR_CODE_OUTOFMEMORY; var_clear(&value); break; } e->value.byteArr->position += count; } #endif //DLMS_IGNORE_MALLOC di_init(&info); var_clear(&value); } --totalCount; if (index == 0 && totalCount == 0) { if (bb_available(e->value.byteArr) == 0) { //Move first item to last. ret = bb_move(e->value.byteArr, 0, e->value.byteArr->size, newDataSize); //Move all items to begin. ret = bb_move(e->value.byteArr, newDataSize, 0, e->value.byteArr->size - newDataSize); e->value.byteArr->position = 0; ret = cosem_setValue(&settings->base, e); bb_clear(e->value.byteArr); break; } else if (index == 0) { //Make space for the new item. ret = bb_move(e->value.byteArr, origPos, origPos + newDataSize, e->value.byteArr->size - newDataSize); //Move new item to new location. totalCount = (uint16_t)e->value.byteArr->size; ret = bb_move(e->value.byteArr, 0, origPos, newDataSize); e->value.byteArr->size = totalCount; //Move all items to first. ret = bb_move(e->value.byteArr, newDataSize, 0, e->value.byteArr->size - newDataSize); e->value.byteArr->position = 0; #ifdef DLMS_IGNORE_MALLOC ret = cosem_setValue(&settings->base, e); bb_clear(e->value.byteArr); #else gxByteBuffer* bb = e->value.byteArr; e->value.vt = DLMS_DATA_TYPE_NONE; if ((ret = dlms_getData(e->value.byteArr, &info, &e->value))) { bb_clear(bb); var_clear(&value); break; } bb_clear(bb); if ((ret = cosem_setValue(&settings->base, e)) != 0) { var_clear(&value); break; } #endif //DLMS_IGNORE_MALLOC break; } --index; } } } return ret; } int invoke_ArrayManagerDeleteEntry( dlmsServerSettings* settings, gxValueEventArg* e, uint16_t from, uint16_t to) { int ret; uint16_t count, pos, totalCount; uint16_t origPos = 0; unsigned char ch; dlmsVARIANT value; gxDataInfo info; di_init(&info); var_init(&value); if ((ret = cosem_getValue(&settings->base, e)) == 0 && bb_size(e->value.byteArr) != 0) { if ((ret = bb_getUInt8(e->value.byteArr, &ch)) != 0 || ch != DLMS_DATA_TYPE_ARRAY) { return DLMS_ERROR_CODE_INVALID_PARAMETER; } if ((ret = hlp_getObjectCount2(e->value.byteArr, &totalCount)) != 0) { return ret; } //Change from to zero-based. --from; if (to - from < totalCount) { totalCount -= to - from; } else { totalCount = from; to = from + 1; } count = (uint16_t)e->value.byteArr->size; e->value.byteArr->size = 1; if ((ret = hlp_setObjectCount(totalCount, e->value.byteArr)) != 0) { return ret; } totalCount = 0; //Return original size. e->value.byteArr->size = count; for (pos = (uint16_t)e->value.byteArr->position; pos != bb_size(e->value.byteArr); ++pos) { //Get data type. if ((ret = bb_getUInt8ByIndex(e->value.byteArr, e->value.byteArr->position, &ch)) != 0) { break; } if (ch == DLMS_DATA_TYPE_ARRAY || ch == DLMS_DATA_TYPE_STRUCTURE) { if (from == 0) { //Save start position. origPos = (uint16_t)e->value.byteArr->position; } ++e->value.byteArr->position; if ((ret = hlp_getObjectCount2(e->value.byteArr, &count)) != 0) { break; } totalCount += 1 + count; } else { if ((ret = dlms_getData(e->value.byteArr, &info, &value)) != 0) { var_clear(&value); break; } #ifdef DLMS_IGNORE_MALLOC if (value.vt == DLMS_DATA_TYPE_OCTET_STRING) { ++e->value.byteArr->position; if ((ret = hlp_getObjectCount2(e->value.byteArr, &count)) != 0) { break; } if (e->value.byteArr->size < e->value.byteArr->position + count) { ret = DLMS_ERROR_CODE_OUTOFMEMORY; break; } e->value.byteArr->position += count; } #endif //DLMS_IGNORE_MALLOC di_init(&info); var_clear(&value); } --totalCount; if (totalCount == 0) { --to; if (to == 0) { ret = bb_move(e->value.byteArr, e->value.byteArr->position, origPos, bb_available(e->value.byteArr)); e->value.byteArr->position = 0; ret = cosem_setValue(&settings->base, e); bb_clear(e->value.byteArr); break; } --from; } } } return ret; } int invoke_ArrayManager( dlmsServerSettings* settings, gxValueEventArg* e) { int pos, ret = 0; gxArrayManagerItem* it; gxArrayManager* object = (gxArrayManager*)e->target; unsigned char ch, found = 0; uint16_t count, totalCount; dlmsVARIANT tmp; dlmsVARIANT value; gxDataInfo info; #ifndef DLMS_IGNORE_MALLOC dlmsVARIANT* tmp2, * tmp3; e->value.byteArr = &settings->info.data; #endif//DLMS_IGNORE_MALLOC e->byteArray = 1; unsigned char id; uint16_t index = 0, from = 0, to = 0, origSize, origPos = 0; if (e->index == 1) { id = e->parameters.bVal; bb_clear(e->value.byteArr); } else if (e->index == 3 || e->index == 4) { //Insert or update entry. #ifdef DLMS_IGNORE_MALLOC if ((ret = cosem_getStructure(e->parameters.byteArr, &count)) != 0 || (ret = cosem_getUInt8(e->parameters.byteArr, &id)) != 0 || (ret = cosem_getStructure(e->parameters.byteArr, &count)) != 0 || (ret = cosem_getUInt16(e->parameters.byteArr, &index)) != 0) { return ret; } #else if ((ret = va_getByIndex(e->parameters.Arr, 0, &tmp2)) != 0) { return ret; } id = tmp2->bVal; if ((ret = va_getByIndex(e->parameters.Arr, 1, &tmp3)) != 0) { return ret; } if ((ret = va_getByIndex(tmp3->Arr, 0, &tmp2)) != 0) { return ret; } from = tmp2->uiVal; if ((ret = va_getByIndex(tmp3->Arr, 1, &tmp2)) != 0) { return ret; } to = tmp2->uiVal; #endif //DLMS_IGNORE_MALLOC } else { #ifdef DLMS_IGNORE_MALLOC if ((ret = cosem_getStructure(e->parameters.byteArr, &count)) != 0 || (ret = cosem_getUInt8(e->parameters.byteArr, &id)) != 0 || (ret = cosem_getStructure(e->parameters.byteArr, &count)) != 0 || (ret = cosem_getUInt16(e->parameters.byteArr, &from)) != 0 || (ret = cosem_getUInt16(e->parameters.byteArr, &to)) != 0) { return ret; } #else if ((ret = va_getByIndex(e->parameters.Arr, 0, &tmp2)) != 0) { return ret; } id = tmp2->bVal; if ((ret = va_getByIndex(e->parameters.Arr, 1, &tmp3)) != 0) { return ret; } if ((ret = va_getByIndex(tmp3->Arr, 0, &tmp2)) != 0) { return ret; } from = tmp2->uiVal; if ((ret = va_getByIndex(tmp3->Arr, 1, &tmp2)) != 0) { return ret; } to = tmp2->uiVal; #endif //DLMS_IGNORE_MALLOC bb_clear(e->value.byteArr); } for (pos = 0; pos != object->elements.size; ++pos) { #ifdef DLMS_IGNORE_MALLOC ret = arr_getByIndex(&object->elements, pos, (void**)&it, sizeof(gxArrayManagerItem)); #else ret = arr_getByIndex(&object->elements, pos, (void**)&it); #endif //DLMS_IGNORE_MALLOC if (ret != 0) { break; } if (it->id == id) { if (e->index == 1) { //Number Of Entries. if (it->element.target->objectType == DLMS_OBJECT_TYPE_PROFILE_GENERIC && it->element.attributeIndex == 2) { //Entries in use is returned when buffer size is asked. GX_UINT32(tmp) = ((gxProfileGeneric*)it->element.target)->entriesInUse; } else { e->index = it->element.attributeIndex; e->target = it->element.target; if ((ret = cosem_getValue(&settings->base, e)) != 0 || (ret = bb_getUInt8(e->value.byteArr, &ch)) != 0) { break; } if (ch != DLMS_DATA_TYPE_ARRAY) { ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; break; } if (hlp_getObjectCount2(e->value.byteArr, &count) != 0) { break; } if (count < 0x100) { GX_UINT8(tmp) = (unsigned char)count; } else { GX_UINT16(tmp) = count; } } bb_clear(e->value.byteArr); if ((ret = dlms_setData(e->value.byteArr, tmp.vt, &tmp)) != 0) { break; } found = 1; break; } else if (e->index == 2) { //Retrieve entries. if (it->element.target->objectType == DLMS_OBJECT_TYPE_PROFILE_GENERIC) { } if (!found) { di_init(&info); var_init(&value); e->index = it->element.attributeIndex; e->target = it->element.target; if ((ret = cosem_getValue(&settings->base, e)) == 0 && bb_size(e->value.byteArr) != 0) { if ((ret = bb_getUInt8(e->value.byteArr, &ch)) != 0 || ch != DLMS_DATA_TYPE_ARRAY) { break; } if ((ret = hlp_getObjectCount2(e->value.byteArr, &totalCount)) != 0) { break; } //Change from to zero-based. --from; if (to - from < totalCount) { totalCount = to - from; } else if (totalCount < to) { if (totalCount == 0) { to = 1; } else { to = totalCount; } } count = (uint16_t)e->value.byteArr->size; e->value.byteArr->size = 1; if ((ret = hlp_setObjectCount(totalCount, e->value.byteArr)) != 0) { break; } totalCount = 0; origSize = (uint16_t)e->value.byteArr->size; //Return original size. e->value.byteArr->size = count; for (pos = e->value.byteArr->position; pos != bb_size(e->value.byteArr); ++pos) { //Get data type. if ((ret = bb_getUInt8ByIndex(e->value.byteArr, e->value.byteArr->position, &ch)) != 0) { break; } if (ch == DLMS_DATA_TYPE_ARRAY || ch == DLMS_DATA_TYPE_STRUCTURE) { if (from == 0) { //Save start position. origPos = (uint16_t)e->value.byteArr->position; } ++e->value.byteArr->position; if ((ret = hlp_getObjectCount2(e->value.byteArr, &count)) != 0) { break; } totalCount += 1 + count; } else { if ((ret = dlms_getData(e->value.byteArr, &info, &value)) != 0) { var_clear(&value); break; } #ifdef DLMS_IGNORE_MALLOC if (value.vt == DLMS_DATA_TYPE_OCTET_STRING) { ++e->value.byteArr->position; if ((ret = hlp_getObjectCount2(e->value.byteArr, &count)) != 0) { break; } if (e->value.byteArr->size < e->value.byteArr->position + count) { ret = DLMS_ERROR_CODE_OUTOFMEMORY; break; } e->value.byteArr->position += count; } #endif //DLMS_IGNORE_MALLOC di_init(&info); var_clear(&value); } --totalCount; if (totalCount == 0) { --to; if (to == 0) { ret = bb_move(e->value.byteArr, origPos, origSize, e->value.byteArr->position - origPos); e->value.byteArr->position = 0; break; } --from; } } found = 1; break; } } break; } else if (e->index == 3) { e->index = it->element.attributeIndex; e->target = it->element.target; ret = invoke_ArrayManagerInsertEntry(settings, e, index); found = 1; break; } else if (e->index == 4) { e->index = it->element.attributeIndex; e->target = it->element.target; ret = invoke_ArrayManagerDeleteEntry(settings, e, index, index); ret = invoke_ArrayManagerInsertEntry(settings, e, index); found = 1; break; } else if (e->index == 5) { e->index = it->element.attributeIndex; e->target = it->element.target; ret = invoke_ArrayManagerDeleteEntry(settings, e, from, to); found = 1; break; } } } if (!found) { bb_clear(e->value.byteArr); ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; } return ret; } #endif //DLMS_IGNORE_ARRAY_MANAGER #ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP int invoke_G3_PLC_MAC_Setup( dlmsServerSettings* settings, gxG3PlcMacSetup* object, gxValueEventArg* e) { uint16_t address, pos, count = 0; int ret = 0; e->byteArray = 1; bb_clear(&settings->info.data); e->value.byteArr = &settings->info.data; if (e->parameters.vt != DLMS_DATA_TYPE_UINT16) { return DLMS_ERROR_CODE_INVALID_PARAMETER; } address = e->parameters.uiVal; if (e->index == 1) { //Get amount of neighbour tables. gxNeighbourTable* it; for (pos = 0; pos < (uint16_t)object->neighbourTable.size; ++pos) { #ifndef DLMS_IGNORE_MALLOC if ((ret = arr_getByIndex(&object->neighbourTable, pos, (void**)&it)) != 0) { break; } #else if ((ret = arr_getByIndex(&object->neighbourTable, pos, (void**)&it, sizeof(gxNeighbourTable))) != 0) { break; } #endif //DLMS_IGNORE_MALLOC if (it->shortAddress == address) { ++count; } } if (ret == 0) { return cosem_getG3PlcMacSetupNeighbourTables(&object->neighbourTable, address, count, e); } } else if (e->index == 2) { gxMacPosTable* it; //Get amount of MAC POS tables. for (pos = 0; pos < object->macPosTable.size; ++pos) { #ifndef DLMS_IGNORE_MALLOC if ((ret = arr_getByIndex(&object->macPosTable, pos, (void**)&it)) != 0) { break; } #else if ((ret = arr_getByIndex(&object->macPosTable, pos, (void**)&it, sizeof(gxMacPosTable))) != 0) { break; } #endif //DLMS_IGNORE_MALLOC if (it->shortAddress == address) { ++count; } } if (ret == 0) { return cosem_getG3PlcMacSetupPosTables(&object->macPosTable, address, count, e); } } bb_clear(e->value.byteArr); return DLMS_ERROR_CODE_READ_WRITE_DENIED; } #endif //DLMS_IGNORE_G3_PLC_MAC_SETUP int cosem_invoke( dlmsServerSettings* settings, gxValueEventArg* e) { int ret = DLMS_ERROR_CODE_INVALID_PARAMETER; //If invoke index is invalid. if (e->index < 1 || e->index > obj_methodCount(e->target)) { return DLMS_ERROR_CODE_INVALID_PARAMETER; } switch (e->target->objectType) { #ifndef DLMS_IGNORE_REGISTER case DLMS_OBJECT_TYPE_REGISTER: ret = invoke_Register( (gxRegister*)e->target, e); break; #endif //DLMS_IGNORE_REGISTER #ifndef DLMS_IGNORE_CLOCK case DLMS_OBJECT_TYPE_CLOCK: ret = invoke_Clock( (gxClock*)e->target, e->index, &e->parameters); break; #endif //DLMS_IGNORE_CLOCK #ifndef DLMS_IGNORE_EXTENDED_REGISTER case DLMS_OBJECT_TYPE_EXTENDED_REGISTER: ret = invoke_ExtendedRegister(settings, (gxExtendedRegister*)e->target, e->index); break; #endif //DLMS_IGNORE_EXTENDED_REGISTER #ifndef DLMS_IGNORE_DEMAND_REGISTER case DLMS_OBJECT_TYPE_DEMAND_REGISTER: ret = invoke_DemandRegister(settings, (gxDemandRegister*)e->target, e->index); break; #endif //DLMS_IGNORE_DEMAND_REGISTER #ifndef DLMS_IGNORE_PROFILE_GENERIC case DLMS_OBJECT_TYPE_PROFILE_GENERIC: ret = invoke_ProfileGeneric( settings, (gxProfileGeneric*)e->target, e->index); break; #endif //DLMS_IGNORE_PROFILE_GENERIC #ifndef DLMS_IGNORE_SCRIPT_TABLE case DLMS_OBJECT_TYPE_SCRIPT_TABLE: ret = invoke_ScriptTable(settings, e); break; #endif //DLMS_IGNORE_SCRIPT_TABLE #ifndef DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL case DLMS_OBJECT_TYPE_ZIG_BEE_NETWORK_CONTROL: ret = invoke_zigbeeNetworkControl( (gxZigBeeNetworkControl*)e->target, e->index, &e->parameters); break; #endif //DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL #ifndef DLMS_IGNORE_CHARGE case DLMS_OBJECT_TYPE_CHARGE: ret = invoke_Charge( (gxCharge*)e->target, e->index, &e->parameters); break; #endif //DLMS_IGNORE_CHARGE #ifndef DLMS_IGNORE_CREDIT case DLMS_OBJECT_TYPE_CREDIT: ret = invoke_Credit( (gxCredit*)e->target, e->index, &e->parameters); break; #endif //DLMS_IGNORE_CREDIT #ifndef DLMS_IGNORE_TOKEN_GATEWAY case DLMS_OBJECT_TYPE_TOKEN_GATEWAY: ret = invoke_gxTokenGateway( (gxTokenGateway*)e->target, e->index, &e->parameters); break; #endif //DLMS_IGNORE_TOKEN_GATEWAY #ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME case DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME: #ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME ret = invoke_AssociationShortName(settings, e); #endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME break; #endif //ASSOCIATION_SHORT_NAME #ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME case DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME: ret = invoke_AssociationLogicalName(settings, e); break; #endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME #ifndef DLMS_IGNORE_IMAGE_TRANSFER case DLMS_OBJECT_TYPE_IMAGE_TRANSFER: ret = invoke_ImageTransfer((gxImageTransfer*)e->target, e); break; #endif //DLMS_IGNORE_IMAGE_TRANSFER #ifndef DLMS_IGNORE_SAP_ASSIGNMENT case DLMS_OBJECT_TYPE_SAP_ASSIGNMENT: ret = invoke_SapAssigment((gxSapAssignment*)e->target, e); break; #endif //DLMS_IGNORE_SAP_ASSIGNMENT #ifndef DLMS_IGNORE_SECURITY_SETUP case DLMS_OBJECT_TYPE_SECURITY_SETUP: ret = invoke_SecuritySetup(settings, (gxSecuritySetup*)e->target, e); break; #endif //DLMS_IGNORE_SECURITY_SETUP #ifndef DLMS_IGNORE_COMPACT_DATA case DLMS_OBJECT_TYPE_COMPACT_DATA: ret = invoke_CompactData(settings, (gxCompactData*)e->target, e->index); break; #endif //DLMS_IGNORE_COMPACT_DATA #ifndef DLMS_IGNORE_DISCONNECT_CONTROL case DLMS_OBJECT_TYPE_DISCONNECT_CONTROL: ret = invoke_DisconnectControl(settings, (gxDisconnectControl*)e->target, e->index); break; #endif //DLMS_IGNORE_DISCONNECT_CONTROL #ifndef DLMS_IGNORE_LLC_SSCS_SETUP case DLMS_OBJECT_TYPE_LLC_SSCS_SETUP: ret = invoke_LlcSscsSetup((gxLlcSscsSetup*)e->target, e->index); break; #endif //DLMS_IGNORE_LLC_SSCS_SETUP #ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS: ret = invoke_PrimeNbOfdmPlcPhysicalLayerCounters((gxPrimeNbOfdmPlcPhysicalLayerCounters*)e->target, e->index); break; #endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS #ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_COUNTERS: ret = invoke_PrimeNbOfdmPlcMacCounters((gxPrimeNbOfdmPlcMacCounters*)e->target, e->index); break; #endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS #ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA: ret = invoke_PrimeNbOfdmPlcMacNetworkAdministrationData((gxPrimeNbOfdmPlcMacNetworkAdministrationData*)e->target, e->index); break; #endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA #ifndef DLMS_IGNORE_SPECIAL_DAYS_TABLE case DLMS_OBJECT_TYPE_SPECIAL_DAYS_TABLE: ret = invoke_SpecialDaysTable((gxSpecialDaysTable*)e->target, e); break; #endif //DLMS_IGNORE_SPECIAL_DAYS_TABLE #ifndef DLMS_IGNORE_REGISTER_ACTIVATION case DLMS_OBJECT_TYPE_REGISTER_ACTIVATION: ret = invoke_RegisterActivation(settings, (gxRegisterActivation*)e->target, e); break; #endif //DLMS_IGNORE_REGISTER_ACTIVATION #ifndef DLMS_IGNORE_ACTIVITY_CALENDAR case DLMS_OBJECT_TYPE_ACTIVITY_CALENDAR: ret = invoke_ActivityCalendar(e); break; #endif //DLMS_IGNORE_ACTIVITY_CALENDAR #ifndef DLMS_IGNORE_ARRAY_MANAGER case DLMS_OBJECT_TYPE_ARRAY_MANAGER: ret = invoke_ArrayManager(settings, e); break; #endif //DLMS_IGNORE_ARRAY_MANAGER #ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP case DLMS_OBJECT_TYPE_G3_PLC_MAC_SETUP: ret = invoke_G3_PLC_MAC_Setup(settings, (gxG3PlcMacSetup*)e->target, e); break; #endif //DLMS_IGNORE_G3_PLC_MAC_SETUP default: //Unknown type. ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } return ret; } #endif //DLMS_IGNORE_SERVER