diff --git a/src/bacnet/basic/object/netport.c b/src/bacnet/basic/object/netport.c index 52337a8b..678e49aa 100644 --- a/src/bacnet/basic/object/netport.c +++ b/src/bacnet/basic/object/netport.c @@ -50,6 +50,10 @@ /* me */ #include "bacnet/basic/object/netport.h" +#if defined(BACDL_BIP6) || defined(BACDL_ALL) +#include "bacnet/datalink/bvlc6.h" +#endif + #ifndef BBMD_ENABLED #define BBMD_ENABLED 1 #endif @@ -89,7 +93,15 @@ struct bacnet_ipv6_port { uint8_t IP_DHCP_Server[IPV6_ADDR_SIZE]; uint16_t Port; BACNET_IP_MODE Mode; + bool Auto_Addressing_Enable; char Zone_Index[ZONE_INDEX_SIZE]; + bool BBMD_Accept_FD_Registrations; + void *BBMD_BD_Table; + void *BBMD_FD_Table; + /* used for foreign device registration to remote BBMD */ + uint8_t BBMD_IP_Address[16]; + uint16_t BBMD_Port; + uint16_t BBMD_Lifetime; }; struct ethernet_port { @@ -140,10 +152,15 @@ static const int MSTP_Port_Properties_Optional[] = { PROP_MAC_ADDRESS, static const int BIP_Port_Properties_Optional[] = { PROP_MAC_ADDRESS, PROP_BACNET_IP_MODE, PROP_IP_ADDRESS, PROP_BACNET_IP_UDP_PORT, PROP_IP_SUBNET_MASK, PROP_IP_DEFAULT_GATEWAY, PROP_IP_DNS_SERVER, -#if defined(BACDL_BIP) && BBMD_ENABLED + PROP_IP_DHCP_ENABLE, +#if (defined(BACDL_ALL) || defined(BACDL_BIP)) && (BBMD_ENABLED || BBMD_CLIENT_ENABLED) +#if (BBMD_ENABLED) PROP_BBMD_ACCEPT_FD_REGISTRATIONS, PROP_BBMD_BROADCAST_DISTRIBUTION_TABLE, - PROP_BBMD_FOREIGN_DEVICE_TABLE, PROP_FD_BBMD_ADDRESS, - PROP_FD_SUBSCRIPTION_LIFETIME, + PROP_BBMD_FOREIGN_DEVICE_TABLE, +#endif +#if (BBMD_CLIENT_ENABLED) + PROP_FD_BBMD_ADDRESS, PROP_FD_SUBSCRIPTION_LIFETIME, +#endif #endif -1 }; @@ -153,7 +170,17 @@ static const int BIP6_Port_Properties_Optional[] = { PROP_MAC_ADDRESS, PROP_BACNET_IPV6_MULTICAST_ADDRESS, PROP_IPV6_DNS_SERVER, PROP_IPV6_AUTO_ADDRESSING_ENABLE, PROP_IPV6_DHCP_LEASE_TIME, PROP_IPV6_DHCP_LEASE_TIME_REMAINING, PROP_IPV6_DHCP_SERVER, - PROP_IPV6_ZONE_INDEX, -1 }; + PROP_IPV6_ZONE_INDEX, +#if (defined(BACDL_ALL) || defined(BACDL_BIP6)) && (BBMD_ENABLED || BBMD_CLIENT_ENABLED) +#if (BBMD_ENABLED) + PROP_BBMD_ACCEPT_FD_REGISTRATIONS, PROP_BBMD_BROADCAST_DISTRIBUTION_TABLE, + PROP_BBMD_FOREIGN_DEVICE_TABLE, +#endif +#if (BBMD_CLIENT_ENABLED) + PROP_FD_BBMD_ADDRESS, PROP_FD_SUBSCRIPTION_LIFETIME, +#endif +#endif + -1 }; static const int Network_Port_Properties_Proprietary[] = { -1 }; @@ -1219,6 +1246,53 @@ bool Network_Port_IP_Gateway_Set( return status; } +/** + * For a given object instance-number, returns the IP_DHCP_Enable + * property value + * + * @param object_instance - object-instance number of the object + * + * @return IP_DHCP_Enable property value + */ +bool Network_Port_IP_DHCP_Enable(uint32_t object_instance) +{ + bool dhcp_enable = false; + unsigned index = 0; + + index = Network_Port_Instance_To_Index(object_instance); + if (index < BACNET_NETWORK_PORTS_MAX) { + if (Object_List[index].Network_Type == PORT_TYPE_BIP) { + dhcp_enable = Object_List[index].Network.IPv4.IP_DHCP_Enable; + } + } + + return dhcp_enable; +} + +/** + * For a given object instance-number, sets the IP_DHCP_Enable property value + * + * @param object_instance - object-instance number of the object + * @param value - boolean IP_DHCP_Enable value + * + * @return true if the IP_DHCP_Enable property value was set + */ +bool Network_Port_IP_DHCP_Enable_Set(uint32_t object_instance, bool value) +{ + bool status = false; + unsigned index = 0; + + index = Network_Port_Instance_To_Index(object_instance); + if (index < BACNET_NETWORK_PORTS_MAX) { + if (Object_List[index].Network_Type == PORT_TYPE_BIP) { + Object_List[index].Network.IPv4.IP_DHCP_Enable = value; + status = true; + } + } + + return status; +} + /** * For a given object instance-number, loads the subnet-mask-address into * an octet string. @@ -1574,7 +1648,7 @@ bool Network_Port_BBMD_FD_Table_Set(uint32_t object_instance, void *fdt_head) return status; } -#if defined(BACDL_BIP) && BBMD_ENABLED +#if (defined(BACDL_BIP) || defined(BACDL_ALL)) && (BBMD_ENABLED || BBMD_CLIENT_ENABLED) /** * For a given object instance-number, gets the ip-address and port * Note: depends on Network_Type being set for this object @@ -1643,6 +1717,7 @@ bool Network_Port_Remote_BBMD_IP_Address( if (d) { *d = Object_List[index].Network.IPv4.BBMD_IP_Address[3]; } + status = true; } } @@ -1670,10 +1745,18 @@ bool Network_Port_Remote_BBMD_IP_Address_Set( index = Network_Port_Instance_To_Index(object_instance); if (index < BACNET_NETWORK_PORTS_MAX) { if (Object_List[index].Network_Type == PORT_TYPE_BIP) { + if((Object_List[index].Network.IPv4.BBMD_IP_Address[0] != a) || + (Object_List[index].Network.IPv4.BBMD_IP_Address[1] != b) || + (Object_List[index].Network.IPv4.BBMD_IP_Address[2] != c) || + (Object_List[index].Network.IPv4.BBMD_IP_Address[3] != d)) { + Object_List[index].Changes_Pending = true; + } Object_List[index].Network.IPv4.BBMD_IP_Address[0] = a; Object_List[index].Network.IPv4.BBMD_IP_Address[1] = b; Object_List[index].Network.IPv4.BBMD_IP_Address[2] = c; Object_List[index].Network.IPv4.BBMD_IP_Address[3] = d; + + status = true; } } @@ -1784,6 +1867,359 @@ bool Network_Port_Remote_BBMD_BIP_Lifetime_Set( return status; } +/* IPv6 BBMD related getters and setters */ +#if (defined(BACDL_ALL) || defined(BACDL_BIP6)) + +/** + * For a given object instance-number, returns the BBMD-Accept-FD-Registrations + * property value + * + * @param object_instance - object-instance number of the object + * + * @return BBMD-Accept-FD-Registrations property value + */ +bool Network_Port_BBMD_IP6_Accept_FD_Registrations(uint32_t object_instance) +{ + bool flag = false; + unsigned index = 0; + struct bacnet_ipv6_port *ipv6 = NULL; + + index = Network_Port_Instance_To_Index(object_instance); + if (index < BACNET_NETWORK_PORTS_MAX) { + ipv6 = &Object_List[index].Network.IPv6; + flag = ipv6->BBMD_Accept_FD_Registrations; + } + + return flag; +} + +/** + * For a given object instance-number, sets the BBMD-Accept-FD-Registrations + * property value + * + * @param object_instance - object-instance number of the object + * @param flag - boolean changes-pending flag + * + * @return true if the BBMD-Accept-FD-Registrations property value was set + */ +bool Network_Port_BBMD_IP6_Accept_FD_Registrations_Set( + uint32_t object_instance, bool flag) +{ + bool status = false; + unsigned index = 0; + struct bacnet_ipv6_port *ipv6 = NULL; + + index = Network_Port_Instance_To_Index(object_instance); + if (index < BACNET_NETWORK_PORTS_MAX) { + ipv6 = &Object_List[index].Network.IPv6; + if (flag != ipv6->BBMD_Accept_FD_Registrations) { + ipv6->BBMD_Accept_FD_Registrations = flag; + Object_List[index].Changes_Pending = true; + } + status = true; + } + + return status; +} + + +/** + * For a given object instance-number, returns the BBMD-BD-Table head + * property value + * + * @param object_instance - object-instance number of the object + * + * @return BBMD-Accept-FD-Registrations property value + */ +void *Network_Port_BBMD_IP6_BD_Table(uint32_t object_instance) +{ + void *bdt_head = NULL; + unsigned index = 0; + struct bacnet_ipv6_port *ipv6 = NULL; + + index = Network_Port_Instance_To_Index(object_instance); + if (index < BACNET_NETWORK_PORTS_MAX) { + ipv6 = &Object_List[index].Network.IPv6; + bdt_head = ipv6->BBMD_BD_Table; + } + + return bdt_head; +} + +/** + * For a given object instance-number, sets the BBMD-BD-Table head + * property value + * + * @param object_instance - object-instance number of the object + * @param bdt_head - Broadcast Distribution Table linked list head + * + * @return true if the Broadcast Distribution Table linked list head + * property value was set + */ +bool Network_Port_BBMD_IP6_BD_Table_Set(uint32_t object_instance, void *bdt_head) +{ + bool status = false; + unsigned index = 0; + struct bacnet_ipv6_port *ipv6 = NULL; + + index = Network_Port_Instance_To_Index(object_instance); + if (index < BACNET_NETWORK_PORTS_MAX) { + ipv6 = &Object_List[index].Network.IPv6; + if (bdt_head != ipv6->BBMD_BD_Table) { + ipv6->BBMD_BD_Table = bdt_head; + Object_List[index].Changes_Pending = true; + } + status = true; + } + + return status; +} + +/** + * For a given object instance-number, returns the BBMD-FD-Table head + * property value + * + * @param object_instance - object-instance number of the object + * + * @return BBMD-Accept-FD-Registrations property value + */ +void *Network_Port_BBMD_IP6_FD_Table(uint32_t object_instance) +{ + void *fdt_head = NULL; + unsigned index = 0; + struct bacnet_ipv6_port *ipv6 = NULL; + + index = Network_Port_Instance_To_Index(object_instance); + if (index < BACNET_NETWORK_PORTS_MAX) { + ipv6 = &Object_List[index].Network.IPv6; + fdt_head = ipv6->BBMD_FD_Table; + } + + return fdt_head; +} + +/** + * For a given object instance-number, sets the BBMD-FD-Table head + * property value + * + * @param object_instance - object-instance number of the object + * @param fdt_head - Foreign Device Table linked list head + * + * @return true if the BBMD-Accept-FD-Registrations property value was set + */ +bool Network_Port_BBMD_IP6_FD_Table_Set(uint32_t object_instance, void *fdt_head) +{ + bool status = false; + unsigned index = 0; + struct bacnet_ipv6_port *ipv6 = NULL; + + index = Network_Port_Instance_To_Index(object_instance); + if (index < BACNET_NETWORK_PORTS_MAX) { + ipv6 = &Object_List[index].Network.IPv6; + if (fdt_head != ipv6->BBMD_FD_Table) { + ipv6->BBMD_FD_Table = fdt_head; + Object_List[index].Changes_Pending = true; + } + status = true; + } + + return status; +} + +#if (defined(BACDL_ALL) || defined(BACDL_BIP6)) && (BBMD_CLIENT_ENABLED) +/** + * For a given object instance-number, gets the ip-address and port + * Note: depends on Network_Type being set for this object + * + * @param object_instance - object-instance number of the object + * @param addr - holds the ip-address and port retrieved + * + * @return true if ip-address and port were retrieved + */ +static bool Network_Port_Remote_BBMD_IP6_Address_And_Port( + uint32_t object_instance, BACNET_IP6_ADDRESS *addr) +{ + unsigned index = 0; /* offset from instance lookup */ + bool status = false; + + if (addr) { + index = Network_Port_Instance_To_Index(object_instance); + if (index < BACNET_NETWORK_PORTS_MAX) { + if (Object_List[index].Network_Type == PORT_TYPE_BIP6) { + memcpy(addr->address, Object_List[index].Network.IPv6.BBMD_IP_Address, sizeof(addr->address)); + addr->port = Object_List[index].Network.IPv6.BBMD_Port; + status = true; + } + } + } + + return status; +} +#endif + +/** + * For a given object instance-number, loads the ip-address into + * an octet string. + * Note: depends on Network_Type being set for this object + * + * @param object_instance - object-instance number of the object + * @param addr - pointer to IP6_ADDRESS_MAX = 16 octets buffer + * + * @return true if ip-address was retrieved + */ +bool Network_Port_Remote_BBMD_IP6_Address( + uint32_t object_instance, uint8_t *addr) +{ + unsigned index = 0; /* offset from instance lookup */ + bool status = false; + + index = Network_Port_Instance_To_Index(object_instance); + if (index < BACNET_NETWORK_PORTS_MAX) { + if (Object_List[index].Network_Type == PORT_TYPE_BIP6) { + if (addr) { + memcpy(addr, Object_List[index].Network.IPv6.BBMD_IP_Address, IP6_ADDRESS_MAX); + status = true; + } + } + } + + return status; +} + +/** + * For a given object instance-number, sets the ip-address + * Note: depends on Network_Type being set for this object + * + * @param object_instance - object-instance number of the object + * @param addr - pointer to IP6_ADDRESS_MAX = 16 octets buffer + * + * @return true if ip-address was set + */ +bool Network_Port_Remote_BBMD_IP6_Address_Set( + uint32_t object_instance, uint8_t *addr) +{ + unsigned index = 0; /* offset from instance lookup */ + bool status = false; + + index = Network_Port_Instance_To_Index(object_instance); + if (index < BACNET_NETWORK_PORTS_MAX) { + if (Object_List[index].Network_Type == PORT_TYPE_BIP6) { + if(memcmp(Object_List[index].Network.IPv6.BBMD_IP_Address, addr, IP6_ADDRESS_MAX)) { + memcpy(Object_List[index].Network.IPv6.BBMD_IP_Address, addr, IP6_ADDRESS_MAX); + Object_List[index].Changes_Pending = true; + } + status = true; + } + } + + return status; +} + +/** + * For a given object instance-number, gets the BBMD UDP Port number + * Note: depends on Network_Type being set to PORT_TYPE_BIP for this object + * + * @param object_instance - object-instance number of the object + * + * @return BBMD UDP Port number + */ +uint16_t Network_Port_Remote_BBMD_BIP6_Port(uint32_t object_instance) +{ + uint16_t value = 0; + unsigned index = 0; + + index = Network_Port_Instance_To_Index(object_instance); + if (index < BACNET_NETWORK_PORTS_MAX) { + if (Object_List[index].Network_Type == PORT_TYPE_BIP6) { + value = Object_List[index].Network.IPv6.BBMD_Port; + } + } + + return value; +} + +/** + * For a given object instance-number, sets the BBMD UDP Port number + * Note: depends on Network_Type being set to PORT_TYPE_BIP for this object + * + * @param object_instance - object-instance number of the object + * @param value - BBMD UDP Port number (default=0xBAC0) + * + * @return true if values are within range and property is set. + */ +bool Network_Port_Remote_BBMD_BIP6_Port_Set( + uint32_t object_instance, uint16_t value) +{ + bool status = false; + unsigned index = 0; + + index = Network_Port_Instance_To_Index(object_instance); + if (index < BACNET_NETWORK_PORTS_MAX) { + if (Object_List[index].Network_Type == PORT_TYPE_BIP6) { + if (Object_List[index].Network.IPv6.BBMD_Port != value) { + Object_List[index].Changes_Pending = true; + } + Object_List[index].Network.IPv6.BBMD_Port = value; + status = true; + } + } + + return status; +} + +/** + * For a given object instance-number, gets the BBMD lifetime seconds + * Note: depends on Network_Type being set to PORT_TYPE_BIP for this object + * + * @param object_instance - object-instance number of the object + * + * @return BBMD lifetime seconds + */ +uint16_t Network_Port_Remote_BBMD_BIP6_Lifetime(uint32_t object_instance) +{ + uint16_t value = 0; + unsigned index = 0; + + index = Network_Port_Instance_To_Index(object_instance); + if (index < BACNET_NETWORK_PORTS_MAX) { + if (Object_List[index].Network_Type == PORT_TYPE_BIP6) { + value = Object_List[index].Network.IPv6.BBMD_Lifetime; + } + } + + return value; +} + +/** + * For a given object instance-number, sets the BBMD lifetime seconds + * Note: depends on Network_Type being set to PORT_TYPE_BIP for this object + * + * @param object_instance - object-instance number of the object + * @param value - BBMD lifetime seconds + * + * @return true if values are within range and property is set. + */ +bool Network_Port_Remote_BBMD_BIP6_Lifetime_Set( + uint32_t object_instance, uint16_t value) +{ + bool status = false; + unsigned index = 0; + + index = Network_Port_Instance_To_Index(object_instance); + if (index < BACNET_NETWORK_PORTS_MAX) { + if (Object_List[index].Network_Type == PORT_TYPE_BIP6) { + if (Object_List[index].Network.IPv6.BBMD_Lifetime != value) { + Object_List[index].Changes_Pending = true; + } + Object_List[index].Network.IPv6.BBMD_Lifetime = value; + status = true; + } + } + + return status; +} +#endif + /** * For a given object instance-number, gets the BACnet/IP UDP Port number * Note: depends on Network_Type being set to PORT_TYPE_BIP for this object @@ -2286,6 +2722,57 @@ bool Network_Port_IPv6_Zone_Index( return status; } +/** + * For a given object instance-number, returns the BACnet IPv6 Auto Addressing Enable + * property value + * + * @param object_instance - object-instance number of the object + * + * @return auto-Addressing-Enable property value + */ +bool Network_Port_IPv6_Auto_Addressing_Enable(uint32_t object_instance) +{ + bool flag = false; + unsigned index = 0; + struct bacnet_ipv6_port *ipv6 = NULL; + + index = Network_Port_Instance_To_Index(object_instance); + if (index < BACNET_NETWORK_PORTS_MAX) { + ipv6 = &Object_List[index].Network.IPv6; + flag = ipv6->Auto_Addressing_Enable; + } + + return flag; +} + +/** + * For a given object instance-number, sets the BACnet/IP6 Auto Addressing Enable + * Note: depends on Network_Type being set to PORT_TYPE_BIP6 for this object + * + * @param object_instance - object-instance number of the object + * @param value - BACnet/IP6 Audo Addressing Enable (default false) + * + * @return true if values are within range and property is set. + */ +bool Network_Port_IPv6_Auto_Addressing_Enable_Set(uint32_t object_instance, bool value) +{ + bool status = false; + unsigned index = 0; + + index = Network_Port_Instance_To_Index(object_instance); + if (index < BACNET_NETWORK_PORTS_MAX) { + if (Object_List[index].Network_Type == PORT_TYPE_BIP6) { + if (Object_List[index].Network.IPv6.Auto_Addressing_Enable != value) { + Object_List[index].Changes_Pending = true; + } + Object_List[index].Network.IPv6.Auto_Addressing_Enable = value; + status = true; + } + } + + return status; +} + /** * For a given object instance-number, sets the gateway ip-address * Note: depends on Network_Type being set for this object @@ -2410,18 +2897,33 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) BACNET_BIT_STRING bit_string; BACNET_OCTET_STRING octet_string; BACNET_CHARACTER_STRING char_string; -#if defined(BACDL_BIP) && BBMD_ENABLED +#if (defined(BACDL_ALL) || defined(BACDL_BIP)) && (BBMD_ENABLED || BBMD_CLIENT_ENABLED) BACNET_IP_ADDRESS ip_address; +#endif +#if (defined(BACDL_ALL) || defined(BACDL_BIP6)) && (BBMD_CLIENT_ENABLED) + BACNET_IP6_ADDRESS ip6_address; #endif uint8_t *apdu = NULL; const int *pRequired = NULL; const int *pOptional = NULL; const int *pProprietary = NULL; + uint8_t network_type = PORT_TYPE_NON_BACNET; + unsigned int index = 0; + if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } + +#if (!BBMD_CLIENT_ENABLED) + (void) network_type; +#endif + + if ((index = Network_Port_Instance_To_Index(rpdata->object_instance)) < BACNET_NETWORK_PORTS_MAX) { + network_type = Object_List[index].Network_Type; + } + Network_Port_Property_List( rpdata->object_instance, &pRequired, &pOptional, &pProprietary); if ((!property_list_member(pRequired, rpdata->object_property)) && @@ -2534,6 +3036,10 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) Network_Port_IP_Gateway(rpdata->object_instance, &octet_string); apdu_len = encode_application_octet_string(&apdu[0], &octet_string); break; + case PROP_IP_DHCP_ENABLE: + apdu_len = encode_application_boolean( + &apdu[0], Network_Port_IP_DHCP_Enable(rpdata->object_instance)); + break; case PROP_IP_DNS_SERVER: apdu_len = bacnet_array_encode(rpdata->object_instance, rpdata->array_index, Network_Port_IP_DNS_Server_Encode, @@ -2547,32 +3053,108 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) apdu_len = BACNET_STATUS_ERROR; } break; -#if defined(BACDL_BIP) && BBMD_ENABLED +#if (defined(BACDL_BIP) || defined (BACDL_BIP6) || defined(BACDL_ALL)) && (BBMD_ENABLED || BBMD_CLIENT_ENABLED) +#if (BBMD_ENABLED) case PROP_BBMD_ACCEPT_FD_REGISTRATIONS: apdu_len = encode_application_boolean(&apdu[0], Network_Port_BBMD_Accept_FD_Registrations( rpdata->object_instance)); break; case PROP_BBMD_BROADCAST_DISTRIBUTION_TABLE: - apdu_len = bvlc_broadcast_distribution_table_encode(&apdu[0], - rpdata->application_data_len, - Network_Port_BBMD_BD_Table(rpdata->object_instance)); + switch(network_type) { +#if (defined(BACDL_ALL) || defined(BACDL_BIP)) + case PORT_TYPE_BIP: + apdu_len = bvlc_broadcast_distribution_table_encode(&apdu[0], + rpdata->application_data_len, + Network_Port_BBMD_BD_Table(rpdata->object_instance)); + break; +#endif +#if (defined(BACDL_ALL) || defined(BACDL_BIP6)) + case PORT_TYPE_BIP6: + apdu_len = bvlc6_broadcast_distribution_table_encode(&apdu[0], + rpdata->application_data_len, + Network_Port_BBMD_IP6_BD_Table(rpdata->object_instance)); + break; +#endif + default: + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + apdu_len = BACNET_STATUS_ERROR; + break; + } break; case PROP_BBMD_FOREIGN_DEVICE_TABLE: - apdu_len = bvlc_foreign_device_table_encode(&apdu[0], - rpdata->application_data_len, - Network_Port_BBMD_FD_Table(rpdata->object_instance)); + switch(network_type) { +#if (defined(BACDL_ALL) || defined(BACDL_BIP)) + case PORT_TYPE_BIP: + apdu_len = bvlc_foreign_device_table_encode(&apdu[0], + rpdata->application_data_len, + Network_Port_BBMD_FD_Table(rpdata->object_instance)); + break; +#endif +#if (defined(BACDL_ALL) || defined(BACDL_BIP6)) + case PORT_TYPE_BIP6: + apdu_len = bvlc6_foreign_device_table_encode(&apdu[0], + rpdata->application_data_len, + Network_Port_BBMD_IP6_FD_Table(rpdata->object_instance)); + break; +#endif + default: + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + apdu_len = BACNET_STATUS_ERROR; + break; + } break; +#endif /* BBMD_ENABLED */ +#if (BBMD_CLIENT_ENABLED) case PROP_FD_BBMD_ADDRESS: - Network_Port_Remote_BBMD_IP_Address_And_Port( - rpdata->object_instance, &ip_address); - apdu_len = bvlc_foreign_device_bbmd_host_address_encode( - &apdu[0], apdu_size, &ip_address); + switch(network_type) { +#if (defined(BACDL_BIP) || defined(BACDL_ALL)) && (BBMD_ENABLED || BBMD_CLIENT_ENABLED) + case PORT_TYPE_BIP: + Network_Port_Remote_BBMD_IP_Address_And_Port( + rpdata->object_instance, &ip_address); + apdu_len = bvlc_foreign_device_bbmd_host_address_encode( + &apdu[0], apdu_size, &ip_address); + break; +#endif +#if (defined(BACDL_ALL) || defined(BACDL_BIP6)) + case PORT_TYPE_BIP6: + Network_Port_Remote_BBMD_IP6_Address_And_Port( + rpdata->object_instance, &ip6_address); + apdu_len = bvlc6_foreign_device_bbmd_host_address_encode( + &apdu[0], apdu_size, &ip6_address); + break; +#endif + default: + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + apdu_len = BACNET_STATUS_ERROR; + break; + } break; case PROP_FD_SUBSCRIPTION_LIFETIME: - apdu_len = encode_application_unsigned(&apdu[0], - Network_Port_Remote_BBMD_BIP_Lifetime(rpdata->object_instance)); + switch(network_type) { +#if (defined(BACDL_ALL) || defined(BACDL_BIP)) + case PORT_TYPE_BIP: + apdu_len = encode_application_unsigned(&apdu[0], + Network_Port_Remote_BBMD_BIP_Lifetime(rpdata->object_instance)); + break; +#endif +#if (defined(BACDL_ALL) || defined(BACDL_BIP6)) + case PORT_TYPE_BIP6: + apdu_len = encode_application_unsigned(&apdu[0], + Network_Port_Remote_BBMD_BIP6_Lifetime(rpdata->object_instance)); + break; +#endif + default: + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + apdu_len = BACNET_STATUS_ERROR; + break; + } break; +#endif #endif case PROP_BACNET_IPV6_MODE: apdu_len = encode_application_enumerated( @@ -2613,7 +3195,7 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) } break; case PROP_IPV6_AUTO_ADDRESSING_ENABLE: - apdu_len = encode_application_boolean(&apdu[0], false); + apdu_len = encode_application_boolean(&apdu[0], Network_Port_IPv6_Auto_Addressing_Enable(rpdata->object_instance)); break; case PROP_IPV6_DHCP_LEASE_TIME: apdu_len = encode_application_unsigned(&apdu[0], 0); @@ -2671,8 +3253,13 @@ bool Network_Port_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) return false; } /* decode the some of the request */ +#if !defined(BACAPP_COMPLEX_TYPES) len = bacapp_decode_application_data( wp_data->application_data, wp_data->application_data_len, &value); +#else + len = bacapp_decode_generic_property( + wp_data->application_data, wp_data->application_data_len, &value, wp_data->object_property); +#endif if (len < 0) { /* error while decoding - a value larger than we can handle */ wp_data->error_class = ERROR_CLASS_PROPERTY; @@ -2728,6 +3315,115 @@ bool Network_Port_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) } } break; +#if (BBMD_CLIENT_ENABLED) + case PROP_FD_BBMD_ADDRESS: + if(write_property_type_valid( wp_data, &value, BACNET_APPLICATION_TAG_HOST_N_PORT)) { + switch(Network_Port_Type(wp_data->object_instance)) { +#if (defined(BACDL_ALL) || defined(BACDL_BIP)) + case PORT_TYPE_BIP: + if(Network_Port_BIP_Mode(wp_data->object_instance) == BACNET_IP_MODE_FOREIGN) { + if(value.type.Host_Address.host.ip_address.length == 4) { + status = Network_Port_Remote_BBMD_IP_Address_Set( + wp_data->object_instance, + value.type.Host_Address.host.ip_address.value[0], + value.type.Host_Address.host.ip_address.value[1], + value.type.Host_Address.host.ip_address.value[2], + value.type.Host_Address.host.ip_address.value[3]); + + if(status) { + status = Network_Port_Remote_BBMD_BIP_Port_Set(wp_data->object_instance, value.type.Host_Address.port); + } + } + + if (!status) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } + break; +#endif +#if (defined(BACDL_ALL) || defined(BACDL_BIP6)) + case PORT_TYPE_BIP6: + if(Network_Port_BIP_Mode(wp_data->object_instance) == BACNET_IP_MODE_FOREIGN) { + if(value.type.Host_Address.host.ip_address.length == 16) { + status = Network_Port_Remote_BBMD_IP6_Address_Set( + wp_data->object_instance, + &value.type.Host_Address.host.ip_address.value[0]); + + if(status) { + status = Network_Port_Remote_BBMD_BIP6_Port_Set(wp_data->object_instance, value.type.Host_Address.port); + } + } + + if (!status) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } + break; +#endif + default: + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + break; + } + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + break; + case PROP_FD_SUBSCRIPTION_LIFETIME: + if(write_property_type_valid(wp_data, &value, BACNET_APPLICATION_TAG_UNSIGNED_INT)) { + if (value.type.Unsigned_Int <= 65535) { + switch(Network_Port_Type(wp_data->object_instance)) { +#if (defined(BACDL_ALL) || defined(BACDL_BIP)) + case PORT_TYPE_BIP: + if(Network_Port_BIP_Mode(wp_data->object_instance) == BACNET_IP_MODE_FOREIGN) { + status = Network_Port_Remote_BBMD_BIP_Lifetime_Set( + wp_data->object_instance, value.type.Unsigned_Int); + if (!status) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } + break; +#endif +#if (defined(BACDL_ALL) || defined(BACDL_BIP6)) + case PORT_TYPE_BIP6: + if(Network_Port_BIP6_Mode(wp_data->object_instance) == BACNET_IP_MODE_FOREIGN) { + status = Network_Port_Remote_BBMD_BIP6_Lifetime_Set( + wp_data->object_instance, value.type.Unsigned_Int); + if (!status) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } + break; +#endif + default: + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + break; + } + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } + break; +#endif default: if (Property_List_Member( wp_data->object_instance, wp_data->object_property)) { diff --git a/src/bacnet/basic/object/netport.h b/src/bacnet/basic/object/netport.h index fa8277cb..f6113e53 100644 --- a/src/bacnet/basic/object/netport.h +++ b/src/bacnet/basic/object/netport.h @@ -222,6 +222,14 @@ extern "C" { uint32_t object_instance, uint8_t a, uint8_t b, uint8_t c, uint8_t d); + + BACNET_STACK_EXPORT + bool Network_Port_IP_DHCP_Enable( + uint32_t object_instance); + BACNET_STACK_EXPORT + bool Network_Port_IP_DHCP_Enable_Set( + uint32_t object_instance, bool value); + BACNET_STACK_EXPORT bool Network_Port_IP_DNS_Server( uint32_t object_instance, @@ -298,6 +306,52 @@ extern "C" { uint32_t object_instance, uint16_t value); +#if (defined(BACDL_ALL) || defined(BACDL_BIP6)) + BACNET_STACK_EXPORT + bool Network_Port_BBMD_IP6_Accept_FD_Registrations( + uint32_t object_instance); + BACNET_STACK_EXPORT + bool Network_Port_BBMD_IP6_Accept_FD_Registrations_Set( + uint32_t object_instance, + bool value); + + BACNET_STACK_EXPORT + void *Network_Port_BBMD_IP6_BD_Table(uint32_t object_instance); + BACNET_STACK_EXPORT + bool Network_Port_BBMD_IP6_BD_Table_Set( + uint32_t object_instance, + void *bdt_head); + BACNET_STACK_EXPORT + void *Network_Port_BBMD_IP6_FD_Table(uint32_t object_instance); + BACNET_STACK_EXPORT + bool Network_Port_BBMD_IP6_FD_Table_Set( + uint32_t object_instance, + void *fdt_head); + + BACNET_STACK_EXPORT + bool Network_Port_Remote_BBMD_IP6_Address( + uint32_t object_instance, + uint8_t *addr); + BACNET_STACK_EXPORT + bool Network_Port_Remote_BBMD_IP6_Address_Set( + uint32_t object_instance, + uint8_t *addr); + BACNET_STACK_EXPORT + uint16_t Network_Port_Remote_BBMD_BIP6_Port( + uint32_t object_instance); + BACNET_STACK_EXPORT + bool Network_Port_Remote_BBMD_BIP6_Port_Set( + uint32_t object_instance, + uint16_t value); + BACNET_STACK_EXPORT + uint16_t Network_Port_Remote_BBMD_BIP6_Lifetime( + uint32_t object_instance); + BACNET_STACK_EXPORT + bool Network_Port_Remote_BBMD_BIP6_Lifetime_Set( + uint32_t object_instance, + uint16_t value); +#endif + BACNET_STACK_EXPORT BACNET_IP_MODE Network_Port_BIP6_Mode( uint32_t object_instance); @@ -370,6 +424,13 @@ extern "C" { uint32_t object_instance, char *zone_index); + BACNET_STACK_EXPORT + bool Network_Port_IPv6_Auto_Addressing_Enable( + uint32_t object_instance); + BACNET_STACK_EXPORT + bool Network_Port_IPv6_Auto_Addressing_Enable_Set( + uint32_t object_instance, bool value); + BACNET_STACK_EXPORT uint16_t Network_Port_BIP6_Port( uint32_t object_instance); diff --git a/src/bacnet/datalink/bvlc6.c b/src/bacnet/datalink/bvlc6.c index 46ebd388..7e631e87 100644 --- a/src/bacnet/datalink/bvlc6.c +++ b/src/bacnet/datalink/bvlc6.c @@ -35,13 +35,11 @@ #include /* for standard integer types uint8_t etc. */ #include /* for the standard bool type. */ #include -/* BACnet Stack defines - first */ -#include "bacnet/bacdef.h" -/* BACnet Stack API */ -#include "bacnet/bacapp.h" +#include "bacnet/bacenum.h" #include "bacnet/bacdcode.h" #include "bacnet/bacint.h" #include "bacnet/datalink/bvlc6.h" +#include "bacnet/hostnport.h" /** Encode the BVLC header * @@ -1578,3 +1576,161 @@ int bvlc6_decode_distribute_broadcast_to_network(uint8_t *pdu, return bytes_consumed; } + +/** + * @brief Encode a BBMD Address for Network Port object + * @param apdu - the APDU buffer + * @param apdu_size - the APDU buffer size + * @param ip6_address - IPv6 address and port number + * @return length of the APDU buffer + */ +int bvlc6_foreign_device_bbmd_host_address_encode( + uint8_t *apdu, uint16_t apdu_size, BACNET_IP6_ADDRESS *ip6_address) +{ + BACNET_HOST_N_PORT address = { 0 }; + int apdu_len = 0; + + address.host_ip_address = true; + address.host_name = false; + octetstring_init( + &address.host.ip_address, &ip6_address->address[0], IP6_ADDRESS_MAX); + address.port = ip6_address->port; + apdu_len = host_n_port_encode(NULL, &address); + if (apdu_len <= apdu_size) { + apdu_len = host_n_port_encode(apdu, &address); + } + + return apdu_len; +} + +/** + * @brief Encode the Broadcast-Distribution-Table for Network Port object + * + * BACnetLIST of BACnetBDTEntry + * + * BACnetBDTEntry ::= SEQUENCE { + * bbmd-address [0] BACnetHostNPort, + * BACnetHostNPort ::= SEQUENCE { + * host [0] BACnetHostAddress, + * BACnetHostAddress ::= CHOICE { + * ip-address [1] OCTET STRING, -- 4 octets for B/IP + * } + * port [1] Unsigned16 + * } + * broadcast-mask [1] OCTET STRING -- shall be present if BACnet/IP, and absent for BACnet/IPv6 + * } + * + * @param apdu - the APDU buffer + * @param apdu_size - the APDU buffer size + * @param bdt_head - head of the BDT linked list + * @return length of the APDU buffer + */ +int bvlc6_broadcast_distribution_table_encode(uint8_t *apdu, + uint16_t apdu_size, + BACNET_IP6_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_head) +{ + int len = 0; + int apdu_len = 0; + int entry_size = 0; + BACNET_OCTET_STRING octet_string; + BACNET_IP6_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_entry; + + bdt_entry = bdt_head; + while (bdt_entry) { + if (bdt_entry->valid) { + /* bbmd-address [0] BACnetHostNPort - opening */ + len = encode_opening_tag(&apdu[apdu_len], 0); + apdu_len += len; + /* host [0] BACnetHostAddress - opening */ + len = encode_opening_tag(&apdu[apdu_len], 0); + apdu_len += len; + /* CHOICE - ip-address [1] OCTET STRING */ + octetstring_init(&octet_string, &bdt_entry->bip6_address.address[0], + IP6_ADDRESS_MAX); + len = + encode_context_octet_string(&apdu[apdu_len], 1, &octet_string); + apdu_len += len; + /* host [0] BACnetHostAddress - closing */ + len = encode_closing_tag(&apdu[apdu_len], 0); + apdu_len += len; + /* port [1] Unsigned16 */ + len = encode_context_unsigned( + &apdu[apdu_len], 1, bdt_entry->bip6_address.port); + apdu_len += len; + /* bbmd-address [0] BACnetHostNPort - closing */ + len = encode_closing_tag(&apdu[apdu_len], 0); + apdu_len += len; + } + if (!entry_size) { + entry_size = apdu_len; + } + /* next entry */ + bdt_entry = bdt_entry->next; + if ((apdu_len + entry_size) > apdu_size) { + /* check for available space */ + break; + } + } + + return apdu_len; +} + +/** + * @brief Encode the Foreign_Device-Table for Network Port object + * + * BACnetLIST of BACnetFDTEntry + * + * BACnetFDTEntry ::= SEQUENCE { + * bacnetip-address [0] OCTET STRING, -- the 6-octet B/IP or 18-octet B/IPv6 address of the registrant + * time-to-live [1] Unsigned16, -- time to live in seconds + * remaining-time-to-live [2] Unsigned16 -- remaining time in seconds + * } + * + * @param apdu - the APDU buffer + * @param apdu_size - the APDU buffer size + * @param fdt_head - head of the BDT linked list + * @return length of the APDU buffer + */ +int bvlc6_foreign_device_table_encode(uint8_t *apdu, + uint16_t apdu_size, + BACNET_IP6_FOREIGN_DEVICE_TABLE_ENTRY *fdt_head) +{ + int len = 0; + int apdu_len = 0; + int entry_size = 0; + BACNET_OCTET_STRING octet_string = { 0 }; + BACNET_IP6_FOREIGN_DEVICE_TABLE_ENTRY *fdt_entry; + + fdt_entry = fdt_head; + while (fdt_entry) { + if (fdt_entry->valid) { + /* bacnetip-address [0] OCTET STRING */ + len = bvlc6_encode_address(octetstring_value(&octet_string), + octetstring_capacity(&octet_string), &fdt_entry->bip6_address); + octetstring_truncate(&octet_string, len); + len = + encode_context_octet_string(&apdu[apdu_len], 0, &octet_string); + apdu_len += len; + /* time-to-live [1] Unsigned16 */ + len = encode_context_unsigned( + &apdu[apdu_len], 1, fdt_entry->ttl_seconds); + apdu_len += len; + /* remaining-time-to-live [2] Unsigned16 */ + len = encode_context_unsigned( + &apdu[apdu_len], 2, fdt_entry->ttl_seconds_remaining); + apdu_len += len; + } + if (!entry_size) { + entry_size = apdu_len; + } + /* next entry */ + fdt_entry = fdt_entry->next; + if ((apdu_len + entry_size) > apdu_size) { + /* check for available space */ + break; + } + } + + return apdu_len; +} + diff --git a/src/bacnet/datalink/bvlc6.h b/src/bacnet/datalink/bvlc6.h index 438067bf..6778251a 100644 --- a/src/bacnet/datalink/bvlc6.h +++ b/src/bacnet/datalink/bvlc6.h @@ -53,6 +53,7 @@ #define BVLC6_RESULT_REGISTER_FOREIGN_DEVICE_NAK 0x0090U #define BVLC6_RESULT_DELETE_FOREIGN_DEVICE_NAK 0x00A0U #define BVLC6_RESULT_DISTRIBUTE_BROADCAST_TO_NETWORK_NAK 0x00C0U +#define BVLC6_RESULT_INVALID 0xFFFFU /** @} */ /** @@ -420,6 +421,19 @@ extern "C" { uint8_t * npdu, uint16_t npdu_size, uint16_t * npdu_len); + BACNET_STACK_EXPORT + int bvlc6_foreign_device_bbmd_host_address_encode(uint8_t *apdu, + uint16_t apdu_size, + BACNET_IP6_ADDRESS *ip6_address); + BACNET_STACK_EXPORT + int bvlc6_broadcast_distribution_table_encode(uint8_t *apdu, + uint16_t apdu_size, + BACNET_IP6_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_head); + BACNET_STACK_EXPORT + int bvlc6_foreign_device_table_encode(uint8_t *apdu, + uint16_t apdu_size, + BACNET_IP6_FOREIGN_DEVICE_TABLE_ENTRY *fdt_head); + #ifdef __cplusplus } diff --git a/test/bacnet/basic/bbmd6/CMakeLists.txt b/test/bacnet/basic/bbmd6/CMakeLists.txt index 92d8b452..65edb244 100644 --- a/test/bacnet/basic/bbmd6/CMakeLists.txt +++ b/test/bacnet/basic/bbmd6/CMakeLists.txt @@ -44,6 +44,7 @@ add_executable(${PROJECT_NAME} ${SRC_DIR}/bacnet/basic/bbmd6/h_bbmd6.c ${SRC_DIR}/bacnet/basic/bbmd6/vmac.c ${SRC_DIR}/bacnet/datalink/bvlc6.c + ${SRC_DIR}/bacnet/hostnport.c # Test and test library files ./src/main.c )