static MmsValue* createOptFlds(ReportControlBlock* reportControlBlock) { MmsValue* optFlds = MmsValue_newBitString(10); uint8_t options = reportControlBlock->options; if (options & 0x01) MmsValue_setBitStringBit(optFlds, 1, true); if (options & 0x02) MmsValue_setBitStringBit(optFlds, 2, true); if (options & 0x04) MmsValue_setBitStringBit(optFlds, 3, true); if (options & 0x08) MmsValue_setBitStringBit(optFlds, 4, true); if (options & 0x10) MmsValue_setBitStringBit(optFlds, 5, true); if (options & 0x20) MmsValue_setBitStringBit(optFlds, 6, true); if (options & 0x40) MmsValue_setBitStringBit(optFlds, 7, true); if (options & 0x80) MmsValue_setBitStringBit(optFlds, 8, true); return optFlds; }
void ClientReportControlBlock_setTrgOps(ClientReportControlBlock self, int trgOps) { if (self->trgOps == NULL) self->trgOps = MmsValue_newBitString(6); MmsValue_setBitStringFromInteger(self->trgOps, trgOps << 1); }
static MmsValue* createTrgOps(ReportControlBlock* reportControlBlock) { MmsValue* trgOps = MmsValue_newBitString(6); uint8_t triggerOps = reportControlBlock->trgOps; if (triggerOps & 0x02) MmsValue_setBitStringBit(trgOps, 1, true); if (triggerOps & 0x04) MmsValue_setBitStringBit(trgOps, 2, true); if (triggerOps & 0x08) MmsValue_setBitStringBit(trgOps, 3, true); if (triggerOps & 0x10) MmsValue_setBitStringBit(trgOps, 4, true); if (triggerOps & 0x20) MmsValue_setBitStringBit(trgOps, 5, true); return trgOps; }
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; }
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;; }
static void sendReport(ReportControl* self, bool isIntegrity, bool isGI) { LinkedList reportElements = LinkedList_create(); LinkedList deletableElements = LinkedList_create(); MmsValue* rptId = ReportControl_getRCBValue(self, "RptID"); MmsValue* optFlds = ReportControl_getRCBValue(self, "OptFlds"); MmsValue* datSet = ReportControl_getRCBValue(self, "DatSet"); LinkedList_add(reportElements, rptId); LinkedList_add(reportElements, optFlds); /* delete option fields for unsupported options */ MmsValue_setBitStringBit(optFlds, 5, false); /* data-reference */ MmsValue_setBitStringBit(optFlds, 7, false); /* entryID */ MmsValue_setBitStringBit(optFlds, 9, false); /* segmentation */ MmsValue* sqNum = ReportControl_getRCBValue(self, "SqNum"); if (MmsValue_getBitStringBit(optFlds, 1)) /* sequence number */ LinkedList_add(reportElements, sqNum); if (MmsValue_getBitStringBit(optFlds, 2)) { /* report time stamp */ LinkedList_add(reportElements, self->timeOfEntry); } if (MmsValue_getBitStringBit(optFlds, 4)) /* data set reference */ LinkedList_add(reportElements, datSet); if (MmsValue_getBitStringBit(optFlds, 6)) { /* bufOvfl */ MmsValue* bufOvfl = MmsValue_newBoolean(false); LinkedList_add(reportElements, bufOvfl); LinkedList_add(deletableElements, bufOvfl); } if (MmsValue_getBitStringBit(optFlds, 8)) LinkedList_add(reportElements, self->confRev); if (isGI || isIntegrity) MmsValue_setAllBitStringBits(self->inclusionField); else MmsValue_deleteAllBitStringBits(self->inclusionField); LinkedList_add(reportElements, self->inclusionField); /* add data set value elements */ int i = 0; for (i = 0; i < self->dataSet->elementCount; i++) { if (isGI || isIntegrity) LinkedList_add(reportElements, self->dataSet->fcda[i]->value); else { if (self->inclusionFlags[i] != REPORT_CONTROL_NONE) { LinkedList_add(reportElements, self->dataSet->fcda[i]->value); MmsValue_setBitStringBit(self->inclusionField, i, true); } } } /* add reason code to report if requested */ if (MmsValue_getBitStringBit(optFlds, 3)) { for (i = 0; i < self->dataSet->elementCount; i++) { if (isGI || isIntegrity) { MmsValue* reason = MmsValue_newBitString(6); if (isGI) MmsValue_setBitStringBit(reason, 5, true); if (isIntegrity) MmsValue_setBitStringBit(reason, 4, true); LinkedList_add(reportElements, reason); LinkedList_add(deletableElements, reason); } else if (self->inclusionFlags[i] != REPORT_CONTROL_NONE) { MmsValue* reason = MmsValue_newBitString(6); switch(self->inclusionFlags[i]) { case REPORT_CONTROL_QUALITY_CHANGED: MmsValue_setBitStringBit(reason, 2, true); break; case REPORT_CONTROL_VALUE_CHANGED: MmsValue_setBitStringBit(reason, 1, true); break; case REPORT_CONTROL_VALUE_UPDATE: MmsValue_setBitStringBit(reason, 3, true); break; } LinkedList_add(reportElements, reason); LinkedList_add(deletableElements, reason); } } } /* clear inclusion flags */ for (i = 0; i < self->dataSet->elementCount; i++) { self->inclusionFlags[i] = REPORT_CONTROL_NONE; } MmsServerConnection_sendInformationReportVMDSpecific(self->clientConnection, "RPT", reportElements); /* Increase sequence number */ self->sqNum++; MmsValue_setUint16(sqNum, self->sqNum); LinkedList_destroyDeep(deletableElements, (LinkedListValueDeleteFunction) MmsValue_delete); LinkedList_destroyStatic(reportElements); /* clear GI flag */ if (isGI) { MmsValue* gi = ReportControl_getRCBValue(self, "GI"); self->gi = false; MmsValue_setBoolean(gi, false); } }
static MmsValue* parseAllDataUnknownValue(GooseSubscriber self, uint8_t* buffer, int allDataLength, bool isStructure) { int bufPos = 0; int elementLength = 0; int elementIndex = 0; MmsValue* dataSetValues = NULL; while (bufPos < allDataLength) { uint8_t tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength); if (bufPos + elementLength > allDataLength) { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n"); goto exit_with_error; } switch (tag) { case 0x80: /* reserved for access result */ break; case 0xa1: /* array */ break; case 0xa2: /* structure */ break; case 0x83: /* boolean */ break; case 0x84: /* BIT STRING */ break; case 0x85: /* integer */ break; case 0x86: /* unsigned integer */ break; case 0x87: /* Float */ break; case 0x89: /* octet string */ break; case 0x8a: /* visible string */ break; case 0x8c: /* binary time */ break; case 0x91: /* Utctime */ break; default: if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found unknown tag %02x\n", tag); goto exit_with_error; } bufPos += elementLength; elementIndex++; } if (isStructure) dataSetValues = MmsValue_createEmptyStructure(elementIndex); else dataSetValues = MmsValue_createEmptyArray(elementIndex); elementIndex = 0; bufPos = 0; while (bufPos < allDataLength) { uint8_t tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength); if (bufPos + elementLength > allDataLength) { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n"); goto exit_with_error; } MmsValue* value = NULL; switch (tag) { case 0xa1: /* array */ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found array\n"); value = parseAllDataUnknownValue(self, buffer + bufPos, elementLength, false); if (value == NULL) goto exit_with_error; break; case 0xa2: /* structure */ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found structure\n"); value = parseAllDataUnknownValue(self, buffer + bufPos, elementLength, true); if (value == NULL) goto exit_with_error; break; case 0x83: /* boolean */ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found boolean\n"); value = MmsValue_newBoolean(BerDecoder_decodeBoolean(buffer, bufPos)); break; case 0x84: /* BIT STRING */ { int padding = buffer[bufPos]; int bitStringLength = (8 * (elementLength - 1)) - padding; value = MmsValue_newBitString(bitStringLength); memcpy(value->value.bitString.buf, buffer + bufPos + 1, elementLength - 1); } break; case 0x85: /* integer */ value = MmsValue_newInteger(elementLength * 8); memcpy(value->value.integer->octets, buffer + bufPos, elementLength); value->value.integer->size = elementLength; break; case 0x86: /* unsigned integer */ value = MmsValue_newUnsigned(elementLength * 8); memcpy(value->value.integer->octets, buffer + bufPos, elementLength); value->value.integer->size = elementLength; break; case 0x87: /* Float */ if (elementLength == 9) value = MmsValue_newDouble(BerDecoder_decodeDouble(buffer, bufPos)); else if (elementLength == 5) value = MmsValue_newFloat(BerDecoder_decodeFloat(buffer, bufPos)); break; case 0x89: /* octet string */ value = MmsValue_newOctetString(elementLength, elementLength); memcpy(value->value.octetString.buf, buffer + bufPos, elementLength); break; case 0x8a: /* visible string */ value = MmsValue_newVisibleStringFromByteArray(buffer + bufPos, elementLength); break; case 0x8c: /* binary time */ if (elementLength == 4) value = MmsValue_newBinaryTime(true); else if (elementLength == 6) value = MmsValue_newBinaryTime(false); if ((elementLength == 4) || (elementLength == 6)) memcpy(value->value.binaryTime.buf, buffer + bufPos, elementLength); break; case 0x91: /* Utctime */ if (elementLength == 8) { value = MmsValue_newUtcTime(0); MmsValue_setUtcTimeByBuffer(value, buffer + bufPos); } else if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: UTCTime element is of wrong size!\n"); break; default: if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found unkown tag %02x\n", tag); goto exit_with_error; } bufPos += elementLength; if (value != NULL) { MmsValue_setElement(dataSetValues, elementIndex, value); elementIndex++; } } self->dataSetValuesSelfAllocated = true; return dataSetValues; exit_with_error: if (dataSetValues != NULL) MmsValue_delete(dataSetValues); return NULL; }