/* decode the service request only */ int whois_decode_service_request( uint8_t * apdu, unsigned apdu_len, int32_t * pLow_limit, int32_t * pHigh_limit) { int len = 0; uint8_t tag_number = 0; uint32_t len_value = 0; uint32_t decoded_value = 0; /* optional limits - must be used as a pair */ if (apdu_len) { len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); if (tag_number != 0) return -1; len += decode_unsigned(&apdu[len], len_value, &decoded_value); if (decoded_value <= BACNET_MAX_INSTANCE) { if (pLow_limit) *pLow_limit = decoded_value; } len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); if (tag_number != 1) return -1; len += decode_unsigned(&apdu[len], len_value, &decoded_value); if (decoded_value <= BACNET_MAX_INSTANCE) { if (pHigh_limit) *pHigh_limit = decoded_value; } } return len; }
/* decode the application class and code */ int bacerror_decode_error_class_and_code( uint8_t * apdu, unsigned apdu_len, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) { int len = 0; uint8_t tag_number = 0; uint32_t len_value_type = 0; uint32_t decoded_value = 0; if (apdu_len) { /* error class */ len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED) return 0; len += decode_enumerated(&apdu[len], len_value_type, &decoded_value); if (error_class) *error_class = (BACNET_ERROR_CLASS) decoded_value; /* error code */ len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED) return 0; len += decode_enumerated(&apdu[len], len_value_type, &decoded_value); if (error_code) *error_code = (BACNET_ERROR_CODE) decoded_value; } return len; }
void ProcessPTA( BACNET_PRIVATE_TRANSFER_DATA * data) { int iLen; /* Index to current location in data */ uint32_t uiErrorCode; char cBlockNumber; uint32_t ulTemp; int tag_len; uint8_t tag_number; uint32_t len_value_type; iLen = 0; /* Error code is returned for read and write operations */ tag_len = decode_tag_number_and_value(&data->serviceParameters[iLen], &tag_number, &len_value_type); iLen += tag_len; if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) { #if PRINT_ENABLED printf("CPTA: Bad Encoding!\n"); #endif return; } iLen += decode_unsigned(&data->serviceParameters[iLen], len_value_type, &uiErrorCode); if (data->serviceNumber == MY_SVC_READ) { /* Read I/O block so should be full block of data or error */ /* Decode the error type and if necessary block number and then fetch the info */ if (uiErrorCode == MY_ERR_OK) { /* Block Number */ tag_len = decode_tag_number_and_value(&data->serviceParameters[iLen], &tag_number, &len_value_type); iLen += tag_len; if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) { #if PRINT_ENABLED printf("CPTA: Bad Encoding!\n"); #endif return; } iLen += decode_unsigned(&data->serviceParameters[iLen], len_value_type, &ulTemp); cBlockNumber = (char) ulTemp; DecodeBlock(cBlockNumber, &data->serviceParameters[iLen]); } else { /* Read error */ printf("Private Transfer read operation returned error code: %u\n", uiErrorCode); return; } } else { /* Write I/O block - should just be an OK type message */ printf("Private Transfer write operation returned error code: %u\n", uiErrorCode); } }
/* decode the service request only */ int whohas_decode_service_request( uint8_t * apdu, unsigned apdu_len, BACNET_WHO_HAS_DATA * data) { int len = 0; uint8_t tag_number = 0; uint32_t len_value = 0; uint32_t decoded_value = 0; /* for decoding */ uint16_t decoded_type = 0; /* for decoding */ if (apdu_len && data) { /* optional limits - must be used as a pair */ if (decode_is_context_tag(&apdu[len], 0)) { len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); len += decode_unsigned(&apdu[len], len_value, &decoded_value); if (decoded_value <= BACNET_MAX_INSTANCE) data->low_limit = decoded_value; if (!decode_is_context_tag(&apdu[len], 1)) return -1; len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); len += decode_unsigned(&apdu[len], len_value, &decoded_value); if (decoded_value <= BACNET_MAX_INSTANCE) data->high_limit = decoded_value; } else { data->low_limit = -1; data->high_limit = -1; } /* object id */ if (decode_is_context_tag(&apdu[len], 2)) { data->object_name = false; len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); len += decode_object_id(&apdu[len], &decoded_type, &data->object.identifier.instance); data->object.identifier.type = decoded_type; } /* object name */ else if (decode_is_context_tag(&apdu[len], 3)) { data->object_name = true; len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); len += decode_character_string(&apdu[len], len_value, &data->object.name); } /* missing required parameters */ else return -1; } return len; }
/* decode the service request only */ int timesync_decode_service_request( uint8_t * apdu, unsigned apdu_len, BACNET_DATE * my_date, BACNET_TIME * my_time) { int len = 0; uint8_t tag_number = 0; uint32_t len_value = 0; if (apdu_len && my_date && my_time) { /* date */ len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); if (tag_number == BACNET_APPLICATION_TAG_DATE) { len += decode_date(&apdu[len], my_date); } else return -1; /* time */ len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); if (tag_number == BACNET_APPLICATION_TAG_TIME) { len += decode_bacnet_time(&apdu[len], my_time); } else return -1; } return len; }
/* decode the service request only */ int whois_decode_service_request( uint8_t * apdu, unsigned apdu_len, int32_t * pLow_limit, int32_t * pHigh_limit) { unsigned int len = 0; uint8_t tag_number = 0; uint32_t len_value = 0; uint32_t decoded_value = 0; /* optional limits - must be used as a pair */ if (apdu_len) { len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); if (tag_number != 0) { return BACNET_STATUS_ERROR; } if (apdu_len > (unsigned)len) { len += decode_unsigned(&apdu[len], len_value, &decoded_value); if (decoded_value <= BACNET_MAX_INSTANCE) { if (pLow_limit) { *pLow_limit = decoded_value; } } if (apdu_len > (unsigned)len) { len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); if (tag_number != 1) { return BACNET_STATUS_ERROR; } if (apdu_len > (unsigned)len) { len += decode_unsigned(&apdu[len], len_value, &decoded_value); if (decoded_value <= BACNET_MAX_INSTANCE) { if (pHigh_limit) { *pHigh_limit = decoded_value; } } } else { return BACNET_STATUS_ERROR; } } else { return BACNET_STATUS_ERROR; } } else { return BACNET_STATUS_ERROR; } } else { if (pLow_limit) { *pLow_limit = -1; } if (pHigh_limit) { *pHigh_limit = -1; } len = 0; } return (int)len; }
int rp_ack_decode_service_request( uint8_t * apdu, int apdu_len, /* total length of the apdu */ BACNET_READ_PROPERTY_DATA * rpdata) { uint8_t tag_number = 0; uint32_t len_value_type = 0; int tag_len = 0; /* length of tag decode */ int len = 0; /* total length of decodes */ uint16_t object = 0; /* object type */ uint32_t property = 0; /* for decoding */ uint32_t array_value = 0; /* for decoding */ memset(prop_name,0,100); /* FIXME: check apdu_len against the len during decode */ /* Tag 0: Object ID */ if (!decode_is_context_tag(&apdu[0], 0)) return -1; len = 1; len += decode_object_id(&apdu[len], &object, &rpdata->object_instance); rpdata->object_type = (BACNET_OBJECT_TYPE) object; /* Tag 1: Property ID */ len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); if (tag_number != 1) return -1; len += decode_enumerated(&apdu[len], len_value_type, &property); rpdata->object_property = (BACNET_PROPERTY_ID) property; if(rpdata->object_property < PROP_EGRESS_ACTIVE) strcpy_s(prop_name,100,bacnet_property_names[rpdata->object_property ].pString); /* Tag 2: Optional Array Index */ tag_len = decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); if (tag_number == 2) { len += tag_len; len += decode_unsigned(&apdu[len], len_value_type, &array_value); rpdata->array_index = array_value; } else rpdata->array_index = BACNET_ARRAY_ALL; /* Tag 3: opening context tag */ if (decode_is_opening_tag_number(&apdu[len], 3)) { /* a tag number of 3 is not extended so only one octet */ len++; /* don't decode the application tag number or its data here */ rpdata->application_data = &apdu[len]; rpdata->application_data_len = apdu_len - len - 1 /*closing tag */ ; /* len includes the data and the closing tag */ len = apdu_len; } else { return -1; } return len; }
/* decode the service request only */ int awf_ack_decode_service_request( uint8_t * apdu, unsigned apdu_len, BACNET_ATOMIC_WRITE_FILE_DATA * data) { int len = 0; uint8_t tag_number = 0; uint32_t len_value_type = 0; /* check for value pointers */ if (apdu_len && data) { len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value_type); if (tag_number == 0) { data->access = FILE_STREAM_ACCESS; len += decode_signed(&apdu[len], len_value_type, &data->type.stream.fileStartPosition); } else if (tag_number == 1) { data->access = FILE_RECORD_ACCESS; len += decode_signed(&apdu[len], len_value_type, &data->type.record.fileStartRecord); } else return -1; } return len; }
void testBinaryInput( Test * pTest) { uint8_t apdu[MAX_APDU] = { 0 }; int len = 0; uint32_t len_value = 0; uint8_t tag_number = 0; BACNET_OBJECT_TYPE decoded_type = OBJECT_BINARY_OUTPUT; uint32_t decoded_instance = 0; uint32_t instance = 123; BACNET_ERROR_CLASS error_class; BACNET_ERROR_CODE error_code; /* FIXME: we should do a lot more testing here... */ len = Binary_Input_Encode_Property_APDU(&apdu[0], instance, PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code); ct_test(pTest, len >= 0); len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value); ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID); len = decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance); ct_test(pTest, decoded_type == OBJECT_BINARY_INPUT); ct_test(pTest, decoded_instance == instance); return; }
void testBinary_Value( Test * pTest) { uint8_t apdu[MAX_APDU] = { 0 }; int len = 0; uint32_t len_value = 0; uint8_t tag_number = 0; uint16_t decoded_type = 0; uint32_t decoded_instance = 0; BACNET_READ_PROPERTY_DATA rpdata; Binary_Value_Init(); rpdata.application_data = &apdu[0]; rpdata.application_data_len = sizeof(apdu); rpdata.object_type = OBJECT_BINARY_VALUE; rpdata.object_instance = 1; rpdata.object_property = PROP_OBJECT_IDENTIFIER; rpdata.array_index = BACNET_ARRAY_ALL; len = Binary_Value_Read_Property(&rpdata); ct_test(pTest, len != 0); len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value); ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID); len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance); ct_test(pTest, decoded_type == rpdata.object_type); ct_test(pTest, decoded_instance == rpdata.object_instance); return; }
void testAnalog_Value( Test * pTest) { uint8_t far apdu[MAX_APDU] = { 0 }; int len = 0; uint32_t len_value = 0; uint8_t tag_number = 0; BACNET_OBJECT_TYPE decoded_type = OBJECT_ANALOG_VALUE; uint32_t decoded_instance = 0; uint32_t instance = 123; BACNET_ERROR_CLASS error_class; BACNET_ERROR_CODE error_code; len = Analog_Value_Encode_Property_APDU(&apdu[0], instance, PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code); ct_test(pTest, len != 0); len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value); ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID); len = decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance); ct_test(pTest, decoded_type == OBJECT_ANALOG_VALUE); ct_test(pTest, decoded_instance == instance); return; }
int rpm_ack_decode_object_property( uint8_t * apdu, unsigned apdu_len, BACNET_PROPERTY_ID * object_property, uint32_t * array_index) { unsigned len = 0; unsigned tag_len = 0; uint8_t tag_number = 0; uint32_t len_value_type = 0; uint32_t property = 0; /* for decoding */ uint32_t array_value = 0; /* for decoding */ /* check for valid pointers */ if (apdu && apdu_len && object_property && array_index) { /* Tag 2: propertyIdentifier */ if (!IS_CONTEXT_SPECIFIC(apdu[len])) return -1; len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); if (tag_number != 2) return -1; len += decode_enumerated(&apdu[len], len_value_type, &property); if (object_property) *object_property = (BACNET_PROPERTY_ID) property; /* Tag 3: Optional propertyArrayIndex */ if ((len < apdu_len) && IS_CONTEXT_SPECIFIC(apdu[len]) && (!IS_CLOSING_TAG(apdu[len]))) { tag_len = (unsigned) decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); if (tag_number == 3) { len += tag_len; len += decode_unsigned(&apdu[len], len_value_type, &array_value); *array_index = array_value; } else { *array_index = BACNET_ARRAY_ALL; } } else { *array_index = BACNET_ARRAY_ALL; } } return (int) len; }
/* decode the service request only */ int ihave_decode_service_request( uint8_t * apdu, unsigned apdu_len, BACNET_I_HAVE_DATA * data) { int len = 0; uint8_t tag_number = 0; uint32_t len_value = 0; uint16_t decoded_type = 0; /* for decoding */ if (apdu_len && data) { /* deviceIdentifier */ len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); if (tag_number == BACNET_APPLICATION_TAG_OBJECT_ID) { len += decode_object_id(&apdu[len], &decoded_type, &data->device_id.instance); data->device_id.type = decoded_type; } else return -1; /* objectIdentifier */ len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); if (tag_number == BACNET_APPLICATION_TAG_OBJECT_ID) { len += decode_object_id(&apdu[len], &decoded_type, &data->object_id.instance); data->object_id.type = decoded_type; } else return -1; /* objectName */ len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); if (tag_number == BACNET_APPLICATION_TAG_CHARACTER_STRING) { len += decode_character_string(&apdu[len], len_value, &data->object_name); } else return -1; } else return -1; return len; }
int Lighting_Output_Decode_Lighting_Command( uint8_t * apdu, unsigned apdu_max_len, BACNET_LIGHTING_COMMAND * data) { int len = 0; int apdu_len = 0; uint8_t tag_number = 0; uint32_t len_value_type = 0; float real_value = 0.0; apdu_max_len = apdu_max_len; /* check for value pointers */ if (apdu_len && data) { /* Tag 0: operation */ if (!decode_is_context_tag(&apdu[apdu_len], 0)) return -1; len = decode_tag_number_and_value(&apdu[apdu_len], &tag_number, &len_value_type); apdu_len += len; len = decode_enumerated(&apdu[apdu_len], len_value_type, (uint32_t *) & data->operation); apdu_len += len; /* Tag 1: level - OPTIONAL */ if (decode_is_context_tag(&apdu[apdu_len], 1)) { len = decode_tag_number_and_value(&apdu[apdu_len], &tag_number, &len_value_type); apdu_len += len; len = decode_real(&apdu[apdu_len], &real_value); apdu_len += len; data->level = (uint8_t) real_value; /* FIXME: are we going to flag errors in decoding values here? */ } /* FIXME: finish me! */ /* Tag 2: */ } return len; }
/* decode the service request only */ int rd_decode_service_request( uint8_t * apdu, unsigned apdu_len, BACNET_REINITIALIZED_STATE * state, BACNET_CHARACTER_STRING * password) { unsigned len = 0; uint8_t tag_number = 0; uint32_t len_value_type = 0; uint32_t value = 0; /* check for value pointers */ if (apdu_len) { /* Tag 0: reinitializedStateOfDevice */ if (!decode_is_context_tag(&apdu[len], 0)) return -1; len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); len += decode_enumerated(&apdu[len], len_value_type, &value); if (state) *state = (BACNET_REINITIALIZED_STATE) value; /* Tag 1: password - optional */ if (len < apdu_len) { if (!decode_is_context_tag(&apdu[len], 1)) return -1; len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); len += decode_character_string(&apdu[len], len_value_type, password); } } return (int) len; }
/** Decoding for WritePropertyMultiple service, object ID. * @ingroup DSWPM * This handler will be invoked by write_property_multiple handler * if it has been enabled by a call to apdu_set_confirmed_handler(). * This function decodes only the first tagged entity, which is * an object identifier. This function will return an error if: * - the tag is not the right value * - the number of bytes is not enough to decode for this entity * - the subsequent tag number is incorrect * * @param apdu [in] The contents of the APDU buffer. * @param apdu_len [in] The length of the APDU buffer. * @param data [out] The BACNET_WRITE_PROPERTY_DATA structure * which will contain the reponse values or error. */ int wpm_decode_object_id( uint8_t * apdu, uint16_t apdu_len, BACNET_WRITE_PROPERTY_DATA * wp_data) { uint8_t tag_number = 0; uint32_t len_value = 0; uint32_t object_instance = 0; uint16_t object_type = 0; uint16_t len = 0; if (apdu && (apdu_len > 5) && wp_data) { /* Context tag 0 - Object ID */ len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); if ((tag_number == 0) && (apdu_len > len)) { apdu_len -= len; if (apdu_len >= 4) { len += decode_object_id(&apdu[len], &object_type, &object_instance); wp_data->object_type = object_type; wp_data->object_instance = object_instance; apdu_len -= len; } else { wp_data->error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER; return BACNET_STATUS_REJECT; } } else { wp_data->error_code = ERROR_CODE_REJECT_INVALID_TAG; return BACNET_STATUS_REJECT; } /* just test for the next tag - no need to decode it here */ /* Context tag 1: sequence of BACnetPropertyValue */ if (apdu_len && !decode_is_opening_tag_number(&apdu[len], 1)) { wp_data->error_code = ERROR_CODE_REJECT_INVALID_TAG; return BACNET_STATUS_REJECT; } } else { wp_data->error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER; return BACNET_STATUS_REJECT; } return (int) len; }
/* decode the service request only */ int ptransfer_error_decode_service_request( uint8_t * apdu, unsigned apdu_len, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code, BACNET_PRIVATE_TRANSFER_DATA * private_data) { int len = 0; /* return value */ int decode_len = 0; /* return value */ uint8_t tag_number = 0; uint32_t len_value_type = 0; uint32_t unsigned_value = 0; /* check for value pointers */ if (apdu_len && private_data) { /* Tag 0: Error */ if (decode_is_opening_tag_number(&apdu[len], 0)) { /* a tag number of 0 is not extended so only one octet */ len++; /* error class */ decode_len = decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); len += decode_len; if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED) { return 0; } decode_len = decode_enumerated(&apdu[len], len_value_type, &unsigned_value); len += decode_len; if (error_class) { *error_class = (BACNET_ERROR_CLASS) unsigned_value; } /* error code */ decode_len = decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); len += decode_len; if (tag_number != BACNET_APPLICATION_TAG_ENUMERATED) { return 0; } decode_len = decode_enumerated(&apdu[len], len_value_type, &unsigned_value); len += decode_len; if (error_code) { *error_code = (BACNET_ERROR_CODE) unsigned_value; } if (decode_is_closing_tag_number(&apdu[len], 0)) { /* a tag number of 0 is not extended so only one octet */ len++; } else { return 0; } } /* Tag 1: vendorID */ decode_len = decode_context_unsigned(&apdu[len], 1, &unsigned_value); if (decode_len < 0) { return -1; } len += decode_len; private_data->vendorID = (uint16_t) unsigned_value; /* Tag 2: serviceNumber */ decode_len = decode_context_unsigned(&apdu[len], 2, &unsigned_value); if (decode_len < 0) { return -1; } len += decode_len; private_data->serviceNumber = unsigned_value; /* Tag 3: serviceParameters */ if (decode_is_opening_tag_number(&apdu[len], 3)) { /* a tag number of 2 is not extended so only one octet */ len++; /* don't decode the serviceParameters here */ private_data->serviceParameters = &apdu[len]; private_data->serviceParametersLen = (int) apdu_len - len - 1 /*closing tag */ ; } else { return -1; } /* we could check for a closing tag of 3 */ } return len; }
void DecodeBlock( char cBlockNum, uint8_t * pData) { int iLen; uint32_t ulTemp; int tag_len; uint8_t tag_number; uint32_t len_value_type; BACNET_CHARACTER_STRING bsName; DATABLOCK Response; iLen = 0; if (cBlockNum >= MY_MAX_BLOCK) return; tag_len = decode_tag_number_and_value(&pData[iLen], &tag_number, &len_value_type); iLen += tag_len; if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) return; iLen += decode_unsigned(&pData[iLen], len_value_type, &ulTemp); Response.cMyByte1 = (char) ulTemp; tag_len = decode_tag_number_and_value(&pData[iLen], &tag_number, &len_value_type); iLen += tag_len; if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) return; iLen += decode_unsigned(&pData[iLen], len_value_type, &ulTemp); Response.cMyByte2 = (char) ulTemp; tag_len = decode_tag_number_and_value(&pData[iLen], &tag_number, &len_value_type); iLen += tag_len; if (tag_number != BACNET_APPLICATION_TAG_REAL) return; iLen += decode_real(&pData[iLen], &Response.fMyReal); tag_len = decode_tag_number_and_value(&pData[iLen], &tag_number, &len_value_type); iLen += tag_len; if (tag_number != BACNET_APPLICATION_TAG_CHARACTER_STRING) return; iLen += decode_character_string(&pData[iLen], len_value_type, &bsName); strncpy(Response.sMyString, characterstring_value(&bsName), MY_MAX_STR); Response.sMyString[MY_MAX_STR] = '\0'; /* Make sure it is nul terminated */ printf("Private Transfer Read Block Response\n"); printf("Data Block: %d\n", (int) cBlockNum); printf(" First Byte : %d\n", (int) Response.cMyByte1); printf(" Second Byte : %d\n", (int) Response.cMyByte2); printf(" Real : %f\n", Response.fMyReal); printf(" String : %s\n\n", Response.sMyString); }
/** * Decodes from bytes into the lighting-command structure * * @param apdu - buffer to hold the bytes * @param apdu_max_len - number of bytes in the buffer to decode * @param value - lighting command value to place the decoded values * * @return number of bytes encoded */ int lighting_command_decode( uint8_t * apdu, unsigned apdu_max_len, BACNET_LIGHTING_COMMAND * data) { int len = 0; int apdu_len = 0; uint8_t tag_number = 0; uint32_t len_value_type = 0; uint32_t unsigned_value = 0; float real_value = 0.0; unused_var(apdu_max_len); /* check for value pointers */ if (apdu_max_len && data) { /* Tag 0: operation */ if (!decode_is_context_tag(&apdu[apdu_len], 0)) return BACNET_STATUS_ERROR; len = decode_tag_number_and_value(&apdu[apdu_len], &tag_number, &len_value_type); apdu_len += len; len = decode_enumerated(&apdu[apdu_len], len_value_type, &unsigned_value); if (len > 0) { data->operation = unsigned_value; } apdu_len += len; /* Tag 1: target-level - OPTIONAL */ if (decode_is_context_tag(&apdu[apdu_len], 1)) { len = decode_tag_number_and_value(&apdu[apdu_len], &tag_number, &len_value_type); apdu_len += len; len = decode_real(&apdu[apdu_len], &real_value); data->target_level = real_value; apdu_len += len; data->use_target_level = true; } else { data->use_target_level = false; } /* Tag 2: ramp-rate - OPTIONAL */ if (decode_is_context_tag(&apdu[apdu_len], 2)) { len = decode_tag_number_and_value(&apdu[apdu_len], &tag_number, &len_value_type); apdu_len += len; len = decode_real(&apdu[apdu_len], &real_value); data->ramp_rate = real_value; data->use_ramp_rate = true; } else { data->use_ramp_rate = false; } /* Tag 3: step-increment - OPTIONAL */ if (decode_is_context_tag(&apdu[apdu_len], 3)) { len = decode_tag_number_and_value(&apdu[apdu_len], &tag_number, &len_value_type); apdu_len += len; len = decode_real(&apdu[apdu_len], &real_value); data->step_increment = real_value; data->use_step_increment = true; } else { data->use_step_increment = false; } /* Tag 4: fade-time - OPTIONAL */ if (decode_is_context_tag(&apdu[apdu_len], 4)) { len = decode_tag_number_and_value(&apdu[apdu_len], &tag_number, &len_value_type); apdu_len += len; len = decode_unsigned(&apdu[apdu_len], len_value_type, &unsigned_value); data->fade_time = unsigned_value; data->use_fade_time = true; } else { data->use_fade_time = false; } /* Tag 5: priority - OPTIONAL */ if (decode_is_context_tag(&apdu[apdu_len], 4)) { len = decode_tag_number_and_value(&apdu[apdu_len], &tag_number, &len_value_type); apdu_len += len; len = decode_unsigned(&apdu[apdu_len], len_value_type, &unsigned_value); data->priority = unsigned_value; data->use_priority = true; } else { data->use_priority = false; } } return len; }
static void ProcessPT( BACNET_PRIVATE_TRANSFER_DATA * data) { int iLen; /* Index to current location in data */ char cBlockNumber; uint32_t ulTemp; int tag_len; uint8_t tag_number; uint32_t len_value_type; BACNET_CHARACTER_STRING bsTemp; iLen = 0; /* Decode the block number */ tag_len = decode_tag_number_and_value(&data->serviceParameters[iLen], &tag_number, &len_value_type); iLen += tag_len; if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) { /* Bail out early if wrong type */ /* and signal unexpected error */ data->serviceParametersLen = 0; return; } iLen += decode_unsigned(&data->serviceParameters[iLen], len_value_type, &ulTemp); cBlockNumber = (char) ulTemp; if (cBlockNumber < MY_MAX_BLOCK) { if (data->serviceNumber == MY_SVC_READ) { /* Read Response is an unsigned int with 0 for success or a non 0 error code For a successful read the 0 success code is followed by the block number and then the block contents which consist of 2 unsigned ints (in 0 to 255 range as they are really chars) a single precision real and a string which will be up to 32 chars + a nul */ iLen = 0; /* Signal success */ iLen += encode_application_unsigned(&IOBufferPT[iLen], MY_ERR_OK); /* Followed by the block number */ iLen += encode_application_unsigned(&IOBufferPT[iLen], cBlockNumber); /* And Then the block contents */ iLen += encode_application_unsigned(&IOBufferPT[iLen], MyData[(int8_t) cBlockNumber].cMyByte1); iLen += encode_application_unsigned(&IOBufferPT[iLen], MyData[(int8_t) cBlockNumber].cMyByte2); iLen += encode_application_real(&IOBufferPT[iLen], MyData[(int8_t) cBlockNumber].fMyReal); characterstring_init_ansi(&bsTemp, (char *) MyData[(int8_t) cBlockNumber].sMyString); iLen += encode_application_character_string(&IOBufferPT[iLen], &bsTemp); } else { /* Write operation */ /* Write block consists of the block number followed by the block contents as described above for the read operation. The returned result is an unsigned response which is 0 for success and a non 0 error code otherwise. */ tag_len = decode_tag_number_and_value(&data->serviceParameters[iLen], &tag_number, &len_value_type); iLen += tag_len; if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) { data->serviceParametersLen = 0; return; } iLen += decode_unsigned(&data->serviceParameters[iLen], len_value_type, &ulTemp); MyData[(int8_t) cBlockNumber].cMyByte1 = (char) ulTemp; tag_len = decode_tag_number_and_value(&data->serviceParameters[iLen], &tag_number, &len_value_type); iLen += tag_len; if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) { data->serviceParametersLen = 0; return; } iLen += decode_unsigned(&data->serviceParameters[iLen], len_value_type, &ulTemp); MyData[(int8_t) cBlockNumber].cMyByte2 = (char) ulTemp; tag_len = decode_tag_number_and_value(&data->serviceParameters[iLen], &tag_number, &len_value_type); iLen += tag_len; if (tag_number != BACNET_APPLICATION_TAG_REAL) { data->serviceParametersLen = 0; return; } iLen += decode_real(&data->serviceParameters[iLen], &MyData[(int8_t) cBlockNumber].fMyReal); tag_len = decode_tag_number_and_value(&data->serviceParameters[iLen], &tag_number, &len_value_type); iLen += tag_len; if (tag_number != BACNET_APPLICATION_TAG_CHARACTER_STRING) { data->serviceParametersLen = 0; return; } decode_character_string(&data->serviceParameters[iLen], len_value_type, &bsTemp); /* Only copy as much as we can accept */ strncpy((char *) MyData[(int8_t) cBlockNumber].sMyString, characterstring_value(&bsTemp), MY_MAX_STR); /* Make sure it is nul terminated */ MyData[(int8_t) cBlockNumber].sMyString[MY_MAX_STR] = '\0'; /* Signal success */ iLen = encode_application_unsigned(&IOBufferPT[0], MY_ERR_OK); } } else { /* Signal bad index */ iLen = encode_application_unsigned(&IOBufferPT[0], MY_ERR_BAD_INDEX); } data->serviceParametersLen = iLen; data->serviceParameters = IOBufferPT; }
/** Process the APDU header and invoke the appropriate service handler * to manage the received request. * Almost all requests and ACKs invoke this function. * @ingroup MISCHNDLR * * @param src [in] The BACNET_ADDRESS of the message's source. * @param apdu [in] The apdu portion of the request, to be processed. * @param apdu_len [in] The total (remaining) length of the apdu. */ void apdu_handler( BACNET_ADDRESS * src, uint8_t * apdu, /* APDU data */ uint16_t apdu_len) { BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 }; BACNET_CONFIRMED_SERVICE_ACK_DATA service_ack_data = { 0 }; //uint8_t invoke_id = 0; uint8_t service_choice = 0; uint8_t *service_request = NULL; uint16_t service_request_len = 0; int len = 0; /* counts where we are in PDU */ uint8_t tag_number = 0; uint32_t len_value = 0; uint32_t error_code = 0; uint32_t error_class = 0; // uint8_t reason = 0; // bool server = false; if (apdu) { /* PDU Type */ switch (apdu[0] & 0xF0) { case PDU_TYPE_CONFIRMED_SERVICE_REQUEST: len = (int) apdu_decode_confirmed_service_request(&apdu[0], apdu_len, &service_data, &service_choice, &service_request, &service_request_len); #if 0 if (apdu_confirmed_dcc_disabled(service_choice)) { tbd: chelsea /* When network communications are completely disabled, only DeviceCommunicationControl and ReinitializeDevice APDUs shall be processed and no messages shall be initiated. */ break; } if ((service_choice < MAX_BACNET_CONFIRMED_SERVICE) && (Confirmed_Function[service_choice])) Confirmed_Function[service_choice] (service_request, service_request_len/*, src, &service_data*/); else if (Unrecognized_Service_Handler) Unrecognized_Service_Handler(service_request, service_request_len/*, src, &service_data*/); #endif // #if READ_WRITE_PROPERTY #if 1 if (service_choice == SERVICE_CONFIRMED_READ_PROPERTY) { handler_read_property(service_request, service_request_len, src, &service_data); } else if (service_choice == SERVICE_CONFIRMED_WRITE_PROPERTY) { handler_write_property(service_request, service_request_len, src, &service_data); } else #endif if (service_choice == SERVICE_CONFIRMED_PRIVATE_TRANSFER) { handler_private_transfer(apdu,apdu_len,src); // add private transfer by chelsea } else { handler_unrecognized_service(service_request, service_request_len, src, &service_data); } break; case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST: { //U8_T i; service_choice = apdu[1]; service_request = &apdu[2]; service_request_len = apdu_len - 2; #if 0 if (apdu_unconfirmed_dcc_disabled(service_choice)) { /* When network communications are disabled, only DeviceCommunicationControl and ReinitializeDevice APDUs shall be processed and no messages shall be initiated. If communications have been initiation disabled, then WhoIs may be processed. */ break; } if (service_choice < MAX_BACNET_UNCONFIRMED_SERVICE) { if (Unconfirmed_Function[service_choice]) Unconfirmed_Function[service_choice] ( service_request, service_request_len/*, src*/); // tbd: chelsea } #endif if (service_choice == SERVICE_UNCONFIRMED_WHO_IS) { if( modbus.protocal == BAC_MSTP) { handler_who_is(service_request, service_request_len, src); } else if((modbus.protocal == BAC_IP) || (modbus.protocal == BAC_GSM)) { Send_I_Am(&Handler_Transmit_Buffer[0]); } } else if (service_choice == SERVICE_UNCONFIRMED_PRIVATE_TRANSFER) { // add unconfirmedPrivateTransfer handler, for TEMCO private handler_private_transfer(apdu,apdu_len,src); } } break; case PDU_TYPE_SIMPLE_ACK: // invoke_id = apdu[1]; service_choice = apdu[2]; switch (service_choice) { case SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM: case SERVICE_CONFIRMED_COV_NOTIFICATION: case SERVICE_CONFIRMED_EVENT_NOTIFICATION: case SERVICE_CONFIRMED_SUBSCRIBE_COV: case SERVICE_CONFIRMED_SUBSCRIBE_COV_PROPERTY: case SERVICE_CONFIRMED_LIFE_SAFETY_OPERATION: /* Object Access Services */ case SERVICE_CONFIRMED_ADD_LIST_ELEMENT: case SERVICE_CONFIRMED_REMOVE_LIST_ELEMENT: case SERVICE_CONFIRMED_DELETE_OBJECT: case SERVICE_CONFIRMED_WRITE_PROPERTY: case SERVICE_CONFIRMED_WRITE_PROP_MULTIPLE: /* Remote Device Management Services */ case SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL: case SERVICE_CONFIRMED_REINITIALIZE_DEVICE: case SERVICE_CONFIRMED_TEXT_MESSAGE: /* Virtual Terminal Services */ case SERVICE_CONFIRMED_VT_CLOSE: /* Security Services */ case SERVICE_CONFIRMED_REQUEST_KEY: if (Confirmed_ACK_Function[service_choice] != NULL) { // tbd: chelsea // ((confirmed_simple_ack_function) // Confirmed_ACK_Function[service_choice]) (src, // invoke_id); } // tsm_free_invoke_id(invoke_id); break; default: break; } break; case PDU_TYPE_COMPLEX_ACK: service_ack_data.segmented_message = (apdu[0] & BIT3) ? true : false; service_ack_data.more_follows = (apdu[0] & BIT2) ? true : false; // invoke_id = service_ack_data.invoke_id = apdu[1]; len = 2; if (service_ack_data.segmented_message) { service_ack_data.sequence_number = apdu[len++]; service_ack_data.proposed_window_number = apdu[len++]; } service_choice = apdu[len++]; service_request = &apdu[len]; service_request_len = apdu_len - (uint16_t) len; switch (service_choice) { case SERVICE_CONFIRMED_GET_ALARM_SUMMARY: case SERVICE_CONFIRMED_GET_ENROLLMENT_SUMMARY: case SERVICE_CONFIRMED_GET_EVENT_INFORMATION: /* File Access Services */ case SERVICE_CONFIRMED_ATOMIC_READ_FILE: case SERVICE_CONFIRMED_ATOMIC_WRITE_FILE: /* Object Access Services */ case SERVICE_CONFIRMED_CREATE_OBJECT: case SERVICE_CONFIRMED_READ_PROPERTY: case SERVICE_CONFIRMED_READ_PROP_CONDITIONAL: case SERVICE_CONFIRMED_READ_PROP_MULTIPLE: case SERVICE_CONFIRMED_READ_RANGE: case SERVICE_CONFIRMED_PRIVATE_TRANSFER: /* Virtual Terminal Services */ case SERVICE_CONFIRMED_VT_OPEN: case SERVICE_CONFIRMED_VT_DATA: /* Security Services */ case SERVICE_CONFIRMED_AUTHENTICATE: if (Confirmed_ACK_Function[service_choice] != NULL) { // (Confirmed_ACK_Function[service_choice]) // (service_request, service_request_len/*, src, // &service_ack_data*/); // tbd: chelsea } // tsm_free_invoke_id(invoke_id); break; default: break; } break; case PDU_TYPE_SEGMENT_ACK: /* FIXME: what about a denial of service attack here? we could check src to see if that matched the tsm */ // tsm_free_invoke_id(invoke_id); break; case PDU_TYPE_ERROR: // invoke_id = apdu[1]; service_choice = apdu[2]; len = 3; /* FIXME: Currently special case for C_P_T but there are others which may need consideration such as ChangeList-Error, CreateObject-Error, WritePropertyMultiple-Error and VTClose_Error but they may be left as is for now until support for these services is added */ if (service_choice == SERVICE_CONFIRMED_PRIVATE_TRANSFER) { /* skip over opening tag 0 */ if (decode_is_opening_tag_number(&apdu[len], 0)) { len++; /* a tag number of 0 is not extended so only one octet */ } } len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); /* FIXME: we could validate that the tag is enumerated... */ len += decode_enumerated(&apdu[len], len_value, &error_class); len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); /* FIXME: we could validate that the tag is enumerated... */ len += decode_enumerated(&apdu[len], len_value, &error_code); if (service_choice == SERVICE_CONFIRMED_PRIVATE_TRANSFER) { /* skip over closing tag 0 */ if (decode_is_closing_tag_number(&apdu[len], 0)) { len++; /* a tag number of 0 is not extended so only one octet */ } } if (service_choice < MAX_BACNET_CONFIRMED_SERVICE) { // if (Error_Function[service_choice]) // Error_Function[service_choice] (src, invoke_id/*, // (BACNET_ERROR_CLASS) error_class, // (BACNET_ERROR_CODE) error_code*/); // tbd: chelsea } // tsm_free_invoke_id(invoke_id); break; case PDU_TYPE_REJECT: // invoke_id = apdu[1]; // reason = apdu[2]; // if (Reject_Function) // Reject_Function(src, invoke_id, reason); // tsm_free_invoke_id(invoke_id); break; case PDU_TYPE_ABORT: // server = apdu[0] & 0x01; // invoke_id = apdu[1]; // reason = apdu[2]; // if (Abort_Function) // Abort_Function(src, invoke_id, reason, server); // tsm_free_invoke_id(invoke_id); break; default: break; } memset(Handler_Transmit_Buffer,0,MAX_PDU); //printf("apdu_done\r\n"); } return; }
/* FIXME: there could be various error messages returned using unique values less than zero */ int wp_decode_service_request( uint8_t * apdu, unsigned apdu_len, BACNET_WRITE_PROPERTY_DATA * wpdata) { int len = 0; int tag_len = 0; uint8_t tag_number = 0; uint32_t len_value_type = 0; uint16_t type = 0; /* for decoding */ uint32_t property = 0; /* for decoding */ uint32_t unsigned_value = 0; int i = 0; /* loop counter */ /* check for value pointers */ if (apdu_len && wpdata) { /* Tag 0: Object ID */ if (!decode_is_context_tag(&apdu[len++], 0)) return -1; len += decode_object_id(&apdu[len], &type, &wpdata->object_instance); wpdata->object_type = (BACNET_OBJECT_TYPE) type; /* Tag 1: Property ID */ len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); if (tag_number != 1) return -1; len += decode_enumerated(&apdu[len], len_value_type, &property); wpdata->object_property = (BACNET_PROPERTY_ID) property; /* Tag 2: Optional Array Index */ /* note: decode without incrementing len so we can check for opening tag */ tag_len = decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); if (tag_number == 2) { len += tag_len; len += decode_unsigned(&apdu[len], len_value_type, &unsigned_value); wpdata->array_index = unsigned_value; } else wpdata->array_index = BACNET_ARRAY_ALL; /* Tag 3: opening context tag */ if (!decode_is_opening_tag_number(&apdu[len], 3)) return -1; /* determine the length of the data blob */ wpdata->application_data_len = bacapp_data_len(&apdu[len], apdu_len - len, (BACNET_PROPERTY_ID) property); /* a tag number of 3 is not extended so only one octet */ len++; /* copy the data from the APDU */ for (i = 0; i < wpdata->application_data_len; i++) { wpdata->application_data[i] = apdu[len + i]; } /* add on the data length */ len += wpdata->application_data_len; if (!decode_is_closing_tag_number(&apdu[len], 3)) return -2; /* a tag number of 3 is not extended so only one octet */ len++; /* Tag 4: optional Priority - assumed MAX if not explicitly set */ wpdata->priority = BACNET_MAX_PRIORITY; if ((unsigned) len < apdu_len) { tag_len = decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); if (tag_number == 4) { len += tag_len; len = decode_unsigned(&apdu[len], len_value_type, &unsigned_value); if ((unsigned_value >= BACNET_MIN_PRIORITY) && (unsigned_value <= BACNET_MAX_PRIORITY)) { wpdata->priority = (uint8_t) unsigned_value; } else return -5; } } } return len; }
/* decode the service request only */ int rp_decode_service_request( uint8_t * apdu, unsigned apdu_len, BACNET_READ_PROPERTY_DATA * rpdata) { unsigned len = 0; uint8_t tag_number = 0; uint32_t len_value_type = 0; uint16_t type = 0; /* for decoding */ uint32_t property = 0; /* for decoding */ uint32_t array_value = 0; /* for decoding */ /* check for value pointers */ if (rpdata != NULL) { /* Must have at least 2 tags, an object id and a property identifier * of at least 1 byte in length to have any chance of parsing */ if (apdu_len < 7) { rpdata->error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER; return BACNET_STATUS_REJECT; } /* Tag 0: Object ID */ if (!decode_is_context_tag(&apdu[len++], 0)) { rpdata->error_code = ERROR_CODE_REJECT_INVALID_TAG; return BACNET_STATUS_REJECT; } len += decode_object_id(&apdu[len], &type, &rpdata->object_instance); rpdata->object_type = (BACNET_OBJECT_TYPE) type; /* Tag 1: Property ID */ len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); if (tag_number != 1) { rpdata->error_code = ERROR_CODE_REJECT_INVALID_TAG; return BACNET_STATUS_REJECT; } len += decode_enumerated(&apdu[len], len_value_type, &property); rpdata->object_property = (BACNET_PROPERTY_ID) property; /* Tag 2: Optional Array Index */ if (len < apdu_len) { len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); if ((tag_number == 2) && (len < apdu_len)) { len += decode_unsigned(&apdu[len], len_value_type, &array_value); rpdata->array_index = array_value; } else { rpdata->error_code = ERROR_CODE_REJECT_INVALID_TAG; return BACNET_STATUS_REJECT; } } else rpdata->array_index = BACNET_ARRAY_ALL; } if (len < apdu_len) { /* If something left over now, we have an invalid request */ rpdata->error_code = ERROR_CODE_REJECT_TOO_MANY_ARGUMENTS; return BACNET_STATUS_REJECT; } return (int) len; }
int bacapp_decode_property_state( uint8_t * apdu, BACNET_PROPERTY_STATE * value) { int len = 0; uint32_t len_value_type; int section_length; uint32_t enumValue; section_length = decode_tag_number_and_value(&apdu[len], (uint8_t *) & value->tag, &len_value_type); if (-1 == section_length) { return -1; } len += section_length; switch (value->tag) { case BOOLEAN_VALUE: value->state.booleanValue = decode_boolean(len_value_type); break; case BINARY_VALUE: if (-1 == (section_length = decode_enumerated(&apdu[len], len_value_type, &enumValue))) { return -1; } value->state.binaryValue = (BACNET_BINARY_PV) enumValue; break; case EVENT_TYPE: if (-1 == (section_length = decode_enumerated(&apdu[len], len_value_type, &enumValue))) { return -1; } value->state.eventType = (BACNET_EVENT_TYPE) enumValue; break; case POLARITY: if (-1 == (section_length = decode_enumerated(&apdu[len], len_value_type, &enumValue))) { return -1; } value->state.polarity = (BACNET_POLARITY) enumValue; break; case PROGRAM_CHANGE: if (-1 == (section_length = decode_enumerated(&apdu[len], len_value_type, &enumValue))) { return -1; } value->state.programChange = (BACNET_PROGRAM_REQUEST) enumValue; break; case PROGRAM_STATE: if (-1 == (section_length = decode_enumerated(&apdu[len], len_value_type, &enumValue))) { return -1; } value->state.programState = (BACNET_PROGRAM_STATE) enumValue; break; case REASON_FOR_HALT: if (-1 == (section_length = decode_enumerated(&apdu[len], len_value_type, &enumValue))) { return -1; } value->state.programError = (BACNET_PROGRAM_ERROR) enumValue; break; case RELIABILITY: if (-1 == (section_length = decode_enumerated(&apdu[len], len_value_type, &enumValue))) { return -1; } value->state.reliability = (BACNET_RELIABILITY) enumValue; break; case STATE: if (-1 == (section_length = decode_enumerated(&apdu[len], len_value_type, &enumValue))) { return -1; } value->state.state = (BACNET_EVENT_STATE) enumValue; break; case SYSTEM_STATUS: if (-1 == (section_length = decode_enumerated(&apdu[len], len_value_type, &enumValue))) { return -1; } value->state.systemStatus = (BACNET_DEVICE_STATUS) enumValue; break; case UNITS: if (-1 == (section_length = decode_enumerated(&apdu[len], len_value_type, &enumValue))) { return -1; } value->state.units = (BACNET_ENGINEERING_UNITS) enumValue; break; case UNSIGNED_VALUE: if (-1 == (section_length = decode_unsigned(&apdu[len], len_value_type, &value->state.unsignedValue))) { return -1; } break; case LIFE_SAFETY_MODE: if (-1 == (section_length = decode_enumerated(&apdu[len], len_value_type, &enumValue))) { return -1; } value->state.lifeSafetyMode = (BACNET_LIFE_SAFETY_MODE) enumValue; break; case LIFE_SAFETY_STATE: if (-1 == (section_length = decode_enumerated(&apdu[len], len_value_type, &enumValue))) { return -1; } value->state.lifeSafetyState = (BACNET_LIFE_SAFETY_STATE) enumValue; break; default: return -1; } len += section_length; return len; }
/** Decode the received RPM data and make a linked list of the results. * @ingroup DSRPM * * @param apdu [in] The received apdu data. * @param apdu_len [in] Total length of the apdu. * @param read_access_data [out] Pointer to the head of the linked list * where the RPM data is to be stored. * @return The number of bytes decoded, or -1 on error */ int rpm_ack_decode_service_request( uint8_t * apdu, int apdu_len, BACNET_READ_ACCESS_DATA * read_access_data) { int decoded_len = 0; /* return value */ uint32_t error_value = 0; /* decoded error value */ int len = 0; /* number of bytes returned from decoding */ uint8_t tag_number = 0; /* decoded tag number */ uint32_t len_value = 0; /* decoded length value */ BACNET_READ_ACCESS_DATA *rpm_object; BACNET_READ_ACCESS_DATA *old_rpm_object; BACNET_PROPERTY_REFERENCE *rpm_property; BACNET_PROPERTY_REFERENCE *old_rpm_property; BACNET_APPLICATION_DATA_VALUE *value; BACNET_APPLICATION_DATA_VALUE *old_value; assert(read_access_data != NULL); rpm_object = read_access_data; old_rpm_object = rpm_object; while (rpm_object && apdu_len) { len = rpm_ack_decode_object_id(apdu, apdu_len, &rpm_object->object_type, &rpm_object->object_instance); if (len <= 0) { old_rpm_object->next = NULL; free(rpm_object); break; } decoded_len += len; apdu_len -= len; apdu += len; rpm_property = calloc(1, sizeof(BACNET_PROPERTY_REFERENCE)); rpm_object->listOfProperties = rpm_property; old_rpm_property = rpm_property; while (rpm_property && apdu_len) { len = rpm_ack_decode_object_property(apdu, apdu_len, &rpm_property->propertyIdentifier, &rpm_property->propertyArrayIndex); if (len <= 0) { old_rpm_property->next = NULL; if (rpm_object->listOfProperties == rpm_property) { /* was this the only property in the list? */ rpm_object->listOfProperties = NULL; } free(rpm_property); break; } decoded_len += len; apdu_len -= len; apdu += len; if (apdu_len && decode_is_opening_tag_number(apdu, 4)) { /* propertyValue */ decoded_len++; apdu_len--; apdu++; /* note: if this is an array, there will be more than one element to decode */ value = calloc(1, sizeof(BACNET_APPLICATION_DATA_VALUE)); rpm_property->value = value; old_value = value; while (value && (apdu_len > 0)) { if (IS_CONTEXT_SPECIFIC(*apdu)) { len = bacapp_decode_context_data(apdu, apdu_len, value, rpm_property->propertyIdentifier); } else { len = bacapp_decode_application_data(apdu, apdu_len, value); } /* If len == 0 then it's an empty structure, which is OK. */ if (len < 0) { /* problem decoding */ /* calling function will free the memory */ return BACNET_STATUS_ERROR; } decoded_len += len; apdu_len -= len; apdu += len; if (apdu_len && decode_is_closing_tag_number(apdu, 4)) { decoded_len++; apdu_len--; apdu++; break; } else { old_value = value; value = calloc(1, sizeof(BACNET_APPLICATION_DATA_VALUE)); old_value->next = value; } } } else if (apdu_len && decode_is_opening_tag_number(apdu, 5)) { /* propertyAccessError */ decoded_len++; apdu_len--; apdu++; /* decode the class and code sequence */ len = decode_tag_number_and_value(apdu, &tag_number, &len_value); decoded_len += len; apdu_len -= len; apdu += len; /* FIXME: we could validate that the tag is enumerated... */ len = decode_enumerated(apdu, len_value, &error_value); rpm_property->error.error_class = error_value; decoded_len += len; apdu_len -= len; apdu += len; len = decode_tag_number_and_value(apdu, &tag_number, &len_value); decoded_len += len; apdu_len -= len; apdu += len; /* FIXME: we could validate that the tag is enumerated... */ len = decode_enumerated(apdu, len_value, &error_value); rpm_property->error.error_code = error_value; decoded_len += len; apdu_len -= len; apdu += len; if (apdu_len && decode_is_closing_tag_number(apdu, 5)) { decoded_len++; apdu_len--; apdu++; } } old_rpm_property = rpm_property; rpm_property = calloc(1, sizeof(BACNET_PROPERTY_REFERENCE)); old_rpm_property->next = rpm_property; } len = rpm_decode_object_end(apdu, apdu_len); if (len) { decoded_len += len; apdu_len -= len; apdu += len; } if (apdu_len) { old_rpm_object = rpm_object; rpm_object = calloc(1, sizeof(BACNET_READ_ACCESS_DATA)); old_rpm_object->next = rpm_object; } } return decoded_len; }
/* BACnetPropertyReference ::= SEQUENCE { propertyIdentifier [0] BACnetPropertyIdentifier, propertyArrayIndex [1] Unsigned OPTIONAL --used only with array datatype -- if omitted with an array the entire array is referenced } */ int rpm_decode_object_property( uint8_t * apdu, unsigned apdu_len, BACNET_RPM_DATA * rpmdata) { unsigned len = 0; unsigned option_len = 0; uint8_t tag_number = 0; uint32_t len_value_type = 0; uint32_t property = 0; /* for decoding */ uint32_t array_value = 0; /* for decoding */ /* check for valid pointers */ if (apdu && apdu_len && rpmdata) { /* Tag 0: propertyIdentifier */ if (!IS_CONTEXT_SPECIFIC(apdu[len])) { rpmdata->error_code = ERROR_CODE_REJECT_INVALID_TAG; return BACNET_STATUS_REJECT; } len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); if (tag_number != 0) { rpmdata->error_code = ERROR_CODE_REJECT_INVALID_TAG; return BACNET_STATUS_REJECT; } /* Should be at least the unsigned value + 1 tag left */ if ((len + len_value_type) >= apdu_len) { rpmdata->error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER; return BACNET_STATUS_REJECT; } len += decode_enumerated(&apdu[len], len_value_type, &property); rpmdata->object_property = (BACNET_PROPERTY_ID) property; /* Assume most probable outcome */ rpmdata->array_index = BACNET_ARRAY_ALL; /* Tag 1: Optional propertyArrayIndex */ if (IS_CONTEXT_SPECIFIC(apdu[len]) && !IS_CLOSING_TAG(apdu[len])) { option_len = (unsigned) decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); if (tag_number == 1) { len += option_len; /* Should be at least the unsigned array index + 1 tag left */ if ((len + len_value_type) >= apdu_len) { rpmdata->error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER; return BACNET_STATUS_REJECT; } len += decode_unsigned(&apdu[len], len_value_type, &array_value); rpmdata->array_index = array_value; } } } return (int) len; }
int wpm_decode_object_property( uint8_t * apdu, uint16_t apdu_len, BACNET_WRITE_PROPERTY_DATA * wp_data) { uint8_t tag_number = 0; uint32_t len_value = 0; uint32_t ulVal = 0; int len = 0, i = 0; if ((apdu) && (apdu_len) && (wp_data)) { wp_data->array_index = BACNET_ARRAY_ALL; wp_data->priority = BACNET_MAX_PRIORITY; wp_data->application_data_len = 0; /* tag 0 - Property Identifier */ len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); if (tag_number == 0) { len += decode_enumerated(&apdu[len], len_value, &ulVal); wp_data->object_property = ulVal; } else { wp_data->error_code = ERROR_CODE_REJECT_INVALID_TAG; return BACNET_STATUS_REJECT; } /* tag 1 - Property Array Index - optional */ len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); if (tag_number == 1) { len += decode_unsigned(&apdu[len], len_value, &ulVal); wp_data->array_index = ulVal; len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); } /* tag 2 - Property Value */ if ((tag_number == 2) && (decode_is_opening_tag(&apdu[len - 1]))) { len--; wp_data->application_data_len = bacapp_data_len(&apdu[len], (unsigned) (apdu_len - len), wp_data->object_property); len++; /* copy application data */ for (i = 0; i < wp_data->application_data_len; i++) { wp_data->application_data[i] = apdu[len + i]; } len += wp_data->application_data_len; len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); /* closing tag 2 */ if ((tag_number != 2) && (decode_is_closing_tag(&apdu[len - 1]))) { wp_data->error_code = ERROR_CODE_REJECT_INVALID_TAG; return BACNET_STATUS_REJECT; } } else { wp_data->error_code = ERROR_CODE_REJECT_INVALID_TAG; return BACNET_STATUS_REJECT; } /* tag 3 - Priority - optional */ len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); if (tag_number == 3) { len += decode_unsigned(&apdu[len], len_value, &ulVal); wp_data->priority = ulVal; } else len--; } else { wp_data->error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER; return BACNET_STATUS_REJECT; } return len; }
/* decode the service request only */ int arf_ack_decode_service_request( uint8_t * apdu, unsigned apdu_len, BACNET_ATOMIC_READ_FILE_DATA * data) { int len = 0; int tag_len = 0; uint8_t tag_number = 0; uint32_t len_value_type = 0; /* check for value pointers */ if (apdu_len && data) { len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value_type); if (tag_number != BACNET_APPLICATION_TAG_BOOLEAN) return -1; data->endOfFile = decode_boolean(len_value_type); if (decode_is_opening_tag_number(&apdu[len], 0)) { data->access = FILE_STREAM_ACCESS; /* a tag number is not extended so only one octet */ len++; /* fileStartPosition */ tag_len = decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); len += tag_len; if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT) return -1; len += decode_signed(&apdu[len], len_value_type, &data->type.stream.fileStartPosition); /* fileData */ tag_len = decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); len += tag_len; if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING) return -1; len += decode_octet_string(&apdu[len], len_value_type, &data->fileData); if (!decode_is_closing_tag_number(&apdu[len], 0)) return -1; /* a tag number is not extended so only one octet */ len++; } else if (decode_is_opening_tag_number(&apdu[len], 1)) { data->access = FILE_RECORD_ACCESS; /* a tag number is not extended so only one octet */ len++; /* fileStartRecord */ tag_len = decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); len += tag_len; if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT) return -1; len += decode_signed(&apdu[len], len_value_type, &data->type.record.fileStartRecord); /* returnedRecordCount */ tag_len = decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); len += tag_len; if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) return -1; len += decode_unsigned(&apdu[len], len_value_type, &data->type.record.RecordCount); /* fileData */ tag_len = decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); len += tag_len; if (tag_number != BACNET_APPLICATION_TAG_OCTET_STRING) return -1; len += decode_octet_string(&apdu[len], len_value_type, &data->fileData); if (!decode_is_closing_tag_number(&apdu[len], 1)) return -1; /* a tag number is not extended so only one octet */ len++; } else return -1; } return len; }
int bacapp_decode_timestamp( uint8_t * apdu, BACNET_TIMESTAMP * value) { int len = 0; int section_len; uint32_t len_value_type; uint32_t sequenceNum; if (apdu) { section_len = decode_tag_number_and_value(&apdu[len], &value->tag, &len_value_type); if (-1 == section_len) { return -1; } switch (value->tag) { case TIME_STAMP_TIME: if ((section_len = decode_context_bacnet_time(&apdu[len], TIME_STAMP_TIME, &value->value.time)) == -1) { return -1; } else { len += section_len; } break; case TIME_STAMP_SEQUENCE: if ((section_len = decode_context_unsigned(&apdu[len], TIME_STAMP_SEQUENCE, &sequenceNum)) == -1) { return -1; } else { if (sequenceNum <= 0xffff) { len += section_len; value->value.sequenceNum = (uint16_t) sequenceNum; } else { return -1; } } break; case TIME_STAMP_DATETIME: if ((section_len = bacapp_decode_context_datetime(&apdu[len], TIME_STAMP_DATETIME, &value->value.dateTime)) == -1) { return -1; } else { len += section_len; } break; default: return -1; } } return len; }
/* decode the service request only */ int arf_decode_service_request( uint8_t * apdu, unsigned apdu_len, BACNET_ATOMIC_READ_FILE_DATA * data) { int len = 0; int tag_len = 0; uint8_t tag_number = 0; uint32_t len_value_type = 0; uint16_t type = 0; /* for decoding */ /* check for value pointers */ if (apdu_len && data) { len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value_type); if (tag_number != BACNET_APPLICATION_TAG_OBJECT_ID) return -1; len += decode_object_id(&apdu[len], &type, &data->object_instance); data->object_type = (BACNET_OBJECT_TYPE) type; if (decode_is_opening_tag_number(&apdu[len], 0)) { data->access = FILE_STREAM_ACCESS; /* a tag number is not extended so only one octet */ len++; /* fileStartPosition */ tag_len = decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); len += tag_len; if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT) return -1; len += decode_signed(&apdu[len], len_value_type, &data->type.stream.fileStartPosition); /* requestedOctetCount */ tag_len = decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); len += tag_len; if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) return -1; len += decode_unsigned(&apdu[len], len_value_type, &data->type.stream.requestedOctetCount); if (!decode_is_closing_tag_number(&apdu[len], 0)) return -1; /* a tag number is not extended so only one octet */ len++; } else if (decode_is_opening_tag_number(&apdu[len], 1)) { data->access = FILE_RECORD_ACCESS; /* a tag number is not extended so only one octet */ len++; /* fileStartRecord */ tag_len = decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); len += tag_len; if (tag_number != BACNET_APPLICATION_TAG_SIGNED_INT) return -1; len += decode_signed(&apdu[len], len_value_type, &data->type.record.fileStartRecord); /* RecordCount */ tag_len = decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); len += tag_len; if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) return -1; len += decode_unsigned(&apdu[len], len_value_type, &data->type.record.RecordCount); if (!decode_is_closing_tag_number(&apdu[len], 1)) return -1; /* a tag number is not extended so only one octet */ len++; } else return -1; } return len; }