diff --git a/CHANGELOG.md b/CHANGELOG.md index c6d137cf..b3d7d38d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -152,6 +152,9 @@ The git repositories are hosted at the following sites: ### Changed +* Changed bacnet_array_write() write_function callback API by adding + array size parameter to avoid a duplicate decoding operation. + Removed duplicate checking of array size in object handlers. (#1253) * Changed bacfile_strdup to bacnet_strdup function to replace POSIX strdup and update bacfile to use bacnet_strdup. (#1251) * Changed PositiveInteger present-value datatype to diff --git a/src/bacnet/bacdcode.c b/src/bacnet/bacdcode.c index a9dc46d4..857590be 100644 --- a/src/bacnet/bacdcode.c +++ b/src/bacnet/bacdcode.c @@ -5904,8 +5904,8 @@ BACNET_ERROR_CODE bacnet_array_write( len = bacnet_unsigned_application_decode( apdu, apdu_size, &unsigned_value); if (len > 0) { - error_code = - write_function(object_instance, array_index, apdu, apdu_size); + error_code = write_function( + object_instance, array_index, unsigned_value, apdu, apdu_size); } else if (len == 0) { error_code = ERROR_CODE_INVALID_DATA_TYPE; } else { @@ -5931,7 +5931,7 @@ BACNET_ERROR_CODE bacnet_array_write( len = decode_function( object_instance, &apdu[apdu_len], apdu_size - apdu_len); error_code = write_function( - object_instance, index, &apdu[apdu_len], len); + object_instance, index, array_size, &apdu[apdu_len], len); if (error_code != ERROR_CODE_SUCCESS) { break; } @@ -5940,8 +5940,8 @@ BACNET_ERROR_CODE bacnet_array_write( } } else if (array_index <= array_size) { /* index was specified; write a single array element */ - error_code = - write_function(object_instance, array_index, apdu, apdu_size); + error_code = write_function( + object_instance, array_index, array_size, apdu, apdu_size); } else { /* array_index was specified out of range */ error_code = ERROR_CODE_INVALID_ARRAY_INDEX; diff --git a/src/bacnet/bacdcode.h b/src/bacnet/bacdcode.h index 674b1419..159924ed 100644 --- a/src/bacnet/bacdcode.h +++ b/src/bacnet/bacdcode.h @@ -47,6 +47,7 @@ typedef int (*bacnet_array_property_element_decode_function)( * @param object_instance [in] BACnet network port object instance number * @param array_index [in] array index to write: * 0=array size, 1 to N for individual array members + * @param array_size [in] number of elements in the array * @param application_data [in] encoded element value * @param application_data_len [in] The size of the encoded element value * @return BACNET_ERROR_CODE value @@ -54,6 +55,7 @@ typedef int (*bacnet_array_property_element_decode_function)( typedef BACNET_ERROR_CODE (*bacnet_array_property_element_write_function)( uint32_t object_instance, BACNET_ARRAY_INDEX array_index, + BACNET_UNSIGNED_INTEGER array_size, uint8_t *application_data, size_t application_data_len); diff --git a/src/bacnet/basic/object/channel.c b/src/bacnet/basic/object/channel.c index 55e680df..30151bea 100644 --- a/src/bacnet/basic/object/channel.c +++ b/src/bacnet/basic/object/channel.c @@ -1111,6 +1111,7 @@ static int Channel_List_Of_Object_Property_References_Length( * @param object_instance [in] BACnet network port object instance number * @param array_index [in] array index to write: * 0=array size, 1 to N for individual array members + * @param array_size [in] number of elements in the array, if writing array size * @param application_data [in] encoded element value * @param application_data_len [in] The size of the encoded element value * @return BACNET_ERROR_CODE value @@ -1118,6 +1119,7 @@ static int Channel_List_Of_Object_Property_References_Length( static BACNET_ERROR_CODE Channel_List_Of_Object_Property_References_Write( uint32_t object_instance, BACNET_ARRAY_INDEX array_index, + BACNET_UNSIGNED_INTEGER array_size, uint8_t *application_data, size_t application_data_len) { @@ -1130,8 +1132,11 @@ static BACNET_ERROR_CODE Channel_List_Of_Object_Property_References_Write( pObject = Object_Data(object_instance); if (pObject) { if (array_index == 0) { + /* This array is not required to be resizable + through BACnet write services */ + (void)array_size; error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - } else if (array_index <= CHANNEL_MEMBERS_MAX) { + } else { len = bacapp_decode_known_property( application_data, application_data_len, &value, OBJECT_CHANNEL, PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES); @@ -1152,8 +1157,6 @@ static BACNET_ERROR_CODE Channel_List_Of_Object_Property_References_Write( } else { error_code = ERROR_CODE_ABORT_OTHER; } - } else { - error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } } @@ -1188,6 +1191,7 @@ static int Channel_Control_Groups_Length( * @param object_instance [in] BACnet network port object instance number * @param array_index [in] array index to write: * 0=array size, 1 to N for individual array members + * @param array_size [in] number of elements in the array, if writing array size * @param application_data [in] encoded element value * @param application_data_len [in] The size of the encoded element value * @return BACNET_ERROR_CODE value @@ -1195,6 +1199,7 @@ static int Channel_Control_Groups_Length( static BACNET_ERROR_CODE Channel_Control_Groups_Write( uint32_t object_instance, BACNET_ARRAY_INDEX array_index, + BACNET_UNSIGNED_INTEGER array_size, uint8_t *application_data, size_t application_data_len) { @@ -1208,8 +1213,11 @@ static BACNET_ERROR_CODE Channel_Control_Groups_Write( pObject = Object_Data(object_instance); if (pObject) { if (array_index == 0) { + /* This array is not required to be resizable + through BACnet write services */ + (void)array_size; error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - } else if (array_index <= CHANNEL_MEMBERS_MAX) { + } else { len = bacapp_decode_known_property( application_data, application_data_len, &value, OBJECT_CHANNEL, PROP_CONTROL_GROUPS); @@ -1233,8 +1241,6 @@ static BACNET_ERROR_CODE Channel_Control_Groups_Write( } else { error_code = ERROR_CODE_ABORT_OTHER; } - } else { - error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } } diff --git a/src/bacnet/basic/object/device.c b/src/bacnet/basic/object/device.c index 12727315..71923543 100644 --- a/src/bacnet/basic/object/device.c +++ b/src/bacnet/basic/object/device.c @@ -2539,6 +2539,7 @@ static int Device_Configuration_File_Length( * @param object_instance [in] BACnet object instance number * @param array_index [in] array index to write: * 0=array size, 1 to N for individual array members + * @param array_size [in] The total size of the array, if writing array size * @param application_data [in] encoded element value * @param application_data_len [in] The size of the encoded element value * @return BACNET_ERROR_CODE value @@ -2546,6 +2547,7 @@ static int Device_Configuration_File_Length( static BACNET_ERROR_CODE Device_Configuration_File_Write( uint32_t object_instance, BACNET_ARRAY_INDEX array_index, + BACNET_UNSIGNED_INTEGER array_size, uint8_t *application_data, size_t application_data_len) { @@ -2558,8 +2560,9 @@ static BACNET_ERROR_CODE Device_Configuration_File_Write( if (array_index == 0) { /* This array is not required to be resizable through BACnet write services */ + (void)array_size; error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - } else if (array_index <= BACNET_BACKUP_FILE_COUNT) { + } else { len = bacnet_object_id_application_decode( application_data, application_data_len, &object_type, &instance); if (len > 0) { @@ -2576,8 +2579,6 @@ static BACNET_ERROR_CODE Device_Configuration_File_Write( } else { error_code = ERROR_CODE_INVALID_DATA_TYPE; } - } else { - error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } return error_code; diff --git a/src/bacnet/basic/object/lc.c b/src/bacnet/basic/object/lc.c index a30ffcdb..24845d0b 100644 --- a/src/bacnet/basic/object/lc.c +++ b/src/bacnet/basic/object/lc.c @@ -1423,6 +1423,8 @@ static int BACnet_Shed_Level_Element_Length( * @param object_instance [in] BACnet object instance number * @param array_index [in] array index to write: * 0=array size, 1 to N for individual array members + * @param array_size [in] The total number of elements in the array, + * if writing array size * @param application_data [in] encoded element value * @param application_data_len [in] The size of the encoded element value * @return BACNET_ERROR_CODE value @@ -1430,6 +1432,7 @@ static int BACnet_Shed_Level_Element_Length( static BACNET_ERROR_CODE BACnet_Shed_Level_Element_Write( uint32_t object_instance, BACNET_ARRAY_INDEX array_index, + BACNET_UNSIGNED_INTEGER array_size, uint8_t *application_data, size_t application_data_len) { @@ -1447,6 +1450,7 @@ static BACNET_ERROR_CODE BACnet_Shed_Level_Element_Write( if (array_index == 0) { /* This array is not required to be resizable through BACnet write services */ + (void)array_size; error_code = ERROR_CODE_WRITE_ACCESS_DENIED; } else if (array_index <= count) { len = bacnet_shed_level_decode( diff --git a/src/bacnet/basic/object/netport.c b/src/bacnet/basic/object/netport.c index ca500b63..9e6ff8ac 100644 --- a/src/bacnet/basic/object/netport.c +++ b/src/bacnet/basic/object/netport.c @@ -2107,6 +2107,8 @@ static int BBMD_Broadcast_Distribution_Table_Element_Length( * @param object_instance [in] BACnet network port object instance number * @param array_index [in] array index to write: * 0=array size, 1 to N for individual array members + * @param array_size [in] The total number of elements in the array, + * if writing array size * @param application_data [in] encoded element value * @param application_data_len [in] The size of the encoded element value * @return BACNET_ERROR_CODE value @@ -2114,13 +2116,13 @@ static int BBMD_Broadcast_Distribution_Table_Element_Length( static BACNET_ERROR_CODE BBMD_Broadcast_Distribution_Table_Element_Write( uint32_t object_instance, BACNET_ARRAY_INDEX array_index, + BACNET_UNSIGNED_INTEGER array_size, uint8_t *application_data, size_t application_data_len) { BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT; BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY bdt_entry = { 0 }; BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_list; - uint16_t capacity = 0; int len; bool status = false; unsigned index = 0; @@ -2128,14 +2130,16 @@ static BACNET_ERROR_CODE BBMD_Broadcast_Distribution_Table_Element_Write( index = Network_Port_Instance_To_Index(object_instance); if (index < BACNET_NETWORK_PORTS_MAX) { if (Object_List[index].Network_Type == PORT_TYPE_BIP) { - bdt_list = Object_List[index].Network.IPv4.BBMD_BD_Table; - capacity = bvlc_broadcast_distribution_table_count(bdt_list); if (array_index == 0) { - error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; - } else if (array_index <= capacity) { + /* This array is not required to be resizable + through BACnet write services */ + (void)array_size; + error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } else { len = bvlc_decode_broadcast_distribution_table_entry( application_data, application_data_len, &bdt_entry); if (len > 0) { + bdt_list = Object_List[index].Network.IPv4.BBMD_BD_Table; status = bvlc_broadcast_distribution_table_entry_insert( bdt_list, &bdt_entry, array_index); if (status) { @@ -2146,8 +2150,6 @@ static BACNET_ERROR_CODE BBMD_Broadcast_Distribution_Table_Element_Write( } else { error_code = ERROR_CODE_INVALID_DATA_TYPE; } - } else { - error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } } else { error_code = ERROR_CODE_ABORT_OTHER; @@ -2320,6 +2322,8 @@ static int BBMD_Foreign_Device_Table_Element_Length( * @param object_instance [in] BACnet network port object instance number * @param array_index [in] array index to write: * 0=array size, 1 to N for individual array members + * @param array_size [in] The total number of elements in the array, + * if writing array size * @param application_data [in] encoded element value * @param application_data_len [in] The size of the encoded element value * @return BACNET_ERROR_CODE value @@ -2327,13 +2331,13 @@ static int BBMD_Foreign_Device_Table_Element_Length( static BACNET_ERROR_CODE BBMD_Foreign_Device_Table_Element_Write( uint32_t object_instance, BACNET_ARRAY_INDEX array_index, + BACNET_UNSIGNED_INTEGER array_size, uint8_t *application_data, size_t application_data_len) { BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT; BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY fdt_entry = { 0 }; BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_list; - uint16_t capacity = 0; int len; bool status = false; unsigned index = 0; @@ -2341,14 +2345,16 @@ static BACNET_ERROR_CODE BBMD_Foreign_Device_Table_Element_Write( index = Network_Port_Instance_To_Index(object_instance); if (index < BACNET_NETWORK_PORTS_MAX) { if (Object_List[index].Network_Type == PORT_TYPE_BIP) { - fdt_list = Object_List[index].Network.IPv4.BBMD_FD_Table; - capacity = bvlc_foreign_device_table_count(fdt_list); if (array_index == 0) { - error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; - } else if (array_index <= capacity) { + /* This array is not required to be resizable + through BACnet write services */ + (void)array_size; + error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } else { len = bvlc_decode_foreign_device_table_entry( application_data, application_data_len, &fdt_entry); if (len > 0) { + fdt_list = Object_List[index].Network.IPv4.BBMD_FD_Table; status = bvlc_foreign_device_table_entry_insert( fdt_list, &fdt_entry, array_index - 1); if (status) { @@ -2359,8 +2365,6 @@ static BACNET_ERROR_CODE BBMD_Foreign_Device_Table_Element_Write( } else { error_code = ERROR_CODE_INVALID_DATA_TYPE; } - } else { - error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } } else { error_code = ERROR_CODE_ABORT_OTHER; diff --git a/src/bacnet/basic/object/schedule.c b/src/bacnet/basic/object/schedule.c index 9d8742a7..1e08a3d8 100644 --- a/src/bacnet/basic/object/schedule.c +++ b/src/bacnet/basic/object/schedule.c @@ -678,6 +678,8 @@ int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) * @param object_instance [in] BACnet network port object instance number * @param array_index [in] array index to write: * 0=array size, 1 to N for individual array members + * @param array_size [in] The total number of elements in the array, + * if writing array size * @param application_data [in] encoded element value * @param application_data_len [in] The size of the encoded element value * @return BACNET_ERROR_CODE value @@ -685,6 +687,7 @@ int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) static BACNET_ERROR_CODE Schedule_Weekly_Schedule_Element_Write( uint32_t object_instance, BACNET_ARRAY_INDEX array_index, + BACNET_UNSIGNED_INTEGER array_size, uint8_t *application_data, size_t application_data_len) { @@ -697,8 +700,11 @@ static BACNET_ERROR_CODE Schedule_Weekly_Schedule_Element_Write( pObject = Schedule_Object(object_instance); if (pObject) { if (array_index == 0) { + /* This array is not required to be resizable + through BACnet write services */ + (void)array_size; error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - } else if (array_index <= BACNET_WEEKLY_SCHEDULE_SIZE) { + } else { array_index--; len = bacnet_dailyschedule_context_decode( application_data, application_data_len, 0, &daily_schedule); @@ -718,8 +724,6 @@ static BACNET_ERROR_CODE Schedule_Weekly_Schedule_Element_Write( } else { error_code = ERROR_CODE_INVALID_DATA_TYPE; } - } else { - error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } } @@ -755,6 +759,8 @@ static int Schedule_Weekly_Schedule_Element_Length( * @param object_instance [in] BACnet network port object instance number * @param array_index [in] array index to write: * 0=array size, 1 to N for individual array members + * @param array_size [in] The total number of elements in the array, + * if writing array size * @param application_data [in] encoded element value * @param application_data_len [in] The size of the encoded element value * @return BACNET_ERROR_CODE value @@ -762,6 +768,7 @@ static int Schedule_Weekly_Schedule_Element_Length( static BACNET_ERROR_CODE Schedule_Exception_Schedule_Element_Write( uint32_t object_instance, BACNET_ARRAY_INDEX array_index, + BACNET_UNSIGNED_INTEGER array_size, uint8_t *application_data, size_t application_data_len) { @@ -773,8 +780,11 @@ static BACNET_ERROR_CODE Schedule_Exception_Schedule_Element_Write( pObject = Schedule_Object(object_instance); if (pObject) { if (array_index == 0) { + /* This array is not required to be resizable + through BACnet write services */ + (void)array_size; error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - } else if (array_index <= BACNET_WEEKLY_SCHEDULE_SIZE) { + } else { array_index--; len = bacnet_special_event_decode( application_data, application_data_len, &special_event); @@ -785,8 +795,6 @@ static BACNET_ERROR_CODE Schedule_Exception_Schedule_Element_Write( } else { error_code = ERROR_CODE_INVALID_DATA_TYPE; } - } else { - error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } } @@ -822,6 +830,8 @@ static int Schedule_Exception_Schedule_Element_Length( * @param object_instance [in] BACnet network port object instance number * @param array_index [in] array index to write: * 0=array size, 1 to N for individual array members + * @param array_size [in] The total number of elements in the array, + * if writing array size * @param application_data [in] encoded element value * @param application_data_len [in] The size of the encoded element value * @return BACNET_ERROR_CODE value @@ -829,6 +839,7 @@ static int Schedule_Exception_Schedule_Element_Length( static BACNET_ERROR_CODE Schedule_List_Of_Object_Property_References_Write( uint32_t object_instance, BACNET_ARRAY_INDEX array_index, + BACNET_UNSIGNED_INTEGER array_size, uint8_t *application_data, size_t application_data_len) { @@ -841,8 +852,11 @@ static BACNET_ERROR_CODE Schedule_List_Of_Object_Property_References_Write( pObject = Schedule_Object(object_instance); if (pObject) { if (array_index == 0) { - error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; - } else if (array_index <= BACNET_SCHEDULE_OBJ_PROP_REF_SIZE) { + /* This array is not required to be resizable + through BACnet write services */ + (void)array_size; + error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } else { len = bacapp_decode_known_property( application_data, application_data_len, &value, OBJECT_SCHEDULE, PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES); @@ -864,8 +878,6 @@ static BACNET_ERROR_CODE Schedule_List_Of_Object_Property_References_Write( } else { error_code = ERROR_CODE_ABORT_OTHER; } - } else { - error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } } diff --git a/src/bacnet/basic/object/timer.c b/src/bacnet/basic/object/timer.c index 2258b888..80cb05b5 100644 --- a/src/bacnet/basic/object/timer.c +++ b/src/bacnet/basic/object/timer.c @@ -1768,6 +1768,8 @@ static int Timer_State_Change_Value_Length( * @param object_instance [in] BACnet object instance number * @param array_index [in] array index to write: * 0=array size, 1 to N for individual array members + * @param array_size [in] The total number of elements in the array, + * if writing array size * @param application_data [in] encoded element value * @param application_data_len [in] The size of the encoded element value * @return BACNET_ERROR_CODE value @@ -1775,6 +1777,7 @@ static int Timer_State_Change_Value_Length( static BACNET_ERROR_CODE Timer_State_Change_Value_Write( uint32_t object_instance, BACNET_ARRAY_INDEX array_index, + BACNET_UNSIGNED_INTEGER array_size, uint8_t *application_data, size_t application_data_len) { @@ -1784,9 +1787,11 @@ static BACNET_ERROR_CODE Timer_State_Change_Value_Write( bool status; if (array_index == 0) { - /* fixed size array */ + /* This array is not required to be resizable + through BACnet write services */ + (void)array_size; error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - } else if (array_index < TIMER_TRANSITION_MAX) { + } else { len = bacnet_timer_value_decode( application_data, application_data_len, &new_value); if (len > 0) { @@ -1801,8 +1806,6 @@ static BACNET_ERROR_CODE Timer_State_Change_Value_Write( } else { error_code = ERROR_CODE_INVALID_DATA_TYPE; } - } else { - error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } return error_code; diff --git a/src/bacnet/basic/server/bacnet_device.c b/src/bacnet/basic/server/bacnet_device.c index dab84b42..9959622f 100644 --- a/src/bacnet/basic/server/bacnet_device.c +++ b/src/bacnet/basic/server/bacnet_device.c @@ -2397,6 +2397,7 @@ static int Device_Configuration_File_Length( * @param object_instance [in] BACnet object instance number * @param array_index [in] array index to write: * 0=array size, 1 to N for individual array members + * @param array_size [in] The total size of the array, if writing array size * @param application_data [in] encoded element value * @param application_data_len [in] The size of the encoded element value * @return BACNET_ERROR_CODE value @@ -2404,6 +2405,7 @@ static int Device_Configuration_File_Length( static BACNET_ERROR_CODE Device_Configuration_File_Write( uint32_t object_instance, BACNET_ARRAY_INDEX array_index, + BACNET_UNSIGNED_INTEGER array_size, uint8_t *application_data, size_t application_data_len) { @@ -2415,7 +2417,8 @@ static BACNET_ERROR_CODE Device_Configuration_File_Write( (void)object_instance; if (array_index == 0) { /* This array is not required to be resizable - through BACnet write services */ + through BACnet write services */ + (void)array_size; error_code = ERROR_CODE_WRITE_ACCESS_DENIED; } else if (array_index <= BACNET_BACKUP_FILE_COUNT) { len = bacnet_object_id_application_decode(