コード例 #1
0
ファイル: bactimevalue.c プロジェクト: aniston/node-bacnet
int bacapp_decode_context_time_value(uint8_t * apdu,
    uint8_t tag_number,
    BACNET_TIME_VALUE * value)
{
    int len = 0;
    int section_length;

    if (decode_is_opening_tag_number(&apdu[len], tag_number))
        len++;
    else
        return -1;

    section_length = bacapp_decode_time_value(&apdu[len], value);
    if (section_length > 0)
        len += section_length;
    else
        return -1;

    if (decode_is_closing_tag_number(&apdu[len], tag_number))
        len++;
    else
        return -1;

    return len;
}
コード例 #2
0
int bacapp_decode_context_assigned_access_rights(
    uint8_t * apdu,
    uint8_t tag,
    BACNET_ASSIGNED_ACCESS_RIGHTS * aar)
{
    int len = 0;
    int section_length;

    if (decode_is_opening_tag_number(&apdu[len], tag)) {
        len++;
        section_length = bacapp_decode_assigned_access_rights(&apdu[len], aar);

        if (section_length == -1) {
            len = -1;
        } else {
            len += section_length;
            if (decode_is_closing_tag_number(&apdu[len], tag)) {
                len++;
            } else {
                len = -1;
            }
        }
    } else {
        len = -1;
    }
    return len;
}
コード例 #3
0
ファイル: access_rule.c プロジェクト: empeeoh/BACnet
int bacapp_decode_context_access_rule(
    uint8_t * apdu,
    uint8_t tag_number,
    BACNET_ACCESS_RULE * rule)
{
    int len = 0;
    int section_length;

    if (decode_is_opening_tag_number(&apdu[len], tag_number)) {
        len++;
        section_length = bacapp_decode_access_rule(&apdu[len], rule);

        if (section_length == -1) {
            len = -1;
        } else {
            len += section_length;
            if (decode_is_closing_tag_number(&apdu[len], tag_number)) {
                len++;
            } else {
                len = -1;
            }
        }
    } else {
        len = -1;
    }
    return len;
}
コード例 #4
0
ファイル: bacpropstates.c プロジェクト: beh9540/bacnetwx2
int bacapp_decode_context_property_state(
    uint8_t * apdu,
    uint8_t tag_number,
    BACNET_PROPERTY_STATE * value)
{
    int len = 0;
    int section_length;

    if (decode_is_opening_tag_number(&apdu[len], tag_number)) {
        len++;
        section_length = bacapp_decode_property_state(&apdu[len], value);

        if (section_length == -1) {
            len = -1;
        } else {
            len += section_length;
            if (decode_is_closing_tag_number(&apdu[len], tag_number)) {
                len++;
            } else {
                len = -1;
            }
        }
    } else {
        len = -1;
    }
    return len;
}
コード例 #5
0
int bacapp_decode_context_device_obj_ref(
    uint8_t * apdu,
    uint8_t tag_number,
    BACNET_DEVICE_OBJECT_REFERENCE * value)
{
    int len = 0;
    int section_length;

    if (decode_is_opening_tag_number(&apdu[len], tag_number)) {
        len++;
        section_length = bacapp_decode_device_obj_ref(&apdu[len], value);

        if (section_length == -1) {
            len = -1;
        } else {
            len += section_length;
            if (decode_is_closing_tag_number(&apdu[len], tag_number)) {
                len++;
            } else {
                len = -1;
            }
        }
    } else {
        len = -1;
    }
    return len;
}
コード例 #6
0
ファイル: datetime.c プロジェクト: 8bitgeek/bacnet-stack
int bacapp_decode_context_datetime(
    uint8_t * apdu,
    uint8_t tag_number,
    BACNET_DATE_TIME * value)
{
    int apdu_len = 0;
    int len;

    if (decode_is_opening_tag_number(&apdu[apdu_len], tag_number)) {
        apdu_len++;
    } else {
        return -1;
    }

    if (-1 == (len = bacapp_decode_datetime(&apdu[apdu_len], value))) {
        return -1;
    } else {
        apdu_len += len;
    }

    if (decode_is_closing_tag_number(&apdu[apdu_len], tag_number)) {
        apdu_len++;
    } else {
        return -1;
    }
    return apdu_len;
}
コード例 #7
0
ファイル: rpm.c プロジェクト: TemcoHeng/Bacnet_Modbus_Gateway
/* is this the end of the list of this objects properties values? */
int rpm_ack_decode_object_end(
    uint8_t * apdu,
    unsigned apdu_len)
{
    int len = 0;        /* total length of the apdu, return value */

    if (apdu && apdu_len) {
        if (decode_is_closing_tag_number(apdu, 1))
            len = 1;
    }

    return len;
}
コード例 #8
0
ファイル: timestamp.c プロジェクト: HITliuyu/NES15_HEVC
int bacapp_decode_context_timestamp(
    uint8_t * apdu,
    uint8_t tag_number,
    BACNET_TIMESTAMP * value)
{
    int len = 0;
    int section_len;


    if (decode_is_opening_tag_number(&apdu[len], tag_number)) {
        len++;
        section_len = bacapp_decode_timestamp(&apdu[len], value);
        if (section_len > 0) {
            len += section_len;
            if (decode_is_closing_tag_number(&apdu[len], tag_number)) {
                len++;
            } else {
                return -1;
            }
        }
    }
    return len;
}
コード例 #9
0
/* 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;
}
コード例 #10
0
/* 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;
}
コード例 #11
0
ファイル: ptransfer.c プロジェクト: stargieg/bacnet-stack
/* 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;
}
コード例 #12
0
ファイル: h_rpm_a.c プロジェクト: 8bitgeek/bacnet-stack
/** 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;
}
コード例 #13
0
ファイル: rpm.c プロジェクト: TemcoHeng/Bacnet_Modbus_Gateway
void testReadPropertyMultipleAck(
    Test * pTest)
{
    uint8_t apdu[480] = { 0 };
    int len = 0;
    int test_len = 0;
    int apdu_len = 0;
    uint8_t invoke_id = 12;
    uint8_t test_invoke_id = 0;
    uint8_t *service_request = NULL;
    unsigned service_request_len = 0;
    BACNET_OBJECT_TYPE object_type = OBJECT_DEVICE;
    uint32_t object_instance = 0;
    BACNET_PROPERTY_ID object_property = PROP_OBJECT_IDENTIFIER;
    uint32_t array_index = 0;
    BACNET_APPLICATION_DATA_VALUE application_data[4] = { {0} };
    BACNET_APPLICATION_DATA_VALUE test_application_data = { 0 };
    uint8_t application_data_buffer[MAX_APDU] = { 0 };
    int application_data_buffer_len = 0;
    BACNET_ERROR_CLASS error_class;
    BACNET_ERROR_CODE error_code;
    BACNET_RPM_DATA rpmdata;

    /* build the RPM - try to make it easy for the
       Application Layer development */
    /* IDEA: similar construction, but pass apdu, apdu_len pointer,
       size of apdu to let the called function handle the out of
       space problem that these get into  by returning a boolean
       of success/failure.
       It almost needs to use the keylist library or something similar.
       Also check case of storing a backoff point
       (i.e. save enough room for object_end) */
    apdu_len = rpm_ack_encode_apdu_init(&apdu[0], invoke_id);
    /* object beginning */
    rpmdata.object_type = OBJECT_DEVICE;
    rpmdata.object_instance = 123;
    apdu_len += rpm_ack_encode_apdu_object_begin(&apdu[apdu_len], &rpmdata);
    /* reply property */
    apdu_len +=
        rpm_ack_encode_apdu_object_property(&apdu[apdu_len],
        PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL);
    /* reply value */
    application_data[0].tag = BACNET_APPLICATION_TAG_OBJECT_ID;
    application_data[0].type.Object_Id.type = OBJECT_DEVICE;
    application_data[0].type.Object_Id.instance = 123;
    application_data_buffer_len =
        bacapp_encode_application_data(&application_data_buffer[0],
        &application_data[0]);
    apdu_len +=
        rpm_ack_encode_apdu_object_property_value(&apdu[apdu_len],
        &application_data_buffer[0], application_data_buffer_len);
    /* reply property */
    apdu_len +=
        rpm_ack_encode_apdu_object_property(&apdu[apdu_len], PROP_OBJECT_TYPE,
        BACNET_ARRAY_ALL);
    /* reply value */
    application_data[1].tag = BACNET_APPLICATION_TAG_ENUMERATED;
    application_data[1].type.Enumerated = OBJECT_DEVICE;
    application_data_buffer_len =
        bacapp_encode_application_data(&application_data_buffer[0],
        &application_data[1]);
    apdu_len +=
        rpm_ack_encode_apdu_object_property_value(&apdu[apdu_len],
        &application_data_buffer[0], application_data_buffer_len);
    /* object end */
    apdu_len += rpm_ack_encode_apdu_object_end(&apdu[apdu_len]);

    /* object beginning */
    rpmdata.object_type = OBJECT_ANALOG_INPUT;
    rpmdata.object_instance = 33;
    apdu_len += rpm_ack_encode_apdu_object_begin(&apdu[apdu_len], &rpmdata);
    /* reply property */
    apdu_len +=
        rpm_ack_encode_apdu_object_property(&apdu[apdu_len],
        PROP_PRESENT_VALUE, BACNET_ARRAY_ALL);
    /* reply value */
    application_data[2].tag = BACNET_APPLICATION_TAG_REAL;
    application_data[2].type.Real = 0.0;
    application_data_buffer_len =
        bacapp_encode_application_data(&application_data_buffer[0],
        &application_data[2]);
    apdu_len +=
        rpm_ack_encode_apdu_object_property_value(&apdu[apdu_len],
        &application_data_buffer[0], application_data_buffer_len);
    /* reply property */
    apdu_len +=
        rpm_ack_encode_apdu_object_property(&apdu[apdu_len], PROP_DEADBAND,
        BACNET_ARRAY_ALL);
    /* reply error */
    apdu_len +=
        rpm_ack_encode_apdu_object_property_error(&apdu[apdu_len],
        ERROR_CLASS_PROPERTY, ERROR_CODE_UNKNOWN_PROPERTY);
    /* object end */
    apdu_len += rpm_ack_encode_apdu_object_end(&apdu[apdu_len]);
    ct_test(pTest, apdu_len != 0);

  /****** decode the packet ******/
    test_len = rpm_ack_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &service_request,       /* will point to the service request in the apdu */
        &service_request_len);
    ct_test(pTest, test_len != -1);
    ct_test(pTest, test_invoke_id == invoke_id);
    ct_test(pTest, service_request != NULL);
    ct_test(pTest, service_request_len > 0);
    /* the first part should be the first object id */
    test_len =
        rpm_ack_decode_object_id(service_request, service_request_len,
        &object_type, &object_instance);
    ct_test(pTest, test_len != -1);
    ct_test(pTest, object_type == OBJECT_DEVICE);
    ct_test(pTest, object_instance == 123);
    len = test_len;
    /* extract the property */
    test_len =
        rpm_ack_decode_object_property(&service_request[len],
        service_request_len - len, &object_property, &array_index);
    ct_test(pTest, object_property == PROP_OBJECT_IDENTIFIER);
    ct_test(pTest, array_index == BACNET_ARRAY_ALL);
    len += test_len;
    /* what is the result? An error or a value? */
    ct_test(pTest, decode_is_opening_tag_number(&service_request[len], 4));
    len++;
    /* decode the object property portion of the service request */
    /* note: if this was an array, there could have been
       more than one element to decode */
    test_len =
        bacapp_decode_application_data(&service_request[len],
        service_request_len - len, &test_application_data);
    ct_test(pTest, test_len > 0);
    ct_test(pTest, bacapp_same_value(&application_data[0],
            &test_application_data));
    len += test_len;
    ct_test(pTest, decode_is_closing_tag_number(&service_request[len], 4));
    len++;
    /* see if there is another property */
    test_len =
        rpm_ack_decode_object_property(&service_request[len],
        service_request_len - len, &object_property, &array_index);
    ct_test(pTest, test_len != -1);
    ct_test(pTest, object_property == PROP_OBJECT_TYPE);
    ct_test(pTest, array_index == BACNET_ARRAY_ALL);
    len += test_len;
    /* what is the result value? */
    ct_test(pTest, decode_is_opening_tag_number(&service_request[len], 4));
    len++;
    /* decode the object property portion of the service request */
    test_len =
        bacapp_decode_application_data(&service_request[len],
        service_request_len - len, &test_application_data);
    ct_test(pTest, test_len > 0);
    ct_test(pTest, bacapp_same_value(&application_data[1],
            &test_application_data));
    len += test_len;
    ct_test(pTest, decode_is_closing_tag_number(&service_request[len], 4));
    len++;
    /* see if there is another property */
    /* this time we should fail */
    test_len =
        rpm_ack_decode_object_property(&service_request[len],
        service_request_len - len, &object_property, &array_index);
    ct_test(pTest, test_len == -1);
    /* see if it is the end of this object */
    test_len =
        rpm_ack_decode_object_end(&service_request[len],
        service_request_len - len);
    ct_test(pTest, test_len == 1);
    len += test_len;
    /* try to decode another object id */
    test_len =
        rpm_ack_decode_object_id(&service_request[len],
        service_request_len - len, &object_type, &object_instance);
    ct_test(pTest, test_len != -1);
    ct_test(pTest, object_type == OBJECT_ANALOG_INPUT);
    ct_test(pTest, object_instance == 33);
    len += test_len;
    /* decode the object property portion of the service request only */
    test_len =
        rpm_ack_decode_object_property(&service_request[len],
        service_request_len - len, &object_property, &array_index);
    ct_test(pTest, test_len != -1);
    ct_test(pTest, object_property == PROP_PRESENT_VALUE);
    ct_test(pTest, array_index == BACNET_ARRAY_ALL);
    len += test_len;
    /* what is the result value? */
    ct_test(pTest, decode_is_opening_tag_number(&service_request[len], 4));
    len++;
    /* decode the object property portion of the service request */
    test_len =
        bacapp_decode_application_data(&service_request[len],
        service_request_len - len, &test_application_data);
    ct_test(pTest, test_len > 0);
    ct_test(pTest, bacapp_same_value(&application_data[2],
            &test_application_data));
    len += test_len;
    ct_test(pTest, decode_is_closing_tag_number(&service_request[len], 4));
    len++;
    /* see if there is another property */
    test_len =
        rpm_ack_decode_object_property(&service_request[len],
        service_request_len - len, &object_property, &array_index);
    ct_test(pTest, test_len != -1);
    ct_test(pTest, object_property == PROP_DEADBAND);
    ct_test(pTest, array_index == BACNET_ARRAY_ALL);
    len += test_len;
    /* what is the result value? */
    ct_test(pTest, decode_is_opening_tag_number(&service_request[len], 5));
    len++;
    /* it was an error reply */
    test_len =
        bacerror_decode_error_class_and_code(&service_request[len],
        service_request_len - len, &error_class, &error_code);
    ct_test(pTest, test_len != 0);
    ct_test(pTest, error_class == ERROR_CLASS_PROPERTY);
    ct_test(pTest, error_code == ERROR_CODE_UNKNOWN_PROPERTY);
    len += test_len;
    ct_test(pTest, decode_is_closing_tag_number(&service_request[len], 5));
    len++;
    /* is there another property? */
    test_len =
        rpm_ack_decode_object_property(&service_request[len],
        service_request_len - len, &object_property, &array_index);
    ct_test(pTest, test_len == -1);
    /* got an error -1, is it the end of this object? */
    test_len =
        rpm_ack_decode_object_end(&service_request[len],
        service_request_len - len);
    ct_test(pTest, test_len == 1);
    len += test_len;
    /* check for another object */
    test_len =
        rpm_ack_decode_object_id(&service_request[len],
        service_request_len - len, &object_type, &object_instance);
    ct_test(pTest, test_len == 0);
    ct_test(pTest, len == service_request_len);
}
コード例 #14
0
ファイル: wp.c プロジェクト: TemcoHeng/Bacnet_Modbus_Gateway
/* 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;
}
コード例 #15
0
ファイル: apdu.c プロジェクト: TemcoEvan/T3-Modules
/** 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;
}
コード例 #16
0
ファイル: h_rp_a.c プロジェクト: aniston/node-bacnet
/** Decode the received RP data into a linked list of the results, with the
 *  same data structure used by RPM ACK replies.
 *  This function is provided to provide common handling for RP and RPM data,
 *  and fully decodes the value(s) portion of the data for one property.
 * @ingroup DSRP
 * @see rp_ack_decode_service_request(), rpm_ack_decode_service_request()
 *
 * @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 RP data is to be stored.
 * @return Number of decoded bytes (could be less than apdu_len),
 * 			or -1 on decoding error.
 */
int rp_ack_fully_decode_service_request(
    uint8_t * apdu,
    int apdu_len,
    BACNET_READ_ACCESS_DATA * read_access_data)
{
    int decoded_len = 0;        /* return value */
    BACNET_READ_PROPERTY_DATA rp1data;
    BACNET_PROPERTY_REFERENCE *rp1_property;    /* single property */
    BACNET_APPLICATION_DATA_VALUE *value, *old_value;
    uint8_t *vdata;
    int vlen, len;

    decoded_len = rp_ack_decode_service_request(apdu, apdu_len, &rp1data);
    if (decoded_len > 0) {
        /* Then we have to transfer to the BACNET_READ_ACCESS_DATA structure
         * and decode the value(s) portion
         */
        read_access_data->object_type = rp1data.object_type;
        read_access_data->object_instance = rp1data.object_instance;
        rp1_property = calloc(1, sizeof(BACNET_PROPERTY_REFERENCE));
        read_access_data->listOfProperties = rp1_property;
        if (rp1_property == NULL) {
            /* can't proceed if calloc failed. */
            return BACNET_STATUS_ERROR;
        }
        rp1_property->propertyIdentifier = rp1data.object_property;
        rp1_property->propertyArrayIndex = rp1data.array_index;
        /* Is there no Error case possible here, as there is when decoding RPM? */
        /* rp1_property->error.error_class = ?? */
        /* rp_ack_decode_service_request() processing already removed the
         * Opening and Closing '3' Tags.
         * note: if this is an array, there will be
         more than one element to decode */
        vdata = rp1data.application_data;
        vlen = rp1data.application_data_len;
        value = calloc(1, sizeof(BACNET_APPLICATION_DATA_VALUE));
        rp1_property->value = value;
        old_value = value;
        while (value && vdata && (vlen > 0)) {
            if (IS_CONTEXT_SPECIFIC(*vdata)) {
                len =
                    bacapp_decode_context_data(vdata, vlen, value,
                                               rp1_property->propertyIdentifier);
            } else {
                len = bacapp_decode_application_data(vdata, vlen, value);
            }
            if (len < 0) {
                /* unable to decode the data */
                while (value) {
                    /* free the linked list of values */
                    old_value = value;
                    value = value->next;
                    free(old_value);
                }
                free(rp1_property);
                read_access_data->listOfProperties = NULL;
                return len;
            }
            decoded_len += len;
            vlen -= len;
            vdata += len;
            /* If unexpected closing tag here: */
            if (vlen && decode_is_closing_tag_number(vdata, 3)) {
                decoded_len++;
                vlen--;
                vdata++;
                break;
            } else {
                if (len == 0) {
                    /* nothing decoded and no closing tag, so malformed */
                    while (value) {
                        /* free the linked list of values */
                        old_value = value;
                        value = value->next;
                        free(old_value);
                    }
                    free(rp1_property);
                    read_access_data->listOfProperties = NULL;
                    return BACNET_STATUS_ERROR;
                }
                if (vlen > 0) {
                    /* If more values */
                    old_value = value;
                    value = calloc(1, sizeof(BACNET_APPLICATION_DATA_VALUE));
                    old_value->next = value;
                }
            }
        }
    }

    return decoded_len;
}
コード例 #17
0
/** Handler for a ReadPropertyMultiple Service request.
 * @ingroup DSRPM
 * This handler will be invoked by apdu_handler() if it has been enabled
 * by a call to apdu_set_confirmed_handler().
 * This handler builds a response packet, which is
 * - an Abort if
 *   - the message is segmented
 *   - if decoding fails
 *   - if the response would be too large
 * - the result from each included read request, if it succeeds
 * - an Error if processing fails for all, or individual errors if only some fail,
 *   or there isn't enough room in the APDU to fit the data.
 *
 * @param service_request [in] The contents of the service request.
 * @param service_len [in] The length of the service_request.
 * @param src [in] BACNET_ADDRESS of the source of the message
 * @param service_data [in] The BACNET_CONFIRMED_SERVICE_DATA information
 *                          decoded from the APDU header of this message.
 */
void handler_read_property_multiple(
    uint8_t * service_request,
    uint16_t service_len,
    BACNET_ADDRESS * src,
    BACNET_CONFIRMED_SERVICE_DATA * service_data)
{
    int len = 0;
    uint16_t copy_len = 0;
    uint16_t decode_len = 0;
    int pdu_len = 0;
    BACNET_NPDU_DATA npdu_data;
    int bytes_sent;
    BACNET_ADDRESS my_address;
    BACNET_RPM_DATA rpmdata;
    int apdu_len = 0;
    int npdu_len = 0;
    int error = 0;

    /* jps_debug - see if we are utilizing all the buffer */
    /* memset(&Handler_Transmit_Buffer[0], 0xff, sizeof(Handler_Transmit_Buffer)); */
    /* encode the NPDU portion of the packet */
    datalink_get_my_address(&my_address);
    npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
    npdu_len =
        npdu_encode_pdu(&Handler_Transmit_Buffer[0], src, &my_address,
                        &npdu_data);
    if (service_data->segmented_message) {
        rpmdata.error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
        error = BACNET_STATUS_ABORT;
#if PRINT_ENABLED
        fprintf(stderr, "RPM: Segmented message. Sending Abort!\r\n");
#endif
        goto RPM_FAILURE;
    }
    /* decode apdu request & encode apdu reply
       encode complex ack, invoke id, service choice */
    apdu_len =
        rpm_ack_encode_apdu_init(&Handler_Transmit_Buffer[npdu_len],
                                 service_data->invoke_id);
    for (;;) {
        /* Start by looking for an object ID */
        len =
            rpm_decode_object_id(&service_request[decode_len],
                                 service_len - decode_len, &rpmdata);
        if (len >= 0) {
            /* Got one so skip to next stage */
            decode_len += len;
        } else {
            /* bad encoding - skip to error/reject/abort handling */
#if PRINT_ENABLED
            fprintf(stderr, "RPM: Bad Encoding.\n");
#endif
            error = len;
            goto RPM_FAILURE;
        }

        /* Test for case of indefinite Device object instance */
        if ((rpmdata.object_type == OBJECT_DEVICE) &&
                (rpmdata.object_instance == BACNET_MAX_INSTANCE)) {
            rpmdata.object_instance = Device_Object_Instance_Number();
        }

        /* Stick this object id into the reply - if it will fit */
        len = rpm_ack_encode_apdu_object_begin(&Temp_Buf[0], &rpmdata);
        copy_len =
            memcopy(&Handler_Transmit_Buffer[npdu_len], &Temp_Buf[0], apdu_len,
                    len, MAX_APDU);
        if (copy_len == 0) {
#if PRINT_ENABLED
            fprintf(stderr, "RPM: Response too big!\r\n");
#endif
            rpmdata.error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
            error = BACNET_STATUS_ABORT;
            goto RPM_FAILURE;
        }

        apdu_len += copy_len;
        /* do each property of this object of the RPM request */
        for (;;) {
            /* Fetch a property */
            len =
                rpm_decode_object_property(&service_request[decode_len],
                                           service_len - decode_len, &rpmdata);
            if (len < 0) {
                /* bad encoding - skip to error/reject/abort handling */
#if PRINT_ENABLED
                fprintf(stderr, "RPM: Bad Encoding.\n");
#endif
                error = len;
                goto RPM_FAILURE;
            }
            decode_len += len;
            /* handle the special properties */
            if ((rpmdata.object_property == PROP_ALL) ||
                    (rpmdata.object_property == PROP_REQUIRED) ||
                    (rpmdata.object_property == PROP_OPTIONAL)) {
                struct special_property_list_t property_list;
                unsigned property_count = 0;
                unsigned index = 0;
                BACNET_PROPERTY_ID special_object_property;

                if (rpmdata.array_index != BACNET_ARRAY_ALL) {
                    /*  No array index options for this special property.
                       Encode error for this object property response */
                    len =
                        rpm_ack_encode_apdu_object_property(&Temp_Buf[0],
                                                            rpmdata.object_property, rpmdata.array_index);
                    copy_len =
                        memcopy(&Handler_Transmit_Buffer[npdu_len],
                                &Temp_Buf[0], apdu_len, len, MAX_APDU);
                    if (copy_len == 0) {
#if PRINT_ENABLED
                        fprintf(stderr,
                                "RPM: Too full to encode property!\r\n");
#endif
                        rpmdata.error_code =
                            ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
                        error = BACNET_STATUS_ABORT;
                        goto RPM_FAILURE;
                    }
                    apdu_len += len;
                    len =
                        rpm_ack_encode_apdu_object_property_error(&Temp_Buf[0],
                                ERROR_CLASS_PROPERTY,
                                ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY);
                    copy_len =
                        memcopy(&Handler_Transmit_Buffer[npdu_len],
                                &Temp_Buf[0], apdu_len, len, MAX_APDU);
                    if (copy_len == 0) {
#if PRINT_ENABLED
                        fprintf(stderr, "RPM: Too full to encode error!\r\n");
#endif
                        rpmdata.error_code =
                            ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
                        error = BACNET_STATUS_ABORT;
                        goto RPM_FAILURE;
                    }
                    apdu_len += len;
                } else {
                    special_object_property = rpmdata.object_property;
                    Device_Objects_Property_List(rpmdata.object_type,
                                                 &property_list);
                    property_count =
                        RPM_Object_Property_Count(&property_list,
                                                  special_object_property);
                    if (property_count == 0) {
                        /* handle the error code - but use the special property */
                        len =
                            RPM_Encode_Property(&Handler_Transmit_Buffer
                                                [npdu_len], (uint16_t) apdu_len, MAX_APDU,
                                                &rpmdata);
                        if (len > 0) {
                            apdu_len += len;
                        } else {
#if PRINT_ENABLED
                            fprintf(stderr,
                                    "RPM: Too full for special property!\r\n");
#endif
                            error = len;
                            goto RPM_FAILURE;
                        }
                    } else {
                        for (index = 0; index < property_count; index++) {
                            rpmdata.object_property =
                                RPM_Object_Property(&property_list,
                                                    special_object_property, index);
                            len =
                                RPM_Encode_Property(&Handler_Transmit_Buffer
                                                    [npdu_len], (uint16_t) apdu_len, MAX_APDU,
                                                    &rpmdata);
                            if (len > 0) {
                                apdu_len += len;
                            } else {
#if PRINT_ENABLED
                                fprintf(stderr,
                                        "RPM: Too full for property!\r\n");
#endif
                                error = len;
                                goto RPM_FAILURE;
                            }
                        }
                    }
                }
            } else {
                /* handle an individual property */
                len =
                    RPM_Encode_Property(&Handler_Transmit_Buffer[npdu_len],
                                        (uint16_t) apdu_len, MAX_APDU, &rpmdata);
                if (len > 0) {
                    apdu_len += len;
                } else {
#if PRINT_ENABLED
                    fprintf(stderr,
                            "RPM: Too full for individual property!\r\n");
#endif
                    error = len;
                    goto RPM_FAILURE;
                }
            }
            if (decode_is_closing_tag_number(&service_request[decode_len], 1)) {
                /* Reached end of property list so cap the result list */
                decode_len++;
                len = rpm_ack_encode_apdu_object_end(&Temp_Buf[0]);
                copy_len =
                    memcopy(&Handler_Transmit_Buffer[npdu_len], &Temp_Buf[0],
                            apdu_len, len, MAX_APDU);
                if (copy_len == 0) {
#if PRINT_ENABLED
                    fprintf(stderr, "RPM: Too full to encode object end!\r\n");
#endif
                    rpmdata.error_code =
                        ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
                    error = BACNET_STATUS_ABORT;
                    goto RPM_FAILURE;
                } else {
                    apdu_len += copy_len;
                }
                break;  /* finished with this property list */
            }
        }
        if (decode_len >= service_len) {
            /* Reached the end so finish up */
            break;
        }
    }

    if (apdu_len > service_data->max_resp) {
        /* too big for the sender - send an abort */
        rpmdata.error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
        error = BACNET_STATUS_ABORT;
#if PRINT_ENABLED
        fprintf(stderr, "RPM: Message too large.  Sending Abort!\n");
#endif
        goto RPM_FAILURE;
    }

RPM_FAILURE:
    if (error) {
        if (error == BACNET_STATUS_ABORT) {
            apdu_len =
                abort_encode_apdu(&Handler_Transmit_Buffer[npdu_len],
                                  service_data->invoke_id,
                                  abort_convert_error_code(rpmdata.error_code), true);
#if PRINT_ENABLED
            fprintf(stderr, "RPM: Sending Abort!\n");
#endif
        } else if (error == BACNET_STATUS_ERROR) {
            apdu_len =
                bacerror_encode_apdu(&Handler_Transmit_Buffer[npdu_len],
                                     service_data->invoke_id, SERVICE_CONFIRMED_READ_PROP_MULTIPLE,
                                     rpmdata.error_class, rpmdata.error_code);
#if PRINT_ENABLED
            fprintf(stderr, "RPM: Sending Error!\n");
#endif
        } else if (error == BACNET_STATUS_REJECT) {
            apdu_len =
                reject_encode_apdu(&Handler_Transmit_Buffer[npdu_len],
                                   service_data->invoke_id,
                                   reject_convert_error_code(rpmdata.error_code));
#if PRINT_ENABLED
            fprintf(stderr, "RPM: Sending Reject!\n");
#endif
        }
    }

    pdu_len = apdu_len + npdu_len;
    bytes_sent =
        datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0],
                          pdu_len);
#if PRINT_ENABLED
    if (bytes_sent <= 0) {
        fprintf(stderr, "RPM: Failed to send PDU (%s)!\n", strerror(errno));
    }
#else
    bytes_sent = bytes_sent;
#endif
}
コード例 #18
0
bool Notification_Class_Write_Property(
    BACNET_WRITE_PROPERTY_DATA * wp_data)
{
    NOTIFICATION_CLASS_INFO *CurrentNotify;
    NOTIFICATION_CLASS_INFO TmpNotify;
    BACNET_APPLICATION_DATA_VALUE value;
    bool status = false;
    int iOffset = 0;
    uint8_t idx = 0;
    int len = 0;



    CurrentNotify =
        &NC_Info[Notification_Class_Instance_To_Index(wp_data->
            object_instance)];

    /* decode the some of the request
     */
    len =
        bacapp_decode_application_data(wp_data->application_data,
        wp_data->application_data_len, &value);
    if (len < 0) {
        /* error while decoding - a value larger than we can handle */
        wp_data->error_class = ERROR_CLASS_PROPERTY;
        wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
        return false;
    }
    if ((wp_data->object_property != PROP_PRIORITY) &&
        (wp_data->array_index != BACNET_ARRAY_ALL)) {
        /*  only array properties can have array options */
        wp_data->error_class = ERROR_CLASS_PROPERTY;
        wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
        return false;
    }
    switch (wp_data->object_property) {
        case PROP_PRIORITY:
            status =
                WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
                &wp_data->error_class, &wp_data->error_code);

            if (status) {
                if (wp_data->array_index == 0) {
                    wp_data->error_class = ERROR_CLASS_PROPERTY;
                    wp_data->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
                } else if (wp_data->array_index == BACNET_ARRAY_ALL) {
                    /* FIXME: wite all array */
                } else if (wp_data->array_index <= 3) {
                    CurrentNotify->Priority[wp_data->array_index - 1] =
                        value.type.Unsigned_Int;
                } else {
                    wp_data->error_class = ERROR_CLASS_PROPERTY;
                    wp_data->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
                }
            }
            break;

        case PROP_ACK_REQUIRED:
            status =
                WPValidateArgType(&value, BACNET_APPLICATION_TAG_BIT_STRING,
                &wp_data->error_class, &wp_data->error_code);

            if (status) {
                if (value.type.Bit_String.bits_used == 3) {
                    CurrentNotify->Ack_Required =
                        value.type.Bit_String.value[0];
                } else {
                    wp_data->error_class = ERROR_CLASS_PROPERTY;
                    wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
                }
            }
            break;

        case PROP_RECIPIENT_LIST:

            memset(&TmpNotify, 0x00, sizeof(NOTIFICATION_CLASS_INFO));

            /* decode all packed */
            while (iOffset < wp_data->application_data_len) {
                /* Decode Valid Days */
                len =
                    bacapp_decode_application_data(&wp_data->
                    application_data[iOffset], wp_data->application_data_len,
                    &value);

                if ((len == 0) ||
                    (value.tag != BACNET_APPLICATION_TAG_BIT_STRING)) {
                    /* Bad decode, wrong tag or following required parameter missing */
                    wp_data->error_class = ERROR_CLASS_PROPERTY;
                    wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
                    return false;
                }

                if (value.type.Bit_String.bits_used == MAX_BACNET_DAYS_OF_WEEK)
                    /* store value */
                    TmpNotify.Recipient_List[idx].ValidDays =
                        value.type.Bit_String.value[0];
                else {
                    wp_data->error_class = ERROR_CLASS_PROPERTY;
                    wp_data->error_code = ERROR_CODE_OTHER;
                    return false;
                }

                iOffset += len;
                /* Decode From Time */
                len =
                    bacapp_decode_application_data(&wp_data->
                    application_data[iOffset], wp_data->application_data_len,
                    &value);

                if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_TIME)) {
                    /* Bad decode, wrong tag or following required parameter missing */
                    wp_data->error_class = ERROR_CLASS_PROPERTY;
                    wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
                    return false;
                }
                /* store value */
                TmpNotify.Recipient_List[idx].FromTime = value.type.Time;

                iOffset += len;
                /* Decode To Time */
                len =
                    bacapp_decode_application_data(&wp_data->
                    application_data[iOffset], wp_data->application_data_len,
                    &value);

                if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_TIME)) {
                    /* Bad decode, wrong tag or following required parameter missing */
                    wp_data->error_class = ERROR_CLASS_PROPERTY;
                    wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
                    return false;
                }
                /* store value */
                TmpNotify.Recipient_List[idx].ToTime = value.type.Time;

                iOffset += len;
                /* context tag [0] - Device */
                if (decode_is_context_tag(&wp_data->application_data[iOffset],
                        0)) {
                    TmpNotify.Recipient_List[idx].Recipient.RecipientType =
                        RECIPIENT_TYPE_DEVICE;
                    /* Decode Network Number */
                    len =
                        bacapp_decode_context_data(&wp_data->
                        application_data[iOffset],
                        wp_data->application_data_len, &value,
                        PROP_RECIPIENT_LIST);

                    if ((len == 0) ||
                        (value.tag != BACNET_APPLICATION_TAG_OBJECT_ID)) {
                        /* Bad decode, wrong tag or following required parameter missing */
                        wp_data->error_class = ERROR_CLASS_PROPERTY;
                        wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
                        return false;
                    }
                    /* store value */
                    TmpNotify.Recipient_List[idx].Recipient._.
                        DeviceIdentifier = value.type.Object_Id.instance;

                    iOffset += len;
                }
                /* opening tag [1] - Recipient */
                else if (decode_is_opening_tag_number(&wp_data->
                        application_data[iOffset], 1)) {
                    iOffset++;
                    TmpNotify.Recipient_List[idx].Recipient.RecipientType =
                        RECIPIENT_TYPE_ADDRESS;
                    /* Decode Network Number */
                    len =
                        bacapp_decode_application_data(&wp_data->
                        application_data[iOffset],
                        wp_data->application_data_len, &value);

                    if ((len == 0) ||
                        (value.tag != BACNET_APPLICATION_TAG_UNSIGNED_INT)) {
                        /* Bad decode, wrong tag or following required parameter missing */
                        wp_data->error_class = ERROR_CLASS_PROPERTY;
                        wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
                        return false;
                    }
                    /* store value */
                    TmpNotify.Recipient_List[idx].Recipient._.Address.net =
                        value.type.Unsigned_Int;

                    iOffset += len;
                    /* Decode Address */
                    len =
                        bacapp_decode_application_data(&wp_data->
                        application_data[iOffset],
                        wp_data->application_data_len, &value);

                    if ((len == 0) ||
                        (value.tag != BACNET_APPLICATION_TAG_OCTET_STRING)) {
                        /* Bad decode, wrong tag or following required parameter missing */
                        wp_data->error_class = ERROR_CLASS_PROPERTY;
                        wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
                        return false;
                    }
                    /* store value */
                    if (TmpNotify.Recipient_List[idx].Recipient._.Address.
                        net == 0) {
                        memcpy(TmpNotify.Recipient_List[idx].Recipient._.
                            Address.mac, value.type.Octet_String.value,
                            value.type.Octet_String.length);
                        TmpNotify.Recipient_List[idx].Recipient._.Address.
                            mac_len = value.type.Octet_String.length;
                    } else {
                        memcpy(TmpNotify.Recipient_List[idx].Recipient._.
                            Address.adr, value.type.Octet_String.value,
                            value.type.Octet_String.length);
                        TmpNotify.Recipient_List[idx].Recipient._.Address.len =
                            value.type.Octet_String.length;
                    }

                    iOffset += len;
                    /* closing tag [1] - Recipient */
                    if (decode_is_closing_tag_number(&wp_data->
                            application_data[iOffset], 1))
                        iOffset++;
                    else {
                        /* Bad decode, wrong tag or following required parameter missing */
                        wp_data->error_class = ERROR_CLASS_PROPERTY;
                        wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
                        return false;
                    }
                } else {
                    /* Bad decode, wrong tag or following required parameter missing */
                    wp_data->error_class = ERROR_CLASS_PROPERTY;
                    wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
                    return false;
                }

                /* Process Identifier */
                len =
                    bacapp_decode_application_data(&wp_data->
                    application_data[iOffset], wp_data->application_data_len,
                    &value);

                if ((len == 0) ||
                    (value.tag != BACNET_APPLICATION_TAG_UNSIGNED_INT)) {
                    /* Bad decode, wrong tag or following required parameter missing */
                    wp_data->error_class = ERROR_CLASS_PROPERTY;
                    wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
                    return false;
                }
                /* store value */
                TmpNotify.Recipient_List[idx].ProcessIdentifier =
                    value.type.Unsigned_Int;

                iOffset += len;
                /* Issue Confirmed Notifications */
                len =
                    bacapp_decode_application_data(&wp_data->
                    application_data[iOffset], wp_data->application_data_len,
                    &value);

                if ((len == 0) ||
                    (value.tag != BACNET_APPLICATION_TAG_BOOLEAN)) {
                    /* Bad decode, wrong tag or following required parameter missing */
                    wp_data->error_class = ERROR_CLASS_PROPERTY;
                    wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
                    return false;
                }
                /* store value */
                TmpNotify.Recipient_List[idx].ConfirmedNotify =
                    value.type.Boolean;

                iOffset += len;
                /* Transitions */
                len =
                    bacapp_decode_application_data(&wp_data->
                    application_data[iOffset], wp_data->application_data_len,
                    &value);

                if ((len == 0) ||
                    (value.tag != BACNET_APPLICATION_TAG_BIT_STRING)) {
                    /* Bad decode, wrong tag or following required parameter missing */
                    wp_data->error_class = ERROR_CLASS_PROPERTY;
                    wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
                    return false;
                }

                if (value.type.Bit_String.bits_used ==
                    MAX_BACNET_EVENT_TRANSITION)
                    /* store value */
                    TmpNotify.Recipient_List[idx].Transitions =
                        value.type.Bit_String.value[0];
                else {
                    wp_data->error_class = ERROR_CLASS_PROPERTY;
                    wp_data->error_code = ERROR_CODE_OTHER;
                    return false;
                }
                iOffset += len;

                /* Increasing element of list */
                if (++idx >= NC_MAX_RECIPIENTS) {
                    wp_data->error_class = ERROR_CLASS_RESOURCES;
                    wp_data->error_code =
                        ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
                    return false;
                }
            }

            /* Decoded all recipient list */
            /* copy elements from temporary object */
            for (idx = 0; idx < NC_MAX_RECIPIENTS; idx++) {
                BACNET_ADDRESS src = { 0 };
                unsigned max_apdu = 0;
                int32_t DeviceID;

                CurrentNotify->Recipient_List[idx] =
                    TmpNotify.Recipient_List[idx];

                if (CurrentNotify->Recipient_List[idx].Recipient.
                    RecipientType == RECIPIENT_TYPE_DEVICE) {
                    /* copy Device_ID */
                    DeviceID =
                        CurrentNotify->Recipient_List[idx].Recipient._.
                        DeviceIdentifier;
                    address_bind_request(DeviceID, &max_apdu, &src);

                } else if (CurrentNotify->Recipient_List[idx].Recipient.
                    RecipientType == RECIPIENT_TYPE_ADDRESS) {
                    /* copy Address */
                    /* src = CurrentNotify->Recipient_List[idx].Recipient._.Address; */
                    /* address_bind_request(BACNET_MAX_INSTANCE, &max_apdu, &src); */
                }
            }

            status = true;

            break;

        default:
            wp_data->error_class = ERROR_CLASS_PROPERTY;
            wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
            break;
    }

    return status;
}