Example #1
0
/* 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;
}
Example #2
0
/* 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;
}
Example #3
0
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);
    }
}
Example #4
0
/* 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;
}
Example #6
0
/* 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;
}
Example #9
0
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;
}
Example #11
0
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;
}
Example #12
0
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;
}
Example #13
0
/* 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;
}
Example #14
0
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;
}
Example #15
0
/* 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;
}
Example #16
0
/** 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;
}
Example #17
0
/* 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;
}
Example #18
0
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);
}
Example #19
0
/**
 * 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;
}
Example #20
0
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;
}
Example #21
0
/** 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;
}
Example #22
0
/* 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;
}
Example #23
0
/* 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;
}
Example #24
0
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;
}
Example #25
0
/** 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;
}
Example #26
0
/*  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;
}
Example #27
0
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;
}
Example #29
0
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;
}