Feature/comments and buffer checks (#73)
* Added comments * Replaced Goto construct * Added apdu_len check * Added comments * Added string limit and reworked printable check * Mainly comments * Just comments * Just comments * decode service request returns now non zero on success * eliminated warnings * Added character string init with length check. * Paranoic length check * Comments and object index checking on read/write. * Check name/desc strings before returning. * Eliminated Goto
This commit is contained in:
+228
-142
@@ -94,6 +94,12 @@ static BACNET_SERVICES_SUPPORTED
|
||||
/* If they are not set, they are handled by a reject message */
|
||||
static confirmed_function Confirmed_Function[MAX_BACNET_CONFIRMED_SERVICE];
|
||||
|
||||
/**
|
||||
* @brief Set a handler function for the given confirmed service.
|
||||
*
|
||||
* @param service_choice Service, see SERVICE_CONFIRMED_X enumeration.
|
||||
* @param pFunction Pointer to the function, being in charge of the service.
|
||||
*/
|
||||
void apdu_set_confirmed_handler(
|
||||
BACNET_CONFIRMED_SERVICE service_choice, confirmed_function pFunction)
|
||||
{
|
||||
@@ -105,6 +111,12 @@ void apdu_set_confirmed_handler(
|
||||
/* Allow the APDU handler to automatically reject */
|
||||
static confirmed_function Unrecognized_Service_Handler;
|
||||
|
||||
/**
|
||||
* @brief Set a handler function called for an unsupported service.
|
||||
*
|
||||
* @param pFunction Pointer to the function, being in charge,
|
||||
* if a unsupported service has been requested.
|
||||
*/
|
||||
void apdu_set_unrecognized_service_handler_handler(confirmed_function pFunction)
|
||||
{
|
||||
Unrecognized_Service_Handler = pFunction;
|
||||
@@ -115,6 +127,12 @@ void apdu_set_unrecognized_service_handler_handler(confirmed_function pFunction)
|
||||
static unconfirmed_function
|
||||
Unconfirmed_Function[MAX_BACNET_UNCONFIRMED_SERVICE];
|
||||
|
||||
/**
|
||||
* @brief Set a handler function for the given unconfirmed service.
|
||||
*
|
||||
* @param service_choice Service, see SERVICE_UNCONFIRMED_X enumeration.
|
||||
* @param pFunction Pointer to the function, being in charge of the service.
|
||||
*/
|
||||
void apdu_set_unconfirmed_handler(
|
||||
BACNET_UNCONFIRMED_SERVICE service_choice, unconfirmed_function pFunction)
|
||||
{
|
||||
@@ -123,6 +141,13 @@ void apdu_set_unconfirmed_handler(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the given service is supported or not.
|
||||
*
|
||||
* @param service_supported Service in question
|
||||
*
|
||||
* @return true/false
|
||||
*/
|
||||
bool apdu_service_supported(BACNET_SERVICES_SUPPORTED service_supported)
|
||||
{
|
||||
int i = 0;
|
||||
@@ -278,6 +303,12 @@ void apdu_set_confirmed_ack_handler(
|
||||
|
||||
static error_function Error_Function[MAX_BACNET_CONFIRMED_SERVICE];
|
||||
|
||||
/**
|
||||
* @brief Set a error handler function for the given confirmed service.
|
||||
*
|
||||
* @param service_choice Service, see SERVICE_CONFIRMED_X enumeration.
|
||||
* @param pFunction Pointer to the function, being in charge of the error handling.
|
||||
*/
|
||||
void apdu_set_error_handler(
|
||||
BACNET_CONFIRMED_SERVICE service_choice, error_function pFunction)
|
||||
{
|
||||
@@ -295,11 +326,35 @@ void apdu_set_abort_handler(abort_function pFunction)
|
||||
|
||||
static reject_function Reject_Function;
|
||||
|
||||
/**
|
||||
* @brief Set a handler function called for a rejected service.
|
||||
*
|
||||
* @param pFunction Pointer to the function, being in charge,
|
||||
* if a service request will be rejected.
|
||||
*/
|
||||
void apdu_set_reject_handler(reject_function pFunction)
|
||||
{
|
||||
Reject_Function = pFunction;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decode the given confirmed service request from the received data.
|
||||
*
|
||||
* @param apdu Received data buffer.
|
||||
* @param apdu_len Count of valid bytes in the receive buffer.
|
||||
* @param service_data Pointer of the structure being filled with the service
|
||||
* data.
|
||||
* @param service_choice Pointer to a variable taking the service requested,
|
||||
* see SERVICE_CONFIRMED_X
|
||||
* @param service_request Pointer to a pointer that will take the pointer
|
||||
* were the service request data can be found in
|
||||
* the receive buffer.
|
||||
* @param service_request_len Pointer to a variable that takes the length
|
||||
* of the service request data.
|
||||
*
|
||||
* @return The length of the service data and reflects the offset, where
|
||||
* we are in PDU after the service had been decoded.
|
||||
*/
|
||||
uint16_t apdu_decode_confirmed_service_request(uint8_t *apdu, /* APDU data */
|
||||
uint16_t apdu_len,
|
||||
BACNET_CONFIRMED_SERVICE_DATA *service_data,
|
||||
@@ -382,13 +437,19 @@ static bool apdu_confirmed_dcc_disabled(uint8_t service_choice)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* When network communications are completely disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
shall be processed and no messages shall be initiated. */
|
||||
/* If the request is valid and the 'Enable/Disable' parameter is
|
||||
DISABLE_INITIATION, the responding BACnet-user shall
|
||||
discontinue the initiation of messages except for I-Am
|
||||
requests issued in accordance with the Who-Is service procedure.*/
|
||||
/**
|
||||
* When network communications are completely disabled,
|
||||
* only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
* shall be processed and no messages shall be initiated.
|
||||
* If the request is valid and the 'Enable/Disable' parameter is
|
||||
* DISABLE_INITIATION, the responding BACnet-user shall
|
||||
* discontinue the initiation of messages except for I-Am
|
||||
* requests issued in accordance with the Who-Is service procedure.
|
||||
*
|
||||
* @param service_choice Service, like SERVICE_UNCONFIRMED_WHO_IS
|
||||
*
|
||||
* @return true, if being disabled.
|
||||
*/
|
||||
static bool apdu_unconfirmed_dcc_disabled(uint8_t service_choice)
|
||||
{
|
||||
bool status = false;
|
||||
@@ -462,101 +523,107 @@ void apdu_handler(BACNET_ADDRESS *src,
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
|
||||
service_choice = apdu[1];
|
||||
service_request = &apdu[2];
|
||||
service_request_len = apdu_len - 2;
|
||||
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);
|
||||
if (apdu_len >= 2) {
|
||||
service_choice = apdu[1];
|
||||
service_request = &apdu[2];
|
||||
service_request_len = apdu_len - 2;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
((confirmed_simple_ack_function)
|
||||
Confirmed_ACK_Function[service_choice])(
|
||||
src, invoke_id);
|
||||
}
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (apdu_len >= 3) {
|
||||
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) {
|
||||
((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] & BIT(3)) ? true : false;
|
||||
service_ack_data.more_follows =
|
||||
(apdu[0] & BIT(2)) ? 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);
|
||||
}
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (apdu_len >= 3) {
|
||||
service_ack_data.segmented_message =
|
||||
(apdu[0] & BIT(3)) ? true : false;
|
||||
service_ack_data.more_follows =
|
||||
(apdu[0] & BIT(2)) ? 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);
|
||||
}
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_SEGMENT_ACK:
|
||||
@@ -565,66 +632,85 @@ void apdu_handler(BACNET_ADDRESS *src,
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
case PDU_TYPE_ERROR:
|
||||
invoke_id = apdu[1];
|
||||
service_choice = apdu[2];
|
||||
len = 3;
|
||||
if (apdu_len >= 3) {
|
||||
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 */
|
||||
/* 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 */
|
||||
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 (len < apdu_len) {
|
||||
len += decode_tag_number_and_value(
|
||||
&apdu[len], &tag_number, &len_value);
|
||||
|
||||
if (len < apdu_len) {
|
||||
/* FIXME: we could validate that the tag is enumerated... */
|
||||
len += decode_enumerated(&apdu[len], len_value, &error_class);
|
||||
|
||||
if (len < apdu_len) {
|
||||
len += decode_tag_number_and_value(
|
||||
&apdu[len], &tag_number, &len_value);
|
||||
|
||||
if (len < apdu_len) {
|
||||
/* 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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
}
|
||||
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);
|
||||
if (apdu_len >= 3) {
|
||||
invoke_id = apdu[1];
|
||||
reason = apdu[2];
|
||||
if (Reject_Function) {
|
||||
Reject_Function(src, invoke_id, reason);
|
||||
}
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
}
|
||||
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);
|
||||
if (apdu_len >= 3) {
|
||||
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);
|
||||
}
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -802,36 +802,37 @@ void handler_cov_subscribe(uint8_t *service_request,
|
||||
fprintf(stderr, "SubscribeCOV: Segmented message. Sending Abort!\n");
|
||||
#endif
|
||||
error = true;
|
||||
goto COV_ABORT;
|
||||
}
|
||||
len = cov_subscribe_decode_service_request(
|
||||
service_request, service_len, &cov_data);
|
||||
#if PRINT_ENABLED
|
||||
if (len <= 0)
|
||||
fprintf(stderr, "SubscribeCOV: Unable to decode Request!\n");
|
||||
#endif
|
||||
if (len < 0) {
|
||||
error = true;
|
||||
goto COV_ABORT;
|
||||
}
|
||||
cov_data.error_class = ERROR_CLASS_OBJECT;
|
||||
cov_data.error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
success = cov_subscribe(
|
||||
src, &cov_data, &cov_data.error_class, &cov_data.error_code);
|
||||
if (success) {
|
||||
apdu_len = encode_simple_ack(&Handler_Transmit_Buffer[npdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_SUBSCRIBE_COV);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "SubscribeCOV: Sending Simple Ack!\n");
|
||||
#endif
|
||||
} else {
|
||||
len = BACNET_STATUS_ERROR;
|
||||
error = true;
|
||||
len = cov_subscribe_decode_service_request(
|
||||
service_request, service_len, &cov_data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "SubscribeCOV: Sending Error!\n");
|
||||
if (len <= 0)
|
||||
fprintf(stderr, "SubscribeCOV: Unable to decode Request!\n");
|
||||
#endif
|
||||
if (len < 0) {
|
||||
error = true;
|
||||
} else {
|
||||
cov_data.error_class = ERROR_CLASS_OBJECT;
|
||||
cov_data.error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
success = cov_subscribe(
|
||||
src, &cov_data, &cov_data.error_class, &cov_data.error_code);
|
||||
if (success) {
|
||||
apdu_len = encode_simple_ack(&Handler_Transmit_Buffer[npdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_SUBSCRIBE_COV);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "SubscribeCOV: Sending Simple Ack!\n");
|
||||
#endif
|
||||
} else {
|
||||
len = BACNET_STATUS_ERROR;
|
||||
error = true;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "SubscribeCOV: Sending Error!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
COV_ABORT:
|
||||
|
||||
/* Error? */
|
||||
if (error) {
|
||||
if (len == BACNET_STATUS_ABORT) {
|
||||
apdu_len = abort_encode_apdu(&Handler_Transmit_Buffer[npdu_len],
|
||||
|
||||
@@ -68,6 +68,7 @@ void handler_write_property(uint8_t *service_request,
|
||||
{
|
||||
BACNET_WRITE_PROPERTY_DATA wp_data;
|
||||
int len = 0;
|
||||
bool bcontinue = true;
|
||||
int pdu_len = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
int bytes_sent = 0;
|
||||
@@ -88,47 +89,55 @@ void handler_write_property(uint8_t *service_request,
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "WP: Segmented message. Sending Abort!\n");
|
||||
#endif
|
||||
goto WP_ABORT;
|
||||
} /* decode the service request only */
|
||||
len = wp_decode_service_request(service_request, service_len, &wp_data);
|
||||
#if PRINT_ENABLED
|
||||
if (len > 0)
|
||||
fprintf(stderr,
|
||||
"WP: type=%lu instance=%lu property=%lu priority=%lu index=%ld\n",
|
||||
(unsigned long)wp_data.object_type,
|
||||
(unsigned long)wp_data.object_instance,
|
||||
(unsigned long)wp_data.object_property,
|
||||
(unsigned long)wp_data.priority, (long)wp_data.array_index);
|
||||
else
|
||||
fprintf(stderr, "WP: Unable to decode Request!\n");
|
||||
#endif
|
||||
/* bad decoding or something we didn't understand - send an abort */
|
||||
if (len <= 0) {
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER, true);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "WP: Bad Encoding. Sending Abort!\n");
|
||||
#endif
|
||||
goto WP_ABORT;
|
||||
bcontinue = false;
|
||||
}
|
||||
if (Device_Write_Property(&wp_data)) {
|
||||
len = encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
|
||||
if (bcontinue) {
|
||||
/* decode the service request only */
|
||||
len = wp_decode_service_request(service_request, service_len, &wp_data);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "WP: Sending Simple Ack!\n");
|
||||
if (len > 0)
|
||||
fprintf(stderr,
|
||||
"WP: type=%lu instance=%lu property=%lu priority=%lu index=%ld\n",
|
||||
(unsigned long)wp_data.object_type,
|
||||
(unsigned long)wp_data.object_instance,
|
||||
(unsigned long)wp_data.object_property,
|
||||
(unsigned long)wp_data.priority, (long)wp_data.array_index);
|
||||
else
|
||||
fprintf(stderr, "WP: Unable to decode Request!\n");
|
||||
#endif
|
||||
} else {
|
||||
len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
wp_data.error_class, wp_data.error_code);
|
||||
/* bad decoding or something we didn't understand - send an abort */
|
||||
if (len <= 0) {
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER, true);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "WP: Sending Error!\n");
|
||||
fprintf(stderr, "WP: Bad Encoding. Sending Abort!\n");
|
||||
#endif
|
||||
bcontinue = false;
|
||||
}
|
||||
|
||||
if (bcontinue) {
|
||||
if (Device_Write_Property(&wp_data)) {
|
||||
len = encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "WP: Sending Simple Ack!\n");
|
||||
#endif
|
||||
} else {
|
||||
len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
wp_data.error_class, wp_data.error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "WP: Sending Error!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
WP_ABORT:
|
||||
|
||||
/* Send PDU */
|
||||
pdu_len += len;
|
||||
bytes_sent = datalink_send_pdu(
|
||||
src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
bytes_sent = datalink_send_pdu( \
|
||||
src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
if (bytes_sent <= 0) {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "WP: Failed to send PDU (%s)!\n", strerror(errno));
|
||||
@@ -138,12 +147,20 @@ WP_ABORT:
|
||||
return;
|
||||
}
|
||||
|
||||
/** Perform basic validation of Write Property argument based on
|
||||
/**
|
||||
* @brief Perform basic validation of Write Property argument based on
|
||||
* the assumption that it is a string. Check for correct data type,
|
||||
* correct encoding (fixed here as ANSI X34),correct length, and
|
||||
* finally if it is allowed to be empty.
|
||||
*
|
||||
* @param pValue Pointer to the application data value representing the string.
|
||||
* @param iMaxLen Maximum string length allowed.
|
||||
* @param bEmptyAllowed true, if empty strings shall be allowed.
|
||||
* @param pErrorClass Pointer to a variable taking the error class.
|
||||
* @param pErrorCode Pointer to a variable taking the error code.
|
||||
*
|
||||
* @return True on success, false otherwise.
|
||||
*/
|
||||
|
||||
bool WPValidateString(BACNET_APPLICATION_DATA_VALUE *pValue,
|
||||
int iMaxLen,
|
||||
bool bEmptyAllowed,
|
||||
|
||||
Reference in New Issue
Block a user