MmsDataAccessError mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* value, MmsServerConnection* connection) { MmsDataAccessError indication; if (self->writeHandler != NULL) { indication = self->writeHandler(self->writeHandlerParameter, domain, itemId, value, connection); } else { MmsValue* cachedValue; if (domain == NULL) domain = (MmsDomain*) self->device; cachedValue = MmsServer_getValueFromCache(self, domain, itemId); if (cachedValue != NULL) { MmsValue_update(cachedValue, value); indication = DATA_ACCESS_ERROR_SUCCESS; } else indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; } return indication; }
MmsValueIndication MmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* value) { MmsValueIndication indication; if (self->writeHandler != NULL) { indication = self->writeHandler(self->writeHandlerParameter, domain, itemId, value); } else { //TODO if value in cache write to cache //else access denied MmsValue* cachedValue; cachedValue = MmsServer_getValueFromCache(self, domain, itemId); if (cachedValue != NULL) { MmsValue_update(cachedValue, value); indication = MMS_VALUE_OK; } else indication = MMS_VALUE_ACCESS_DENIED; } return indication; }
static void updateOrClone(MmsValue** valuePtr, MmsValue* values, int index) { if (*valuePtr != NULL) MmsValue_update(*valuePtr, MmsValue_getElement(values, index)); else *valuePtr = MmsValue_clone(MmsValue_getElement(values, index)); }
void ClientGooseControlBlock_setDstAddress_addr(ClientGooseControlBlock self, MmsValue* macAddr) { if (self->dstAddress == NULL) self->dstAddress = newEmptyPhyCommAddress(); MmsValue* addr = MmsValue_getElement(self->dstAddress, 0); MmsValue_update(addr, macAddr); }
ClientDataSet IedConnection_readDataSetValues(IedConnection self, IedClientError* error, char* dataSetReference, ClientDataSet dataSet) { char domainIdBuffer[65]; char itemIdBuffer[129]; char* domainId = NULL; char* itemId = NULL; bool isAssociationSpecific = false; if (dataSetReference[0] != '@') { domainId = MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainIdBuffer); itemId = copyStringToBuffer(dataSetReference + strlen(domainId) + 1, itemIdBuffer); StringUtils_replace(itemId, '.', '$'); } else { itemId = dataSetReference; isAssociationSpecific = true; } MmsError mmsError; MmsValue* dataSetVal; if (isAssociationSpecific) dataSetVal = MmsConnection_readNamedVariableListValuesAssociationSpecific(self->connection, &mmsError, itemId, true); else dataSetVal= MmsConnection_readNamedVariableListValues(self->connection, &mmsError, domainId, itemId, true); if (dataSetVal == NULL) { *error = iedConnection_mapMmsErrorToIedError(mmsError); goto cleanup_and_exit; } else *error = IED_ERROR_OK; if (dataSet == NULL) { dataSet = ClientDataSet_create(dataSetReference); ClientDataSet_setDataSetValues(dataSet, dataSetVal); } else { MmsValue* dataSetValues = ClientDataSet_getValues(dataSet); MmsValue_update(dataSetValues, dataSetVal); } cleanup_and_exit: return dataSet; }
void IedServer_updateAttributeValue(IedServer self, DataAttribute* dataAttribute, MmsValue* value) { assert(self != NULL); assert(dataAttribute != NULL); assert(MmsValue_getType(dataAttribute->mmsValue) == MmsValue_getType(value)); if (MmsValue_equals(dataAttribute->mmsValue, value)) checkForUpdateTrigger(self, dataAttribute); else { MmsValue_update(dataAttribute->mmsValue, value); checkForChangedTriggers(self, dataAttribute); } }
void ClientReportControlBlock_setEntryId(ClientReportControlBlock self, MmsValue* entryId) { if (self->entryId != NULL) { MmsValue_update(self->entryId, entryId); } else { if (MmsValue_getType(entryId) != MMS_OCTET_STRING) { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: ClientReportControlBlock_setEntryId invalid argument type\n"); } else self->entryId = MmsValue_clone(entryId); } }
void ClientReportControlBlock_setOptFlds(ClientReportControlBlock self, MmsValue* optFlds) { if (self->optFlds != NULL) { MmsValue_update(self->optFlds, optFlds); } else { if (MmsValue_getType(optFlds) != MMS_BIT_STRING) { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: ClientReportControlBlock_setOptFlds invalid argument type\n"); } else self->optFlds = MmsValue_clone(optFlds); } }
static void installDefaultValuesForDataAttribute(IedServer self, DataAttribute* dataAttribute, char* objectReference, int position) { sprintf(objectReference + position, ".%s", dataAttribute->name); char mmsVariableName[65]; /* maximum size is 64 according to 61850-8-1 */ MmsValue* value = dataAttribute->mmsValue; MmsMapping_createMmsVariableNameFromObjectReference(objectReference, dataAttribute->fc, mmsVariableName); char domainName[65]; MmsMapping_getMmsDomainFromObjectReference(objectReference, domainName); MmsDomain* domain = MmsDevice_getDomain(self->mmsDevice, domainName); if (domain == NULL) { if (DEBUG_IED_SERVER) printf("Error domain (%s) not found!\n", domainName); return; } MmsValue* cacheValue = MmsServer_getValueFromCache(self->mmsServer, domain, mmsVariableName); dataAttribute->mmsValue = cacheValue; if (value != NULL) { MmsValue_update(cacheValue, value); MmsValue_delete(value); } int childPosition = strlen(objectReference); DataAttribute* subDataAttribute = (DataAttribute*) dataAttribute->firstChild; while (subDataAttribute != NULL) { installDefaultValuesForDataAttribute(self, subDataAttribute, objectReference, childPosition); subDataAttribute = (DataAttribute*) subDataAttribute->sibling; } }
bool ControlObjectClient_selectWithValue(ControlObjectClient self, MmsValue* ctlVal) { resetLastApplError(self); char domainId[65]; char itemId[65]; MmsMapping_getMmsDomainFromObjectReference(self->objectReference, domainId); convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO"); strncat(itemId, "$SBOw", 64); if (DEBUG_IED_CLIENT) printf("IED_CLIENT: select with value: %s/%s\n", domainId, itemId); MmsError mmsError; MmsValue* selValParameters; if (self->hasTimeActivatedMode) selValParameters = MmsValue_createEmptyStructure(7); else selValParameters = MmsValue_createEmptyStructure(6); MmsValue_setElement(selValParameters, 0, ctlVal); int index = 1; if (self->hasTimeActivatedMode) { MmsValue* operTm = MmsValue_newUtcTimeByMsTime(0); MmsValue_setElement(selValParameters, index++, operTm); } MmsValue* origin = createOriginValue(self); MmsValue_setElement(selValParameters, index++, origin); self->ctlNum++; MmsValue* ctlNum = MmsValue_newUnsignedFromUint32(self->ctlNum); MmsValue_setElement(selValParameters, index++, ctlNum); uint64_t timestamp = Hal_getTimeInMs(); MmsValue* ctlTime; if (self->edition == 2) ctlTime = MmsValue_newUtcTimeByMsTime(timestamp); else { ctlTime = MmsValue_newBinaryTime(false); MmsValue_setBinaryTime(ctlTime, timestamp); } MmsValue_setElement(selValParameters, index++, ctlTime); MmsValue* ctlTest = MmsValue_newBoolean(self->test); MmsValue_setElement(selValParameters, index++, ctlTest); MmsValue* check = MmsValue_newBitString(2); MmsValue_setBitStringBit(check, 1, self->interlockCheck); MmsValue_setBitStringBit(check, 0, self->synchroCheck); MmsValue_setElement(selValParameters, index++, check); MmsConnection_writeVariable(IedConnection_getMmsConnection(self->connection), &mmsError, domainId, itemId, selValParameters); MmsValue_setElement(selValParameters, 0, NULL); MmsValue_delete(selValParameters); if (mmsError != MMS_ERROR_NONE) { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: select-with-value failed!\n"); return false; } MmsValue_update(self->ctlVal, ctlVal); return true; }
bool ControlObjectClient_operate(ControlObjectClient self, MmsValue* ctlVal, uint64_t operTime) { bool success = false; if (ctlVal == NULL) { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: operate - (ctlVal == NULL)!\n"); goto exit_function; } resetLastApplError(self); MmsValue* operParameters; if (self->hasTimeActivatedMode) operParameters = MmsValue_createEmptyStructure(7); else operParameters = MmsValue_createEmptyStructure(6); MmsValue_setElement(operParameters, 0, ctlVal); int index = 1; if (self->hasTimeActivatedMode) { MmsValue* operTm = MmsValue_newUtcTimeByMsTime(operTime); MmsValue_setElement(operParameters, index++, operTm); } MmsValue* origin = createOriginValue(self); MmsValue_setElement(operParameters, index++, origin); if (!((self->ctlModel == CONTROL_MODEL_SBO_NORMAL) || (self->ctlModel == CONTROL_MODEL_SBO_ENHANCED))) { self->ctlNum++; } MmsValue* ctlNum = MmsValue_newUnsignedFromUint32(self->ctlNum); MmsValue_setElement(operParameters, index++, ctlNum); uint64_t timestamp = Hal_getTimeInMs(); MmsValue* ctlTime; if (self->edition == 2) ctlTime = MmsValue_newUtcTimeByMsTime(timestamp); else { ctlTime = MmsValue_newBinaryTime(false); MmsValue_setBinaryTime(ctlTime, timestamp); } MmsValue_setElement(operParameters, index++, ctlTime); MmsValue* ctlTest = MmsValue_newBoolean(self->test); MmsValue_setElement(operParameters, index++, ctlTest); MmsValue* check = MmsValue_newBitString(2); MmsValue_setBitStringBit(check, 1, self->interlockCheck); MmsValue_setBitStringBit(check, 0, self->synchroCheck); MmsValue_setElement(operParameters, index++, check); char domainId[65]; char itemId[65]; MmsMapping_getMmsDomainFromObjectReference(self->objectReference, domainId); convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO"); int controlObjectItemIdLen = strlen(itemId); strncat(itemId, "$Oper", 64 - controlObjectItemIdLen); if (DEBUG_IED_CLIENT) printf("IED_CLIENT: operate: %s/%s\n", domainId, itemId); MmsError mmsError; MmsConnection_writeVariable(IedConnection_getMmsConnection(self->connection), &mmsError, domainId, itemId, operParameters); MmsValue_setElement(operParameters, 0, NULL); MmsValue_delete(operParameters); if (mmsError != MMS_ERROR_NONE) { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: operate failed!\n"); goto exit_function; } MmsValue_update(self->ctlVal, ctlVal); self->opertime = operTime; success = true; exit_function: return success; }
/********************************************************************************************** * mmsServer_handleWriteRequest * возвращает MmsServiceError *********************************************************************************************/ int mmsServer_handleWriteRequest( MmsServerConnection* connection, WriteRequest_t* writeRequest, int invokeId, ByteBuffer* response) { ListOfVariableSeq_t* varSpec; Identifier_t domainId; char* domainIdStr; MmsDevice* device; MmsDomain* domain; Identifier_t nameId; char* nameIdStr; MmsTypeSpecification* variable; AlternateAccess_t* alternateAccess; Data_t* dataElement; MmsValue* value; MmsValueIndication valueIndication; if (writeRequest->variableAccessSpecification.choice.listOfVariable.list.count != 1) return -1; varSpec = writeRequest->variableAccessSpecification.choice.listOfVariable.list.array[0]; if (varSpec->variableSpecification.present != VariableSpecification_PR_name) { createMmsWriteResponse(connection, invokeId, response, MMS_VALUE_ACCESS_DENIED); return 0; } if (varSpec->variableSpecification.choice.name.present != ObjectName_PR_domainspecific) { createMmsWriteResponse(connection, invokeId, response, MMS_VALUE_ACCESS_DENIED); return 0; } domainId = varSpec->variableSpecification.choice.name.choice.domainspecific.domainId; domainIdStr = createStringFromBuffer(domainId.buf, domainId.size); device = MmsServer_getDevice(connection->server); domain = MmsDevice_getDomain(device, domainIdStr); free(domainIdStr); if (domain == NULL) { createMmsWriteResponse(connection, invokeId, response, MMS_VALUE_ACCESS_DENIED); return 0; } nameId = varSpec->variableSpecification.choice.name.choice.domainspecific.itemId; nameIdStr = createStringFromBuffer(nameId.buf, nameId.size); variable = MmsDomain_getNamedVariable(domain, nameIdStr); if (variable == NULL) goto return_access_denied; if (writeRequest->listOfData.list.count != 1) goto return_access_denied; alternateAccess = varSpec->alternateAccess; if (alternateAccess != NULL) { if (variable->type != MMS_ARRAY) goto return_access_denied; if (!mmsServer_isIndexAccess(alternateAccess)) goto return_access_denied; } dataElement = writeRequest->listOfData.list.array[0]; value = mmsMsg_parseDataElement(dataElement); if (value == NULL) goto return_access_denied; if (alternateAccess != NULL) { MmsValue* cachedArray = MmsServer_getValueFromCache(connection->server, domain, nameIdStr); int index; MmsValue* elementValue; if (cachedArray == NULL) { MmsValue_delete(value); goto return_access_denied; } index = mmsServer_getLowIndex(alternateAccess); elementValue = MmsValue_getElement(cachedArray, index); if (elementValue == NULL) { MmsValue_delete(value); goto return_access_denied; } if (MmsValue_update(elementValue, value) == false) { MmsValue_delete(value); goto return_access_denied; } } MmsServer_lockModel(connection->server); valueIndication = mmsServer_setValue(connection->server, domain, nameIdStr, value, connection); MmsServer_unlockModel(connection->server); createMmsWriteResponse(connection, invokeId, response, valueIndication); MmsValue_delete(value); free(nameIdStr); return 0; return_access_denied: createMmsWriteResponse(connection, invokeId, response, MMS_VALUE_ACCESS_DENIED); free(nameIdStr); return 0; }
MmsDataAccessError Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* elementName, MmsValue* value, MmsServerConnection* connection) { if (strcmp(elementName, "RptEna") == 0) { if (value->value.boolean == true) { if (rc->enabled == true) return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; if (DEBUG) printf("Activate report for client %s\n", MmsServerConnection_getClientAddress(connection)); MmsValue* dataSetValue; dataSetValue = ReportControl_getRCBValue(rc, "DatSet"); char* dataSetName = MmsValue_toString(dataSetValue); if (rc->isDynamicDataSet) { if (rc->dataSet != NULL) MmsMapping_freeDynamicallyCreatedDataSet(rc->dataSet); } if (dataSetValue != NULL) { DataSet* dataSet = IedModel_lookupDataSet(self->model, dataSetName); if (dataSet == NULL) { dataSet = MmsMapping_getDomainSpecificDataSet(self, dataSetName); if (dataSet == NULL) return DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT; rc->isDynamicDataSet = true; } else rc->isDynamicDataSet = false; rc->dataSet = dataSet; rc->inclusionField = MmsValue_newBitString( dataSet->elementCount); rc->clientConnection = connection; // TODO check integrity bit in trigger options MmsValue* intgPd = ReportControl_getRCBValue(rc, "IntgPd"); rc->intgPd = MmsValue_toUint32(intgPd); MmsValue* rptEna = ReportControl_getRCBValue(rc, "RptEna"); MmsValue_update(rptEna, value); MmsValue* bufTm = ReportControl_getRCBValue(rc, "BufTm"); rc->bufTm = MmsValue_toUint32(bufTm); rc->triggerOps = 0; MmsValue* trgOps = ReportControl_getRCBValue(rc, "TrgOps"); if (MmsValue_getBitStringBit(trgOps, 1)) rc->triggerOps += TRG_OPT_DATA_CHANGED; if (MmsValue_getBitStringBit(trgOps, 2)) rc->triggerOps += TRG_OPT_QUALITY_CHANGED; if (MmsValue_getBitStringBit(trgOps, 3)) rc->triggerOps += TRG_OPT_DATA_UPDATE; if (MmsValue_getBitStringBit(trgOps, 4)) rc->triggerOps += TRG_OPT_INTEGRITY; if (MmsValue_getBitStringBit(trgOps, 5)) rc->triggerOps += TRG_OPT_GI; rc->sqNum = 0; rc->inclusionFlags = (ReportInclusionFlag*) calloc(dataSet->elementCount, sizeof(ReportInclusionFlag)); rc->enabled = true; return DATA_ACCESS_ERROR_SUCCESS; } return DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT; } else { if (((rc->enabled) || (rc->reserved)) && (rc->clientConnection != connection)) return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; if (DEBUG) printf("Deactivate report for client %s\n", MmsServerConnection_getClientAddress(connection)); free(rc->inclusionFlags); rc->inclusionFlags = NULL; rc->enabled = false; } } if (strcmp(elementName, "GI") == 0) { if ((rc->enabled) && (rc->clientConnection == connection)) { rc->gi = true; return DATA_ACCESS_ERROR_SUCCESS;; } else return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; } if (rc->enabled == false) { if ((rc->reserved) && (rc->clientConnection != connection)) return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; if (rc->bufferd == false) { if (strcmp(elementName, "Resv") == 0) { rc->reserved = value->value.boolean; if (rc->reserved == true) rc->clientConnection = connection; } } MmsValue* rcbValue = ReportControl_getRCBValue(rc, elementName); if (rcbValue != NULL) MmsValue_update(rcbValue, value); else return DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; } else return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; return DATA_ACCESS_ERROR_SUCCESS;; }
void mmsServer_handleWriteRequest( MmsServerConnection* connection, uint8_t* buffer, int bufPos, int maxBufPos, uint32_t invokeId, ByteBuffer* response) { WriteRequest_t* writeRequest = 0; MmsPdu_t* mmsPdu = 0; asn_dec_rval_t rval; /* Decoder return value */ rval = ber_decode(NULL, &asn_DEF_MmsPdu, (void**) &mmsPdu, buffer, CONFIG_MMS_MAXIMUM_PDU_SIZE); if (rval.code != RC_OK) { mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); return; } writeRequest = &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.write); int numberOfWriteItems = writeRequest->variableAccessSpecification.choice.listOfVariable.list.count; if (numberOfWriteItems < 1) { mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response); return; } if (numberOfWriteItems > CONFIG_MMS_WRITE_SERVICE_MAX_NUMBER_OF_WRITE_ITEMS) { mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_OTHER, response); return; } if (writeRequest->listOfData.list.count != numberOfWriteItems) { mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response); return; } MmsDataAccessError accessResults[CONFIG_MMS_WRITE_SERVICE_MAX_NUMBER_OF_WRITE_ITEMS * sizeof(MmsDataAccessError)]; bool sendResponse = true; int i; for (i = 0; i < numberOfWriteItems; i++) { ListOfVariableSeq_t* varSpec = writeRequest->variableAccessSpecification.choice.listOfVariable.list.array[i]; if (varSpec->variableSpecification.present != VariableSpecification_PR_name) { accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ACCESS_UNSUPPORTED; continue; } if (varSpec->variableSpecification.choice.name.present != ObjectName_PR_domainspecific) { accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ACCESS_UNSUPPORTED; continue; } Identifier_t domainId = varSpec->variableSpecification.choice.name.choice.domainspecific.domainId; char* domainIdStr = createStringFromBuffer(domainId.buf, domainId.size); MmsDevice* device = MmsServer_getDevice(connection->server); MmsDomain* domain = MmsDevice_getDomain(device, domainIdStr); free(domainIdStr); if (domain == NULL) { accessResults[i] = DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT; continue; } Identifier_t nameId = varSpec->variableSpecification.choice.name.choice.domainspecific.itemId; char* nameIdStr = createStringFromBuffer(nameId.buf, nameId.size); MmsVariableSpecification* variable = MmsDomain_getNamedVariable(domain, nameIdStr); if (variable == NULL) { free(nameIdStr); accessResults[i] = DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT; continue; } AlternateAccess_t* alternateAccess = varSpec->alternateAccess; if (alternateAccess != NULL) { if (variable->type != MMS_ARRAY) { free(nameIdStr); accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT; continue; } if (!mmsServer_isIndexAccess(alternateAccess)) { free(nameIdStr); accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ACCESS_UNSUPPORTED; continue; } } Data_t* dataElement = writeRequest->listOfData.list.array[i]; MmsValue* value = mmsMsg_parseDataElement(dataElement); if (value == NULL) { free(nameIdStr); accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT; continue; } if (alternateAccess != NULL) { MmsValue* cachedArray = MmsServer_getValueFromCache(connection->server, domain, nameIdStr); if (cachedArray == NULL) { free(nameIdStr); MmsValue_delete(value); accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT; continue; } int index = mmsServer_getLowIndex(alternateAccess); MmsValue* elementValue = MmsValue_getElement(cachedArray, index); if (elementValue == NULL) { free(nameIdStr); MmsValue_delete(value); accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT; continue; } if (MmsValue_update(elementValue, value) == false) { free(nameIdStr); MmsValue_delete(value); accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; continue; } free(nameIdStr); MmsValue_delete(value); accessResults[i] = DATA_ACCESS_ERROR_SUCCESS; continue; } MmsDataAccessError valueIndication = mmsServer_setValue(connection->server, domain, nameIdStr, value, connection); if (valueIndication == DATA_ACCESS_ERROR_NO_RESPONSE) sendResponse = false; accessResults[i] = valueIndication; MmsValue_delete(value); free(nameIdStr); } if (sendResponse) { mmsServer_createMmsWriteResponse(connection, invokeId, response, numberOfWriteItems, accessResults); } asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); }
MmsDataAccessError Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, MmsValue* value, MmsServerConnection connection) { MmsDataAccessError indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; if (DEBUG_IED_SERVER) printf("IED_SERVER: writeAccessControlObject: %s\n", variableIdOrig); char variableId[65]; strncpy(variableId, variableIdOrig, 64); variableId[64] = 0; char* separator = strchr(variableId, '$'); if (separator == NULL) goto free_and_return; *separator = 0; char* lnName = variableId; if (lnName == NULL) goto free_and_return; char* objectName = MmsMapping_getNextNameElement(separator + 1); if (objectName == NULL) goto free_and_return; char* varName = MmsMapping_getNextNameElement(objectName); if (varName != NULL) { bool foundVar = false; char* nextVarName = varName; do { if (doesElementEquals(varName, "Oper") || doesElementEquals(varName, "SBO") || doesElementEquals(varName, "SBOw") || doesElementEquals(varName, "Cancel")) { *(varName - 1) = 0; foundVar = true; break; } nextVarName = MmsMapping_getNextNameElement(varName); if (nextVarName != NULL) varName = nextVarName; } while (nextVarName != NULL); if (foundVar == false) varName = NULL; } if (DEBUG_IED_SERVER) printf("IED_SERVER: write access control: objectName: (%s) varName: (%s)\n", objectName, varName); if (varName == NULL) { indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; goto free_and_return; } ControlObject* controlObject = Control_lookupControlObject(self, domain, lnName, objectName); if (controlObject == NULL) { indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; goto free_and_return; } initialize(controlObject); if (strcmp(varName, "SBOw") == 0) { /* select with value */ if (controlObject->ctlModel == 4) { MmsValue* ctlVal = getCtlVal(value); if (ctlVal != NULL) { MmsValue* ctlNum = getOperParameterCtlNum(value); MmsValue* origin = getOperParameterOrigin(value); MmsValue* check = getOperParameterCheck(value); MmsValue* test = getOperParameterTest(value); if (checkValidityOfOriginParameter(origin) == false) { indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; goto free_and_return; } uint64_t currentTime = Hal_getTimeInMs(); checkSelectTimeout(controlObject, currentTime); int state = getState(controlObject); if (state != STATE_UNSELECTED) { indication = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; if (connection != controlObject->mmsConnection) ControlObject_sendLastApplError(controlObject, connection, "SBOw", 0, ADD_CAUSE_LOCKED_BY_OTHER_CLIENT, ctlNum, origin, true); else ControlObject_sendLastApplError(controlObject, connection, "SBOw", 0, ADD_CAUSE_OBJECT_ALREADY_SELECTED, ctlNum, origin, true); if (DEBUG_IED_SERVER) printf("SBOw: select failed!\n"); } else { CheckHandlerResult checkResult = CONTROL_ACCEPTED; bool interlockCheck = MmsValue_getBitStringBit(check, 1); bool testCondition = MmsValue_getBoolean(test); if (controlObject->checkHandler != NULL) { /* perform operative tests */ ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); checkResult = controlObject->checkHandler( controlObject->checkHandlerParameter, ctlVal, testCondition, interlockCheck, clientConnection); } if (checkResult == CONTROL_ACCEPTED) { selectObject(controlObject, currentTime, connection); updateControlParameters(controlObject, ctlVal, ctlNum, origin); indication = DATA_ACCESS_ERROR_SUCCESS; if (DEBUG_IED_SERVER) printf("SBOw: selected successful\n"); } else { indication = getDataAccessErrorFromCheckHandlerResult(checkResult); ControlObject_sendLastApplError(controlObject, connection, "SBOw", 0, ADD_CAUSE_SELECT_FAILED, ctlNum, origin, true); if (DEBUG_IED_SERVER) printf("SBOw: select rejected by application!\n"); } } } else { indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; } } else { indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; goto free_and_return; } } else if (strcmp(varName, "Oper") == 0) { MmsValue* ctlVal = getCtlVal(value); MmsValue* test = getOperParameterTest(value); MmsValue* ctlNum = getOperParameterCtlNum(value); MmsValue* origin = getOperParameterOrigin(value); MmsValue* check = getOperParameterCheck(value); MmsValue* timeParameter = getOperParameterTime(value); if ((ctlVal == NULL) || (test == NULL) || (ctlNum == NULL) || (origin == NULL) || (check == NULL) || (timeParameter == NULL)) { indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; goto free_and_return; } if (checkValidityOfOriginParameter(origin) == false) { indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; goto free_and_return; } uint64_t currentTime = Hal_getTimeInMs(); checkSelectTimeout(controlObject, currentTime); int state = getState(controlObject); if (state == STATE_WAIT_FOR_ACTIVATION_TIME) { indication = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; ControlObject_sendLastApplError(controlObject, connection, "Oper", CONTROL_ERROR_NO_ERROR, ADD_CAUSE_COMMAND_ALREADY_IN_EXECUTION, ctlNum, origin, true); goto free_and_return; } else if (state == STATE_READY) { bool interlockCheck = MmsValue_getBitStringBit(check, 1); bool synchroCheck = MmsValue_getBitStringBit(check, 0); bool testCondition = MmsValue_getBoolean(test); controlObject->testMode = testCondition; if ((controlObject->ctlModel == 2) || (controlObject->ctlModel == 4)) { if (controlObject->mmsConnection != connection) { indication = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; if (DEBUG_IED_SERVER) printf("Oper: operate from wrong client connection!\n"); goto free_and_return; } if (controlObject->ctlModel == 4) { /* select-before-operate with enhanced security */ if ((MmsValue_equals(ctlVal, controlObject->ctlVal) && MmsValue_equals(origin, controlObject->origin) && MmsValue_equals(ctlNum, controlObject->ctlNum)) == false) { indication = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; ControlObject_sendLastApplError(controlObject, connection, "Oper", CONTROL_ERROR_NO_ERROR, ADD_CAUSE_INCONSISTENT_PARAMETERS, ctlNum, origin, true); goto free_and_return; } } } updateControlParameters(controlObject, ctlVal, ctlNum, origin); MmsValue* operTm = getOperParameterOperTime(value); if (operTm != NULL) { controlObject->operateTime = MmsValue_getUtcTimeInMs(operTm); if (controlObject->operateTime != 0) { controlObject->timeActivatedOperate = true; controlObject->synchroCheck = synchroCheck; controlObject->interlockCheck = interlockCheck; controlObject->mmsConnection = connection; initiateControlTask(controlObject); setState(controlObject, STATE_WAIT_FOR_ACTIVATION_TIME); if (DEBUG_IED_SERVER) printf("Oper: activate time activated control\n"); indication = DATA_ACCESS_ERROR_SUCCESS; } } MmsValue_update(controlObject->oper, value); if (controlObject->timeActivatedOperate == false) { CheckHandlerResult checkResult = CONTROL_ACCEPTED; if (controlObject->checkHandler != NULL) { /* perform operative tests */ ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); checkResult = controlObject->checkHandler( controlObject->checkHandlerParameter, ctlVal, testCondition, interlockCheck, clientConnection); } if (checkResult == CONTROL_ACCEPTED) { indication = DATA_ACCESS_ERROR_NO_RESPONSE; controlObject->mmsConnection = connection; controlObject->operateInvokeId = MmsServerConnection_getLastInvokeId(connection); setState(controlObject, STATE_WAIT_FOR_EXECUTION); initiateControlTask(controlObject); #if (CONFIG_MMS_THREADLESS_STACK == 1) //TODO call this in single threaded version to increase response time!? //executeControlTask(controlObject); #endif } else { indication = getDataAccessErrorFromCheckHandlerResult(checkResult); abortControlOperation(controlObject); } } } else if (state == STATE_UNSELECTED) { if (DEBUG_IED_SERVER) printf("IED_SERVER: Oper failed - control not selected!\n"); indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; ControlObject_sendLastApplError(controlObject, connection, "Oper", CONTROL_ERROR_NO_ERROR, ADD_CAUSE_OBJECT_NOT_SELECTED, ctlNum, origin, true); goto free_and_return; } } else if (strcmp(varName, "Cancel") == 0) { if (DEBUG_IED_SERVER) printf("IED_SERVER: control received cancel!\n"); int state = getState(controlObject); MmsValue* ctlNum = getCancelParameterCtlNum(value); MmsValue* origin = getCancelParameterOrigin(value); if ((ctlNum == NULL) || (origin == NULL)) { indication = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; if (DEBUG_IED_SERVER) printf("IED_SERVER: Invalid cancel message!\n"); goto free_and_return; } if ((controlObject->ctlModel == 2) || (controlObject->ctlModel == 4)) { if (state != STATE_UNSELECTED) { if (controlObject->mmsConnection == connection) { indication = DATA_ACCESS_ERROR_SUCCESS; setState(controlObject, STATE_UNSELECTED); goto free_and_return; } else { indication = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; ControlObject_sendLastApplError(controlObject, connection, "Cancel", CONTROL_ERROR_NO_ERROR, ADD_CAUSE_LOCKED_BY_OTHER_CLIENT, ctlNum, origin, true); } } } if (controlObject->timeActivatedOperate) { controlObject->timeActivatedOperate = false; abortControlOperation(controlObject); indication = DATA_ACCESS_ERROR_SUCCESS; goto free_and_return; } } free_and_return: return indication; }