Secure ReadPropertyMultiple code, and improve unit test coverage. (#650)
This commit is contained in:
@@ -1,29 +1,13 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2007 Steve Karg <skarg@users.sourceforge.net>
|
||||
* Inspired by John Stachler <John.Stachler@lennoxind.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief BACnet ReadPropertyMultiple-Request handler
|
||||
* @author Steve Karg <skarg@users.sourceforge.net>
|
||||
* @author John Stachler <John.Stachler@lennoxind.com>
|
||||
* @author Peter McShane <petermcs@users.sourceforge.net>
|
||||
* @author Roy Schneider <postmaster@overthehill.de>
|
||||
* @date 2007
|
||||
* @copyright SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@@ -47,12 +31,21 @@
|
||||
#endif
|
||||
#include "bacnet/basic/tsm/tsm.h"
|
||||
#include "bacnet/basic/services.h"
|
||||
#include "bacnet/basic/sys/debug.h"
|
||||
#include "bacnet/datalink/datalink.h"
|
||||
|
||||
/** @file h_rpm.c Handles Read Property Multiple requests. */
|
||||
|
||||
static uint8_t Temp_Buf[MAX_APDU] = { 0 };
|
||||
|
||||
/**
|
||||
* @brief Fetches the lists of properties (array of BACNET_PROPERTY_ID's) for
|
||||
* this object type and the special properties ALL or REQUIRED or OPTIONAL.
|
||||
* @param pPropertyList reference for the list of ALL, REQUIRED, and OPTIONAL
|
||||
* properties.
|
||||
* @param special_property The special property ALL, REQUIRED, or OPTIONAL
|
||||
* to fetch.
|
||||
* @param index The index of the property to fetch.
|
||||
* @return The property ID or -1 if not found.
|
||||
*/
|
||||
static BACNET_PROPERTY_ID RPM_Object_Property(
|
||||
struct special_property_list_t *pPropertyList,
|
||||
BACNET_PROPERTY_ID special_property,
|
||||
@@ -87,6 +80,16 @@ static BACNET_PROPERTY_ID RPM_Object_Property(
|
||||
return (BACNET_PROPERTY_ID)property;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fetches the number of properties (array of BACNET_PROPERTY_ID's) for
|
||||
* this object type belonging to the special properties ALL or REQUIRED or
|
||||
* OPTIONAL.
|
||||
* @param pPropertyList reference for the list of ALL, REQUIRED, and OPTIONAL
|
||||
* properties.
|
||||
* @param special_property The special property ALL, REQUIRED, or OPTIONAL
|
||||
* to fetch.
|
||||
* @return The number of properties.
|
||||
*/
|
||||
static unsigned RPM_Object_Property_Count(
|
||||
struct special_property_list_t *pPropertyList,
|
||||
BACNET_PROPERTY_ID special_property)
|
||||
@@ -105,8 +108,16 @@ static unsigned RPM_Object_Property_Count(
|
||||
return count;
|
||||
}
|
||||
|
||||
/** Encode the RPM property returning the length of the encoding,
|
||||
or 0 if there is no room to fit the encoding. */
|
||||
/**
|
||||
* @brief Encode the RPM property returning the length of the encoding,
|
||||
* or 0 if there is no room to fit the encoding.
|
||||
* @param apdu [out] The buffer to encode the property into.
|
||||
* @param offset [in] The offset into the buffer to start encoding.
|
||||
* @param max_apdu [in] The maximum length of the buffer.
|
||||
* @param rpmdata [in] The RPM data to encode.
|
||||
* @return The length of the encoding, or 0 if there is no room to fit the
|
||||
* encoding.
|
||||
*/
|
||||
static int RPM_Encode_Property(
|
||||
uint8_t *apdu, uint16_t offset, uint16_t max_apdu, BACNET_RPM_DATA *rpmdata)
|
||||
{
|
||||
@@ -221,9 +232,7 @@ void handler_read_property_multiple(uint8_t *service_request,
|
||||
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
|
||||
debug_fprintf(stderr, "RPM: Segmented message. Sending Abort!\r\n");
|
||||
} else {
|
||||
/* decode apdu request & encode apdu reply
|
||||
encode complex ack, invoke id, service choice */
|
||||
@@ -239,9 +248,7 @@ void handler_read_property_multiple(uint8_t *service_request,
|
||||
decode_len += len;
|
||||
} else {
|
||||
/* bad encoding - skip to error/reject/abort handling */
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "RPM: Bad Encoding.\n");
|
||||
#endif
|
||||
debug_fprintf(stderr, "RPM: Bad Encoding.\n");
|
||||
error = len;
|
||||
berror = true;
|
||||
break;
|
||||
@@ -273,9 +280,7 @@ void handler_read_property_multiple(uint8_t *service_request,
|
||||
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
|
||||
debug_fprintf(stderr, "RPM: Response too big!\r\n");
|
||||
rpmdata.error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
error = BACNET_STATUS_ABORT;
|
||||
@@ -292,9 +297,7 @@ void handler_read_property_multiple(uint8_t *service_request,
|
||||
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
|
||||
debug_fprintf(stderr, "RPM: Bad Encoding.\n");
|
||||
error = len;
|
||||
berror = true;
|
||||
break; /* The berror flag ensures that both loops will
|
||||
@@ -319,10 +322,8 @@ void handler_read_property_multiple(uint8_t *service_request,
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
} else {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
debug_fprintf(stderr,
|
||||
"RPM: Too full for property!\r\n");
|
||||
#endif
|
||||
error = len;
|
||||
/* The berror flag ensures that
|
||||
both loops will be broken! */
|
||||
@@ -342,10 +343,8 @@ void handler_read_property_multiple(uint8_t *service_request,
|
||||
&Temp_Buf[0], apdu_len, len, MAX_APDU);
|
||||
|
||||
if (copy_len == 0) {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
debug_fprintf(stderr,
|
||||
"RPM: Too full to encode property!\r\n");
|
||||
#endif
|
||||
rpmdata.error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
error = BACNET_STATUS_ABORT;
|
||||
@@ -364,10 +363,8 @@ void handler_read_property_multiple(uint8_t *service_request,
|
||||
&Temp_Buf[0], apdu_len, len, MAX_APDU);
|
||||
|
||||
if (copy_len == 0) {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
debug_fprintf(stderr,
|
||||
"RPM: Too full to encode error!\r\n");
|
||||
#endif
|
||||
rpmdata.error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
error = BACNET_STATUS_ABORT;
|
||||
@@ -400,10 +397,8 @@ void handler_read_property_multiple(uint8_t *service_request,
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
} else {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
debug_fprintf(stderr,
|
||||
"RPM: Too full for property!\r\n");
|
||||
#endif
|
||||
error = len;
|
||||
/* The berror flag ensures that
|
||||
both loops will be broken! */
|
||||
@@ -423,10 +418,8 @@ void handler_read_property_multiple(uint8_t *service_request,
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
} else {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
debug_fprintf(stderr,
|
||||
"RPM: Too full for property!\r\n");
|
||||
#endif
|
||||
error = len;
|
||||
berror = true;
|
||||
break; /* The berror flag ensures that
|
||||
@@ -444,10 +437,8 @@ void handler_read_property_multiple(uint8_t *service_request,
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
} else {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
debug_fprintf(stderr,
|
||||
"RPM: Too full for individual property!\r\n");
|
||||
#endif
|
||||
error = len;
|
||||
berror = true;
|
||||
break; /* The berror flag ensures that both loops */
|
||||
@@ -464,10 +455,8 @@ void handler_read_property_multiple(uint8_t *service_request,
|
||||
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,
|
||||
debug_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;
|
||||
@@ -496,10 +485,8 @@ void handler_read_property_multiple(uint8_t *service_request,
|
||||
rpmdata.error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
error = BACNET_STATUS_ABORT;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(
|
||||
debug_fprintf(
|
||||
stderr, "RPM: Message too large. Sending Abort!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -510,24 +497,18 @@ void handler_read_property_multiple(uint8_t *service_request,
|
||||
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
|
||||
debug_fprintf(stderr, "RPM: Sending Abort!\n");
|
||||
} 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
|
||||
debug_fprintf(stderr, "RPM: Sending Error!\n");
|
||||
} 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
|
||||
debug_fprintf(stderr, "RPM: Sending Reject!\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -535,9 +516,8 @@ void handler_read_property_multiple(uint8_t *service_request,
|
||||
bytes_sent = datalink_send_pdu(
|
||||
src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
if (bytes_sent <= 0) {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "RPM: Failed to send PDU (%s)!\n", strerror(errno));
|
||||
#endif
|
||||
debug_fprintf(stderr, "RPM: Failed to send PDU (errno=%d)!\n",
|
||||
errno);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user