diff --git a/apps/blinkt/device.c b/apps/blinkt/device.c index d6529398..022bbb86 100644 --- a/apps/blinkt/device.c +++ b/apps/blinkt/device.c @@ -307,6 +307,35 @@ void Device_Objects_Property_List( return; } +/** + * @brief Determine if the object property is a member of this object instance + * @param object_type - object type of the object + * @param object_instance - object-instance number of the object + * @param object_property - object-property to be checked + * @return true if the property is a member of this object instance + */ +bool Device_Objects_Property_List_Member( + BACNET_OBJECT_TYPE object_type, + uint32_t object_instance, + BACNET_PROPERTY_ID object_property) +{ + bool found = false; + struct special_property_list_t property_list = { 0 }; + + Device_Objects_Property_List(object_type, object_instance, &property_list); + found = property_list_member(property_list.Required.pList, object_property); + if (!found) { + found = + property_list_member(property_list.Optional.pList, object_property); + } + if (!found) { + found = property_list_member( + property_list.Proprietary.pList, object_property); + } + + return found; +} + /* These three arrays are used by the ReadPropertyMultiple handler */ static const int Device_Properties_Required[] = { PROP_OBJECT_IDENTIFIER, @@ -1738,8 +1767,17 @@ bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) status = pObject->Object_Write_Property(wp_data); } } else { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + if (Device_Objects_Property_List_Member( + wp_data->object_type, wp_data->object_instance, + wp_data->object_property)) { + /* this property is not writable */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } else { + /* this property is not supported */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY; + } } } else { wp_data->error_class = ERROR_CLASS_OBJECT; diff --git a/apps/piface/device.c b/apps/piface/device.c index a429bc6a..9d7f206b 100644 --- a/apps/piface/device.c +++ b/apps/piface/device.c @@ -256,6 +256,35 @@ void Device_Objects_Property_List( return; } +/** + * @brief Determine if the object property is a member of this object instance + * @param object_type - object type of the object + * @param object_instance - object-instance number of the object + * @param object_property - object-property to be checked + * @return true if the property is a member of this object instance + */ +bool Device_Objects_Property_List_Member( + BACNET_OBJECT_TYPE object_type, + uint32_t object_instance, + BACNET_PROPERTY_ID object_property) +{ + bool found = false; + struct special_property_list_t property_list = { 0 }; + + Device_Objects_Property_List(object_type, object_instance, &property_list); + found = property_list_member(property_list.Required.pList, object_property); + if (!found) { + found = + property_list_member(property_list.Optional.pList, object_property); + } + if (!found) { + found = property_list_member( + property_list.Proprietary.pList, object_property); + } + + return found; +} + /* These three arrays are used by the ReadPropertyMultiple handler */ static const int Device_Properties_Required[] = { PROP_OBJECT_IDENTIFIER, diff --git a/ports/at91sam7s/Makefile b/ports/at91sam7s/Makefile index 389267cd..25f45612 100644 --- a/ports/at91sam7s/Makefile +++ b/ports/at91sam7s/Makefile @@ -38,7 +38,9 @@ CFLAGS = -fno-common $(INCLUDES) $(BACNET_FLAGS) -g CFLAGS += -mno-thumb-interwork # dead code removal CFLAGS += -fdata-sections -ffunction-sections - +# C standard to use for compiler +CSTANDARD = -std=gnu11 +CFLAGS += $(CSTANDARD) # enable all relevant warnings that find bugs WARNING_ALL := -Wall -Wextra -Wfloat-equal -Wconversion WARNING_ALL += -Wredundant-decls -Wswitch-default -pedantic @@ -51,11 +53,13 @@ WARNING_ALL += -Wno-implicit-fallthrough # the older Atmel SDK does not meet coding guidelines WARNING_ALL += -Wno-comment -Wno-missing-braces WARNING_ALL += -Wno-unused-variable -Wno-char-subscripts +# fix later +WARNING_ALL += -Wno-unused-parameter +WARNING_ALL += -Wno-type-limits +WARNING_ALL += -Wno-redundant-decls #WARNING_ALL += -Werror CFLAGS += $(WARNING_ALL) -CFLAGS += -Wno-char-subscripts - LIBRARY = lib$(TARGET).a # -Wa, Pass comma-separated on to the assembler AFLAGS = -Wa,-ahls,-mapcs-32,-adhlns=$(<:.s=.lst) diff --git a/ports/at91sam7s/device.c b/ports/at91sam7s/device.c index c12e4f72..458bb7f9 100644 --- a/ports/at91sam7s/device.c +++ b/ports/at91sam7s/device.c @@ -36,10 +36,6 @@ /* current version of the BACnet stack */ static const char *BACnet_Version = BACNET_VERSION_TEXT; -/* forward prototype */ -int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata); -bool Device_Write_Property_Local(BACNET_WRITE_PROPERTY_DATA *wp_data); - static struct my_object_functions { BACNET_OBJECT_TYPE Object_Type; object_init_function Object_Init; @@ -77,7 +73,7 @@ static struct my_object_functions { Network_Port_Object_Name, Network_Port_Read_Property, Network_Port_Write_Property, Network_Port_Property_Lists }, #endif - { MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL } }; + { MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } }; /* note: you really only need to define variables for properties that are writable or that may change. @@ -197,6 +193,67 @@ int Device_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) return apdu_len; } +/** + * @brief Handles the writing of the object name property + * @param wp_data [in,out] WriteProperty data structure + * @param Object_Write_Property object specific function to write the property + * @return True on success, else False if there is an error. + */ +static bool Device_Write_Property_Object_Name( + BACNET_WRITE_PROPERTY_DATA *wp_data, + write_property_function Object_Write_Property) +{ + bool status = false; /* return value */ + int len = 0; + BACNET_CHARACTER_STRING value; + BACNET_OBJECT_TYPE object_type = OBJECT_NONE; + uint32_t object_instance = 0; + int apdu_size = 0; + uint8_t *apdu = NULL; + + if (!wp_data) { + return false; + } + apdu = wp_data->application_data; + apdu_size = wp_data->application_data_len; + len = bacnet_character_string_application_decode(apdu, apdu_size, &value); + if (len > 0) { + if ((characterstring_encoding(&value) != CHARACTER_ANSI_X34) || + (characterstring_length(&value) == 0) || + (!characterstring_printable(&value))) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } else { + status = true; + } + } else if (len == 0) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + if (status) { + /* All the object names in a device must be unique */ + if (Device_Valid_Object_Name(&value, &object_type, &object_instance)) { + if ((object_type == wp_data->object_type) && + (object_instance == wp_data->object_instance)) { + /* writing same name to same object */ + status = true; + } else { + /* name already exists in some object */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_DUPLICATE_NAME; + status = false; + } + } else { + status = Object_Write_Property(wp_data); + } + } + + return status; +} + bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) { bool status = false; @@ -208,10 +265,30 @@ bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) if (pObject->Object_Valid_Instance && pObject->Object_Valid_Instance(wp_data->object_instance)) { if (pObject->Object_Write_Property) { - status = pObject->Object_Write_Property(wp_data); +#if (BACNET_PROTOCOL_REVISION >= 14) + if (wp_data->object_property == PROP_PROPERTY_LIST) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + return false; + } +#endif + if (wp_data->object_property == PROP_OBJECT_NAME) { + status = Device_Write_Property_Object_Name( + wp_data, pObject->Object_Write_Property); + } else { + status = pObject->Object_Write_Property(wp_data); + } } else { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + if (Device_Objects_Property_List_Member(wp_data->object_type, + wp_data->object_instance, wp_data->object_property)) { + /* this property is not writable */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } else { + /* this property is not supported */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY; + } } } else { wp_data->error_class = ERROR_CLASS_OBJECT; @@ -264,6 +341,35 @@ void Device_Objects_Property_List(BACNET_OBJECT_TYPE object_type, return; } +/** + * @brief Determine if the object property is a member of this object instance + * @param object_type - object type of the object + * @param object_instance - object-instance number of the object + * @param object_property - object-property to be checked + * @return true if the property is a member of this object instance + */ +bool Device_Objects_Property_List_Member( + BACNET_OBJECT_TYPE object_type, + uint32_t object_instance, + BACNET_PROPERTY_ID object_property) +{ + bool found = false; + struct special_property_list_t property_list = { 0 }; + + Device_Objects_Property_List(object_type, object_instance, &property_list); + found = property_list_member(property_list.Required.pList, object_property); + if (!found) { + found = + property_list_member(property_list.Optional.pList, object_property); + } + if (!found) { + found = property_list_member( + property_list.Proprietary.pList, object_property); + } + + return found; +} + void Device_Property_Lists( const int **pRequired, const int **pOptional, const int **pProprietary) { diff --git a/ports/bdk-atxx4-mstp/device.c b/ports/bdk-atxx4-mstp/device.c index e691a263..1fc63b70 100644 --- a/ports/bdk-atxx4-mstp/device.c +++ b/ports/bdk-atxx4-mstp/device.c @@ -160,6 +160,67 @@ int Device_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) return apdu_len; } +/** + * @brief Handles the writing of the object name property + * @param wp_data [in,out] WriteProperty data structure + * @param Object_Write_Property object specific function to write the property + * @return True on success, else False if there is an error. + */ +static bool Device_Write_Property_Object_Name( + BACNET_WRITE_PROPERTY_DATA *wp_data, + write_property_function Object_Write_Property) +{ + bool status = false; /* return value */ + int len = 0; + BACNET_CHARACTER_STRING value; + BACNET_OBJECT_TYPE object_type = OBJECT_NONE; + uint32_t object_instance = 0; + int apdu_size = 0; + uint8_t *apdu = NULL; + + if (!wp_data) { + return false; + } + apdu = wp_data->application_data; + apdu_size = wp_data->application_data_len; + len = bacnet_character_string_application_decode(apdu, apdu_size, &value); + if (len > 0) { + if ((characterstring_encoding(&value) != CHARACTER_ANSI_X34) || + (characterstring_length(&value) == 0) || + (!characterstring_printable(&value))) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } else { + status = true; + } + } else if (len == 0) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + if (status) { + /* All the object names in a device must be unique */ + if (Device_Valid_Object_Name(&value, &object_type, &object_instance)) { + if ((object_type == wp_data->object_type) && + (object_instance == wp_data->object_instance)) { + /* writing same name to same object */ + status = true; + } else { + /* name already exists in some object */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_DUPLICATE_NAME; + status = false; + } + } else { + status = Object_Write_Property(wp_data); + } + } + + return status; +} + bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) { bool status = false; @@ -171,10 +232,30 @@ bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) if (pObject->Object_Valid_Instance && pObject->Object_Valid_Instance(wp_data->object_instance)) { if (pObject->Object_Write_Property) { - status = pObject->Object_Write_Property(wp_data); +#if (BACNET_PROTOCOL_REVISION >= 14) + if (wp_data->object_property == PROP_PROPERTY_LIST) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + return false; + } +#endif + if (wp_data->object_property == PROP_OBJECT_NAME) { + status = Device_Write_Property_Object_Name( + wp_data, pObject->Object_Write_Property); + } else { + status = pObject->Object_Write_Property(wp_data); + } } else { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + if (Device_Objects_Property_List_Member(wp_data->object_type, + wp_data->object_instance, wp_data->object_property)) { + /* this property is not writable */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } else { + /* this property is not supported */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY; + } } } else { wp_data->error_class = ERROR_CLASS_OBJECT; @@ -241,6 +322,35 @@ void Device_Objects_Property_List(BACNET_OBJECT_TYPE object_type, return; } +/** + * @brief Determine if the object property is a member of this object instance + * @param object_type - object type of the object + * @param object_instance - object-instance number of the object + * @param object_property - object-property to be checked + * @return true if the property is a member of this object instance + */ +bool Device_Objects_Property_List_Member( + BACNET_OBJECT_TYPE object_type, + uint32_t object_instance, + BACNET_PROPERTY_ID object_property) +{ + bool found = false; + struct special_property_list_t property_list = { 0 }; + + Device_Objects_Property_List(object_type, object_instance, &property_list); + found = property_list_member(property_list.Required.pList, object_property); + if (!found) { + found = + property_list_member(property_list.Optional.pList, object_property); + } + if (!found) { + found = property_list_member( + property_list.Proprietary.pList, object_property); + } + + return found; +} + void Device_Property_Lists( const int **pRequired, const int **pOptional, const int **pProprietary) { diff --git a/ports/stm32f10x/device.c b/ports/stm32f10x/device.c index 8992659b..96aeb090 100644 --- a/ports/stm32f10x/device.c +++ b/ports/stm32f10x/device.c @@ -252,6 +252,35 @@ void Device_Objects_Property_List(BACNET_OBJECT_TYPE object_type, return; } +/** + * @brief Determine if the object property is a member of this object instance + * @param object_type - object type of the object + * @param object_instance - object-instance number of the object + * @param object_property - object-property to be checked + * @return true if the property is a member of this object instance + */ +bool Device_Objects_Property_List_Member( + BACNET_OBJECT_TYPE object_type, + uint32_t object_instance, + BACNET_PROPERTY_ID object_property) +{ + bool found = false; + struct special_property_list_t property_list = { 0 }; + + Device_Objects_Property_List(object_type, object_instance, &property_list); + found = property_list_member(property_list.Required.pList, object_property); + if (!found) { + found = + property_list_member(property_list.Optional.pList, object_property); + } + if (!found) { + found = property_list_member( + property_list.Proprietary.pList, object_property); + } + + return found; +} + void Device_Property_Lists( const int **pRequired, const int **pOptional, const int **pProprietary) { diff --git a/src/bacnet/basic/object/client/device-client.c b/src/bacnet/basic/object/client/device-client.c index ae5ff9ed..726682a9 100644 --- a/src/bacnet/basic/object/client/device-client.c +++ b/src/bacnet/basic/object/client/device-client.c @@ -274,6 +274,35 @@ void Device_Objects_Property_List( return; } +/** + * @brief Determine if the object property is a member of this object instance + * @param object_type - object type of the object + * @param object_instance - object-instance number of the object + * @param object_property - object-property to be checked + * @return true if the property is a member of this object instance + */ +bool Device_Objects_Property_List_Member( + BACNET_OBJECT_TYPE object_type, + uint32_t object_instance, + BACNET_PROPERTY_ID object_property) +{ + bool found = false; + struct special_property_list_t property_list = { 0 }; + + Device_Objects_Property_List(object_type, object_instance, &property_list); + found = property_list_member(property_list.Required.pList, object_property); + if (!found) { + found = + property_list_member(property_list.Optional.pList, object_property); + } + if (!found) { + found = property_list_member( + property_list.Proprietary.pList, object_property); + } + + return found; +} + /* These three arrays are used by the ReadPropertyMultiple handler */ static const int Device_Properties_Required[] = { PROP_OBJECT_IDENTIFIER, @@ -1300,8 +1329,17 @@ bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) status = pObject->Object_Write_Property(wp_data); } } else { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + if (Device_Objects_Property_List_Member( + wp_data->object_type, wp_data->object_instance, + wp_data->object_property)) { + /* this property is not writable */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } else { + /* this property is not supported */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY; + } } } else { wp_data->error_class = ERROR_CLASS_OBJECT; diff --git a/src/bacnet/basic/object/device.c b/src/bacnet/basic/object/device.c index 76b21c65..a09834bb 100644 --- a/src/bacnet/basic/object/device.c +++ b/src/bacnet/basic/object/device.c @@ -2017,8 +2017,17 @@ bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) Device_Write_Property_Store(wp_data); } } else { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + if (Device_Objects_Property_List_Member( + wp_data->object_type, wp_data->object_instance, + wp_data->object_property)) { + /* this property is not writable */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } else { + /* this property is not supported */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY; + } } } else { wp_data->error_class = ERROR_CLASS_OBJECT;