/** * @file * @brief Helper Network port objects for implement secure connect attributes * @author Mikhail Antropov * @date June 2022 * @copyright SPDX-License-Identifier: MIT */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* me */ #include #include #include #include #include #define SC_MIN_RECONNECT_MIN 2 #define SC_MIN_RECONNECT_MAX 300 #define SC_MAX_RECONNECT_MIN 2 #define SC_MAX_RECONNECT_MAX 600 #define SC_WAIT_CONNECT_MIN 5 #define SC_WAIT_CONNECT_MAX 300 static int string_splite(const char *str, char separator, int *indexes, int length); static bool string_subsstr(char *str, int length, int index, const char *substr); static void sc_binding_parse(char *str, uint16_t *port, char **ifname) { char *p = NULL; *port = 0; *ifname = NULL; if (str != NULL) { for (p = str; (*p != 0) && (*p != BACNET_SC_BINDING_SEPARATOR); ++p) ; if (p != str) { if (*p == BACNET_SC_BINDING_SEPARATOR) { *p = 0; *port = (uint16_t)strtol(p + 1, NULL, 0); *ifname = (char *)str; } else { *port = (uint16_t)strtol(str, NULL, 0); *ifname = NULL; } } } } BACNET_UNSIGNED_INTEGER Network_Port_Max_BVLC_Length_Accepted(uint32_t object_instance) { BACNET_UNSIGNED_INTEGER max_length = 0; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { max_length = params->Max_BVLC_Length_Accepted; } return max_length; } bool Network_Port_Max_BVLC_Length_Accepted_Set( uint32_t object_instance, BACNET_UNSIGNED_INTEGER value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } params->Max_BVLC_Length_Accepted = value; return true; } bool Network_Port_Max_BVLC_Length_Accepted_Dirty_Set( uint32_t object_instance, BACNET_UNSIGNED_INTEGER value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } params->Max_BVLC_Length_Accepted_dirty = value; return true; } BACNET_UNSIGNED_INTEGER Network_Port_Max_NPDU_Length_Accepted(uint32_t object_instance) { BACNET_UNSIGNED_INTEGER max_length = 0; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { max_length = params->Max_NPDU_Length_Accepted; } return max_length; } bool Network_Port_Max_NPDU_Length_Accepted_Set( uint32_t object_instance, BACNET_UNSIGNED_INTEGER value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } params->Max_NPDU_Length_Accepted = value; return true; } bool Network_Port_Max_NPDU_Length_Accepted_Dirty_Set( uint32_t object_instance, BACNET_UNSIGNED_INTEGER value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } params->Max_NPDU_Length_Accepted_dirty = value; return true; } bool Network_Port_SC_Primary_Hub_URI( uint32_t object_instance, BACNET_CHARACTER_STRING *str) { bool status = false; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { status = characterstring_init_ansi(str, params->SC_Primary_Hub_URI); } return status; } const char *Network_Port_SC_Primary_Hub_URI_char(uint32_t object_instance) { char *p = NULL; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params && params->SC_Primary_Hub_URI[0]) { p = params->SC_Primary_Hub_URI; } return p; } bool Network_Port_SC_Primary_Hub_URI_Set( uint32_t object_instance, const char *str) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } if (str) { snprintf( params->SC_Primary_Hub_URI, sizeof(params->SC_Primary_Hub_URI), "%s", str); } else { params->SC_Primary_Hub_URI[0] = 0; } return true; } bool Network_Port_SC_Primary_Hub_URI_Dirty_Set( uint32_t object_instance, const char *str) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } if (str) { snprintf( params->SC_Primary_Hub_URI_dirty, sizeof(params->SC_Primary_Hub_URI_dirty), "%s", str); } else { params->SC_Primary_Hub_URI_dirty[0] = 0; } Network_Port_Changes_Pending_Set(object_instance, true); return true; } bool Network_Port_SC_Failover_Hub_URI( uint32_t object_instance, BACNET_CHARACTER_STRING *str) { bool status = false; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { status = characterstring_init_ansi(str, params->SC_Failover_Hub_URI); } return status; } const char *Network_Port_SC_Failover_Hub_URI_char(uint32_t object_instance) { char *p = NULL; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params && params->SC_Failover_Hub_URI[0]) { p = params->SC_Failover_Hub_URI; } return p; } bool Network_Port_SC_Failover_Hub_URI_Set( uint32_t object_instance, const char *str) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } if (str) { snprintf( params->SC_Failover_Hub_URI, sizeof(params->SC_Failover_Hub_URI), "%s", str); } else { params->SC_Failover_Hub_URI[0] = 0; } return true; } bool Network_Port_SC_Failover_Hub_URI_Dirty_Set( uint32_t object_instance, const char *str) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } if (str) { snprintf( params->SC_Failover_Hub_URI_dirty, sizeof(params->SC_Failover_Hub_URI_dirty), "%s", str); } else { params->SC_Failover_Hub_URI_dirty[0] = 0; } Network_Port_Changes_Pending_Set(object_instance, true); return true; } BACNET_UNSIGNED_INTEGER Network_Port_SC_Minimum_Reconnect_Time(uint32_t object_instance) { BACNET_UNSIGNED_INTEGER timeout = 0; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { timeout = params->SC_Minimum_Reconnect_Time; } return timeout; } bool Network_Port_SC_Minimum_Reconnect_Time_Set( uint32_t object_instance, BACNET_UNSIGNED_INTEGER value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } if ((value < SC_MIN_RECONNECT_MIN) || (value > SC_MIN_RECONNECT_MAX)) { return false; } params->SC_Minimum_Reconnect_Time = value; return true; } bool Network_Port_SC_Minimum_Reconnect_Time_Dirty_Set( uint32_t object_instance, BACNET_UNSIGNED_INTEGER value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } if ((value < SC_MIN_RECONNECT_MIN) || (value > SC_MIN_RECONNECT_MAX)) { return false; } params->SC_Minimum_Reconnect_Time_dirty = value; return true; } BACNET_UNSIGNED_INTEGER Network_Port_SC_Maximum_Reconnect_Time(uint32_t object_instance) { BACNET_UNSIGNED_INTEGER timeout = 0; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { timeout = params->SC_Maximum_Reconnect_Time; } return timeout; } bool Network_Port_SC_Maximum_Reconnect_Time_Set( uint32_t object_instance, BACNET_UNSIGNED_INTEGER value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } if ((value < SC_MAX_RECONNECT_MIN) || (value > SC_MAX_RECONNECT_MAX)) { return false; } params->SC_Maximum_Reconnect_Time = value; return true; } bool Network_Port_SC_Maximum_Reconnect_Time_Dirty_Set( uint32_t object_instance, BACNET_UNSIGNED_INTEGER value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } if ((value < SC_MAX_RECONNECT_MIN) || (value > SC_MAX_RECONNECT_MAX)) { return false; } params->SC_Maximum_Reconnect_Time_dirty = value; return true; } BACNET_UNSIGNED_INTEGER Network_Port_SC_Connect_Wait_Timeout(uint32_t object_instance) { BACNET_UNSIGNED_INTEGER timeout = 0; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { timeout = params->SC_Connect_Wait_Timeout; } return timeout; } bool Network_Port_SC_Connect_Wait_Timeout_Set( uint32_t object_instance, BACNET_UNSIGNED_INTEGER value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } if ((value < SC_WAIT_CONNECT_MIN) || (value > SC_WAIT_CONNECT_MAX)) { return false; } params->SC_Connect_Wait_Timeout = value; return true; } bool Network_Port_SC_Connect_Wait_Timeout_Dirty_Set( uint32_t object_instance, BACNET_UNSIGNED_INTEGER value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } if ((value < SC_WAIT_CONNECT_MIN) || (value > SC_WAIT_CONNECT_MAX)) { return false; } params->SC_Connect_Wait_Timeout_dirty = value; return true; } BACNET_UNSIGNED_INTEGER Network_Port_SC_Disconnect_Wait_Timeout(uint32_t object_instance) { BACNET_UNSIGNED_INTEGER timeout = 0; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { timeout = params->SC_Disconnect_Wait_Timeout; } return timeout; } bool Network_Port_SC_Disconnect_Wait_Timeout_Set( uint32_t object_instance, BACNET_UNSIGNED_INTEGER value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } params->SC_Disconnect_Wait_Timeout = value; return true; } bool Network_Port_SC_Disconnect_Wait_Timeout_Dirty_Set( uint32_t object_instance, BACNET_UNSIGNED_INTEGER value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } params->SC_Disconnect_Wait_Timeout_dirty = value; return true; } BACNET_UNSIGNED_INTEGER Network_Port_SC_Heartbeat_Timeout(uint32_t object_instance) { BACNET_UNSIGNED_INTEGER timeout = 0; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { timeout = params->SC_Heartbeat_Timeout; } return timeout; } bool Network_Port_SC_Heartbeat_Timeout_Set( uint32_t object_instance, BACNET_UNSIGNED_INTEGER value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } params->SC_Heartbeat_Timeout = value; return true; } bool Network_Port_SC_Heartbeat_Timeout_Dirty_Set( uint32_t object_instance, BACNET_UNSIGNED_INTEGER value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } params->SC_Heartbeat_Timeout_dirty = value; return true; } BACNET_SC_HUB_CONNECTOR_STATE Network_Port_SC_Hub_Connector_State(uint32_t object_instance) { BACNET_SC_HUB_CONNECTOR_STATE state = BACNET_SC_HUB_CONNECTOR_STATE_NO_HUB_CONNECTION; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { state = params->SC_Hub_Connector_State; } return state; } bool Network_Port_SC_Hub_Connector_State_Set( uint32_t object_instance, BACNET_SC_HUB_CONNECTOR_STATE value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } params->SC_Hub_Connector_State = value; return true; } uint32_t Network_Port_Operational_Certificate_File(uint32_t object_instance) { uint32_t id = 0; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { id = params->Operational_Certificate_File; } return id; } bool Network_Port_Operational_Certificate_File_Set( uint32_t object_instance, uint32_t value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } params->Operational_Certificate_File = value; return true; } uint32_t Network_Port_Issuer_Certificate_File(uint32_t object_instance, uint8_t index) { uint32_t id = 0; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params && (index < BACNET_ISSUER_CERT_FILE_MAX)) { id = params->Issuer_Certificate_Files[index]; } return id; } bool Network_Port_Issuer_Certificate_File_Set( uint32_t object_instance, uint8_t index, uint32_t value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params || (index >= BACNET_ISSUER_CERT_FILE_MAX)) { return false; } params->Issuer_Certificate_Files[index] = value; return true; } /** * @brief Encode one BACnetARRAY property element; a function template * @param object_instance [in] BACnet network port object instance number * @param index [in] array index requested: * 0 to n for individual array members * @param apdu [out] Buffer in which the APDU contents are built, or NULL to * return the length of buffer if it had been built * @return The length of the apdu encoded or * BACNET_STATUS_ERROR for invalid array index */ int Network_Port_Issuer_Certificate_File_Encode( uint32_t object_instance, BACNET_ARRAY_INDEX index, uint8_t *apdu) { int apdu_len = 0; uint32_t file_instance = 0; if (index >= BACNET_ISSUER_CERT_FILE_MAX) { apdu_len = BACNET_STATUS_ERROR; } else { file_instance = Network_Port_Issuer_Certificate_File(object_instance, index); apdu_len = encode_application_unsigned(apdu, file_instance); } return apdu_len; } uint32_t Network_Port_Certificate_Signing_Request_File(uint32_t object_instance) { uint32_t id = 0; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { id = params->Certificate_Signing_Request_File; } return id; } bool Network_Port_Certificate_Signing_Request_File_Set( uint32_t object_instance, uint32_t value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } params->Certificate_Signing_Request_File = value; return true; } #ifdef BACNET_SECURE_CONNECT_ROUTING_TABLE #if 0 /* This function will needed if the Network_Port_Routing_Table_Find() or Network_Port_Routing_Table_Get() will return individual fields, not the entire struct. */ static bool MAC_Address_Get(uint8_t network_type, uint8_t *mac, BACNET_OCTET_STRING *mac_address) { bool status = false; uint8_t ip_mac[4 + 2] = { 0 }; size_t mac_len = 0; switch (network_type) { case PORT_TYPE_ETHERNET: mac_len = 6; break; case PORT_TYPE_MSTP: mac_len = 1; break; case PORT_TYPE_BIP: memcpy(&ip_mac[0], mac, 4); /* convert port from host-byte-order to network-byte-order */ encode_unsigned16(&ip_mac[4], *(uint16_t*)(mac + 4)); mac = &ip_mac[0]; mac_len = sizeof(ip_mac); break; case PORT_TYPE_BIP6: mac_len = 3; break; default: break; } if (mac) { status = octetstring_init(mac_address, mac, mac_len); } return status; } #endif static bool MAC_Address_Set( uint8_t network_type, uint8_t *mac_dest, uint8_t *mac_src, uint8_t mac_len) { bool status = false; size_t mac_size = 0; uint8_t ip_mac[4 + 2] = { 0 }; switch (network_type) { case PORT_TYPE_ETHERNET: mac_size = 6; break; case PORT_TYPE_MSTP: mac_size = 1; break; case PORT_TYPE_BIP: memcpy(&ip_mac[0], mac_src, 4); /* convert port from host-byte-order to network-byte-order */ decode_unsigned16(&mac_src[4], (uint16_t *)&ip_mac[4]); mac_src = &ip_mac[0]; mac_len = sizeof(ip_mac); break; case PORT_TYPE_BIP6: mac_size = 3; break; default: break; } if (mac_src && mac_dest && (mac_len == mac_size)) { memcpy(mac_dest, mac_src, mac_size); status = true; } return status; } BACNET_ROUTER_ENTRY *Network_Port_Routing_Table_Find( uint32_t object_instance, uint16_t network_number) { BACNET_ROUTER_ENTRY *entry = NULL; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return entry; } entry = Keylist_Data(params->Routing_Table, network_number); return entry; } BACNET_ROUTER_ENTRY * Network_Port_Routing_Table_Get(uint32_t object_instance, uint8_t index) { BACNET_ROUTER_ENTRY *entry = NULL; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return entry; } entry = Keylist_Data_Index(params->Routing_Table, index); return entry; } bool Network_Port_Routing_Table_Add( uint32_t object_instance, uint16_t network_number, uint8_t *mac, uint8_t mac_len, uint8_t status, uint8_t performance_index) { int index; uint8_t network_type; BACNET_ROUTER_ENTRY *entry; BACNET_SC_PARAMS *params; params = Network_Port_SC_Params(object_instance); if (!params) { return false; } network_type = Network_Port_Type(object_instance); entry = calloc(1, sizeof(BACNET_ROUTER_ENTRY)); if (!entry) { return false; } entry->Network_Number = network_number; MAC_Address_Set(network_type, entry->Mac_Address, mac, mac_len); entry->Status = status; entry->Performance_Index = performance_index; index = Keylist_Data_Add(params->Routing_Table, network_number, entry); if (index < 0) { free(entry); return false; } return true; } bool Network_Port_Routing_Table_Delete( uint32_t object_instance, uint16_t network_number) { BACNET_ROUTER_ENTRY *entry; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } entry = Keylist_Data_Delete(params->Routing_Table, network_number); free(entry); return true; } bool Network_Port_Routing_Table_Delete_All(uint32_t object_instance) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } Keylist_Delete(params->Routing_Table); params->Routing_Table = Keylist_Create(); return true; } uint8_t Network_Port_Routing_Table_Count(uint32_t object_instance) { uint8_t count = 0; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return 0; } count = Keylist_Count(params->Routing_Table); return count; } /** * @brief Handle a request to encode all the the routing table entries * @param apdu [out] Buffer in which the APDU contents are built. * @param max_apdu [in] Max length of the APDU buffer. * * @return How many bytes were encoded in the buffer, or * BACNET_STATUS_ABORT if the response would not fit within the buffer. */ int Network_Port_Routing_Table_Encode( uint32_t object_instance, uint8_t *apdu, int max_apdu) { BACNET_ROUTER_ENTRY *entry = NULL; int apdu_len = 0; unsigned index = 0; unsigned size = 0; size = Network_Port_Routing_Table_Count(object_instance); for (index = 0; index < size; index++) { entry = Network_Port_Routing_Table_Get(object_instance, index); apdu_len += bacapp_encode_RouterEntry(NULL, entry); } if (apdu_len > max_apdu) { return BACNET_STATUS_ABORT; } apdu_len = 0; for (index = 0; index < size; index++) { entry = Network_Port_Routing_Table_Get(object_instance, index); apdu_len += bacapp_encode_RouterEntry(&apdu[apdu_len], entry); } return apdu_len; } #endif /* BACNET_SECURE_CONNECT_ROUTING_TABLE */ #if BSC_CONF_HUB_FUNCTIONS_NUM != 0 BACNET_SC_HUB_CONNECTION_STATUS * Network_Port_SC_Primary_Hub_Connection_Status(uint32_t object_instance) { BACNET_SC_HUB_CONNECTION_STATUS *connection = NULL; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { connection = ¶ms->SC_Primary_Hub_Connection_Status; } return connection; } bool Network_Port_SC_Primary_Hub_Connection_Status_Set( uint32_t object_instance, BACNET_SC_CONNECTION_STATE state, BACNET_DATE_TIME *connect_ts, BACNET_DATE_TIME *disconnect_ts, BACNET_ERROR_CODE error, const char *error_details) { BACNET_SC_HUB_CONNECTION_STATUS *st; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } st = ¶ms->SC_Primary_Hub_Connection_Status; st->State = state; st->Connect_Timestamp = *connect_ts; st->Disconnect_Timestamp = *disconnect_ts; st->Error = error; if (error_details) { bsc_copy_str( st->Error_Details, error_details, sizeof(st->Error_Details)); } else { st->Error_Details[0] = 0; } return true; } BACNET_SC_HUB_CONNECTION_STATUS * Network_Port_SC_Failover_Hub_Connection_Status(uint32_t object_instance) { BACNET_SC_HUB_CONNECTION_STATUS *connection = NULL; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { connection = ¶ms->SC_Failover_Hub_Connection_Status; } return connection; } bool Network_Port_SC_Failover_Hub_Connection_Status_Set( uint32_t object_instance, BACNET_SC_CONNECTION_STATE state, BACNET_DATE_TIME *connect_ts, BACNET_DATE_TIME *disconnect_ts, BACNET_ERROR_CODE error, const char *error_details) { BACNET_SC_HUB_CONNECTION_STATUS *st; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } st = ¶ms->SC_Failover_Hub_Connection_Status; st->State = state; st->Connect_Timestamp = *connect_ts; st->Disconnect_Timestamp = *disconnect_ts; st->Error = error; if (error_details) { bsc_copy_str( st->Error_Details, error_details, sizeof(st->Error_Details)); } else { st->Error_Details[0] = 0; } return true; } bool Network_Port_SC_Hub_Function_Enable(uint32_t object_instance) { bool enable = false; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { enable = params->SC_Hub_Function_Enable; } return enable; } bool Network_Port_SC_Hub_Function_Enable_Set( uint32_t object_instance, bool value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } params->SC_Hub_Function_Enable = value; return true; } bool Network_Port_SC_Hub_Function_Enable_Dirty_Set( uint32_t object_instance, bool value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } params->SC_Hub_Function_Enable_dirty = value; Network_Port_Changes_Pending_Set(object_instance, true); return true; } bool Network_Port_SC_Hub_Function_Accept_URI( uint32_t object_instance, uint8_t index, BACNET_CHARACTER_STRING *str) { bool status = false; int idx[BACNET_SC_DIRECT_ACCEPT_URI_MAX + 1] = { 0 }; int len; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params && (index < BACNET_SC_DIRECT_ACCEPT_URI_MAX)) { len = string_splite( params->SC_Hub_Function_Accept_URIs, ' ', idx, sizeof(idx)); if (index < len) { status = characterstring_init_ansi_safe( str, params->SC_Hub_Function_Accept_URIs + idx[index], idx[index + 1] - idx[index] - 1); } else { status = characterstring_init_ansi(str, ""); } } return status; } bool Network_Port_SC_Hub_Function_Accept_URI_Set( uint32_t object_instance, uint8_t index, const char *str) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params || (index >= BACNET_SC_DIRECT_ACCEPT_URI_MAX)) { return false; } string_subsstr( params->SC_Hub_Function_Accept_URIs, sizeof(params->SC_Hub_Function_Accept_URIs), index, str); return true; } /** * @brief Encode a BACnetARRAY property element; a function template * @param object_instance [in] BACnet network port object instance number * @param index [in] array index requested: * 0 to n for individual array members * @param apdu [out] Buffer in which the APDU contents are built, or NULL to * return the length of buffer if it had been built * @return The length of the apdu encoded or * BACNET_STATUS_ERROR for invalid array index */ int Network_Port_SC_Hub_Function_Accept_URI_Encode( uint32_t object_instance, BACNET_ARRAY_INDEX index, uint8_t *apdu) { int apdu_len = 0; BACNET_CHARACTER_STRING uri = { 0 }; if (index >= BACNET_SC_DIRECT_ACCEPT_URI_MAX) { apdu_len = BACNET_STATUS_ERROR; } else { if (Network_Port_SC_Hub_Function_Accept_URI( object_instance, index, &uri)) { apdu_len = encode_application_character_string(apdu, &uri); } } return apdu_len; } bool Network_Port_SC_Hub_Function_Accept_URI_Dirty_Set( uint32_t object_instance, uint8_t index, const char *str) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params || (index >= BACNET_SC_DIRECT_ACCEPT_URI_MAX)) { return false; } string_subsstr( params->SC_Hub_Function_Accept_URIs_dirty, sizeof(params->SC_Hub_Function_Accept_URIs_dirty), index, str); return true; } const char * Network_Port_SC_Hub_Function_Accept_URIs_char(uint32_t object_instance) { char *p = NULL; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { p = params->SC_Hub_Function_Accept_URIs; } return p; } bool Network_Port_SC_Hub_Function_Accept_URIs_Set( uint32_t object_instance, const char *str) { bool status = false; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { if (str) { snprintf( params->SC_Hub_Function_Accept_URIs, sizeof(params->SC_Hub_Function_Accept_URIs), "%s", str); } else { params->SC_Hub_Function_Accept_URIs[0] = 0; } } return status; } bool Network_Port_SC_Hub_Function_Binding( uint32_t object_instance, BACNET_CHARACTER_STRING *str) { bool status = false; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); char tmp[sizeof(params->SC_Hub_Function_Binding)]; if (params) { snprintf( tmp, sizeof(tmp), "%s:%d", params->SC_Hub_Function_Binding + sizeof(uint16_t), *(uint16_t *)params->SC_Hub_Function_Binding); status = characterstring_init_ansi(str, tmp); } return status; } void Network_Port_SC_Hub_Function_Binding_get( uint32_t object_instance, uint16_t *port, char **ifname) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); *port = 0; *ifname = NULL; if (params && params->SC_Hub_Function_Binding[0]) { *port = *(uint16_t *)params->SC_Hub_Function_Binding; *ifname = params->SC_Hub_Function_Binding + sizeof(uint16_t); if (**ifname == 0) { *ifname = NULL; } } } bool Network_Port_SC_Hub_Function_Binding_Set( uint32_t object_instance, const char *str) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); uint16_t port; char *ifname; char tmp[BACNET_BINDING_STRING_LENGTH]; if (!params) { return false; } if (str && str[0]) { bsc_copy_str(tmp, str, sizeof(tmp)); sc_binding_parse(tmp, &port, &ifname); *(uint16_t *)params->SC_Hub_Function_Binding = port; if (ifname) { bsc_copy_str( params->SC_Hub_Function_Binding + sizeof(uint16_t), ifname, sizeof(params->SC_Hub_Function_Binding) - sizeof(uint16_t)); } else { *(params->SC_Hub_Function_Binding + sizeof(uint16_t)) = 0; } } else { memset( params->SC_Hub_Function_Binding, 0, sizeof(params->SC_Hub_Function_Binding)); } return true; } bool Network_Port_SC_Hub_Function_Binding_Dirty_Set( uint32_t object_instance, const char *str) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } if (str) { snprintf( params->SC_Hub_Function_Binding_dirty, sizeof(params->SC_Hub_Function_Binding_dirty), "%s", str); } else { params->SC_Hub_Function_Binding_dirty[0] = 0; } Network_Port_Changes_Pending_Set(object_instance, true); return true; } BACNET_SC_HUB_FUNCTION_CONNECTION_STATUS * Network_Port_SC_Hub_Function_Connection_Status_Get( uint32_t object_instance, uint8_t index) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return NULL; } if (index >= params->SC_Hub_Function_Connection_Status_Count) { return NULL; } return ¶ms->SC_Hub_Function_Connection_Status[index]; } bool Network_Port_SC_Hub_Function_Connection_Status_Add( uint32_t object_instance, BACNET_SC_CONNECTION_STATE state, BACNET_DATE_TIME *connect_ts, BACNET_DATE_TIME *disconnect_ts, BACNET_HOST_N_PORT_DATA *peer_address, uint8_t *peer_VMAC, uint8_t *peer_UUID, BACNET_ERROR_CODE error, const char *error_details) { BACNET_SC_HUB_FUNCTION_CONNECTION_STATUS *st; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } if (params->SC_Hub_Function_Connection_Status_Count + 1 > ARRAY_SIZE(params->SC_Hub_Function_Connection_Status)) { return false; } st = ¶ms->SC_Hub_Function_Connection_Status [params->SC_Hub_Function_Connection_Status_Count]; params->SC_Hub_Function_Connection_Status_Count += 1; st->State = state; st->Connect_Timestamp = *connect_ts; st->Disconnect_Timestamp = *disconnect_ts; st->Peer_Address = *peer_address; memcpy(st->Peer_VMAC, peer_VMAC, sizeof(st->Peer_VMAC)); memcpy( st->Peer_UUID.uuid.uuid128, peer_UUID, sizeof(st->Peer_UUID.uuid.uuid128)); st->Error = error; if (error_details) { bsc_copy_str( st->Error_Details, error_details, sizeof(st->Error_Details)); } else { st->Error_Details[0] = 0; } return true; } bool Network_Port_SC_Hub_Function_Connection_Status_Delete_All( uint32_t object_instance) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } params->SC_Hub_Function_Connection_Status_Count = 0; return true; } int Network_Port_SC_Hub_Function_Connection_Status_Count( uint32_t object_instance) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return 0; } return params->SC_Hub_Function_Connection_Status_Count; } /** * @brief Handle a request to encode all the the entries * @param object_instance [in] BACnet network port object instance number * @param apdu [out] Buffer in which the APDU contents are built. * @param max_apdu [in] Max length of the APDU buffer. * * @return How many bytes were encoded in the buffer, or * BACNET_STATUS_ABORT if the response would not fit within the buffer. */ int Network_Port_SC_Hub_Function_Connection_Status_Encode( uint32_t object_instance, uint8_t *apdu, int max_apdu) { BACNET_SC_HUB_FUNCTION_CONNECTION_STATUS *entry = NULL; int apdu_len = 0; unsigned index = 0; unsigned size = 0; size = Network_Port_SC_Hub_Function_Connection_Status_Count(object_instance); for (index = 0; index < size; index++) { entry = Network_Port_SC_Hub_Function_Connection_Status_Get( object_instance, index); apdu_len += bacapp_encode_SCHubFunctionConnection(NULL, entry); } if (apdu_len > max_apdu) { return BACNET_STATUS_ABORT; } apdu_len = 0; for (index = 0; index < size; index++) { entry = Network_Port_SC_Hub_Function_Connection_Status_Get( object_instance, index); apdu_len += bacapp_encode_SCHubFunctionConnection(&apdu[apdu_len], entry); } return apdu_len; } #endif /* BSC_CONF_HUB_FUNCTIONS_NUM!=0 */ #if BSC_CONF_HUB_CONNECTORS_NUM != 0 bool Network_Port_SC_Direct_Connect_Initiate_Enable(uint32_t object_instance) { bool enable = false; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { enable = params->SC_Direct_Connect_Initiate_Enable; } return enable; } bool Network_Port_SC_Direct_Connect_Initiate_Enable_Set( uint32_t object_instance, bool value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } params->SC_Direct_Connect_Initiate_Enable = value; return true; } bool Network_Port_SC_Direct_Connect_Initiate_Enable_Dirty_Set( uint32_t object_instance, bool value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } params->SC_Direct_Connect_Initiate_Enable_dirty = value; Network_Port_Changes_Pending_Set(object_instance, true); return true; } bool Network_Port_SC_Direct_Connect_Accept_Enable(uint32_t object_instance) { bool enable = false; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { enable = params->SC_Direct_Connect_Accept_Enable; } return enable; } bool Network_Port_SC_Direct_Connect_Accept_Enable_Set( uint32_t object_instance, bool value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } params->SC_Direct_Connect_Accept_Enable = value; return true; } bool Network_Port_SC_Direct_Connect_Accept_Enable_Dirty_Set( uint32_t object_instance, bool value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } params->SC_Direct_Connect_Accept_Enable_dirty = value; Network_Port_Changes_Pending_Set(object_instance, true); return true; } /* return number of urls, */ /* indexes are fill first position of urls plus position of end string */ static int string_splite(const char *str, char separator, int *indexes, int length) { int i; int k = 0; indexes[0] = 0; for (i = 0; str[i] != 0 && k < length; i++) { if (str[i] == separator) { k++; indexes[k] = i + 1; } } if (k < length) { k++; indexes[k] = i + 1; } return k; } static bool string_subsstr(char *str, int length, int index, const char *substr) { int idx[BACNET_SC_DIRECT_ACCEPT_URI_MAX + 1] = { 0 }; int len; char *head; char *tail_old; char *tail_new; len = string_splite(str, ' ', idx, sizeof(idx)); if (index < len) { head = str + idx[index]; tail_old = str + idx[index + 1] - 1; tail_new = head + strlen(substr); if (tail_new + strlen(tail_old) + 1 - str >= length) { return false; } memmove(tail_new, tail_old, strlen(tail_old) + 1); memcpy(head, substr, strlen(substr)); } else { head = str + strlen(str); if (head != str) { *head = ' '; head++; } if (head + strlen(substr) + 1 - str >= length) { return false; } memcpy(head, substr, strlen(substr) + 1); } return true; } bool Network_Port_SC_Direct_Connect_Accept_URI( uint32_t object_instance, uint8_t index, BACNET_CHARACTER_STRING *str) { bool status = false; int idx[BACNET_SC_DIRECT_ACCEPT_URI_MAX + 1] = { 0 }; int len; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params && (index < BACNET_SC_DIRECT_ACCEPT_URI_MAX)) { len = string_splite( params->SC_Direct_Connect_Accept_URIs, ' ', idx, sizeof(idx)); if (index < len) { status = characterstring_init_ansi_safe( str, params->SC_Direct_Connect_Accept_URIs + idx[index], idx[index + 1] - idx[index] - 1); } else { status = characterstring_init_ansi(str, ""); } } return status; } bool Network_Port_SC_Direct_Connect_Accept_URI_Set( uint32_t object_instance, uint8_t index, const char *str) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params || (index >= BACNET_SC_DIRECT_ACCEPT_URI_MAX)) { return false; } string_subsstr( params->SC_Direct_Connect_Accept_URIs, sizeof(params->SC_Direct_Connect_Accept_URIs), index, str); return true; } /** * @brief Encode a BACnetARRAY property element; a function template * @param object_instance [in] BACnet network port object instance number * @param index [in] array index requested: * 0 to n for individual array members * @param apdu [out] Buffer in which the APDU contents are built, or NULL to * return the length of buffer if it had been built * @return The length of the apdu encoded or * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX */ int Network_Port_SC_Direct_Connect_Accept_URI_Encode( uint32_t object_instance, BACNET_ARRAY_INDEX index, uint8_t *apdu) { int apdu_len = 0; BACNET_CHARACTER_STRING uri = { 0 }; if (index >= BACNET_SC_DIRECT_ACCEPT_URI_MAX) { apdu_len = BACNET_STATUS_ERROR; } else { if (Network_Port_SC_Direct_Connect_Accept_URI( object_instance, index, &uri)) { apdu_len = encode_application_character_string(apdu, &uri); } } return apdu_len; } bool Network_Port_SC_Direct_Connect_Accept_URI_Dirty_Set( uint32_t object_instance, uint8_t index, const char *str) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params || (index >= BACNET_SC_DIRECT_ACCEPT_URI_MAX)) { return false; } string_subsstr( params->SC_Direct_Connect_Accept_URIs_dirty, sizeof(params->SC_Direct_Connect_Accept_URIs_dirty), index, str); return true; } char *Network_Port_SC_Direct_Connect_Accept_URIs_char(uint32_t object_instance) { char *p = NULL; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { p = params->SC_Direct_Connect_Accept_URIs; } return p; } bool Network_Port_SC_Direct_Connect_Accept_URIs_Set( uint32_t object_instance, const char *str) { bool status = false; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { if (str) { snprintf( params->SC_Direct_Connect_Accept_URIs, sizeof(params->SC_Direct_Connect_Accept_URIs), "%s", str); } else { params->SC_Direct_Connect_Accept_URIs[0] = 0; } } return status; } bool Network_Port_SC_Direct_Connect_Accept_URIs_Dirty_Set( uint32_t object_instance, const char *str) { bool status = false; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (params) { if (str) { snprintf( params->SC_Direct_Connect_Accept_URIs_dirty, sizeof(params->SC_Direct_Connect_Accept_URIs_dirty), "%s", str); } else { params->SC_Direct_Connect_Accept_URIs_dirty[0] = 0; } } return status; } bool Network_Port_SC_Direct_Connect_Binding( uint32_t object_instance, BACNET_CHARACTER_STRING *str) { bool status = false; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); char tmp[sizeof(params->SC_Direct_Connect_Binding)]; if (params) { snprintf( tmp, sizeof(tmp), "%s:%d", params->SC_Direct_Connect_Binding + sizeof(uint16_t), *(uint16_t *)params->SC_Direct_Connect_Binding); status = characterstring_init_ansi(str, tmp); } return status; } void Network_Port_SC_Direct_Connect_Binding_get( uint32_t object_instance, uint16_t *port, char **ifname) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); *port = 0; *ifname = NULL; if (params && params->SC_Direct_Connect_Binding[0]) { *port = *(uint16_t *)params->SC_Direct_Connect_Binding; *ifname = params->SC_Direct_Connect_Binding + sizeof(uint16_t); if (**ifname == 0) { *ifname = NULL; } } } bool Network_Port_SC_Direct_Connect_Binding_Set( uint32_t object_instance, const char *str) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); uint16_t port; char *ifname; char tmp[BACNET_BINDING_STRING_LENGTH]; if (!params) { return false; } if (str && str[0]) { bsc_copy_str(tmp, str, sizeof(tmp)); sc_binding_parse(tmp, &port, &ifname); *(uint16_t *)params->SC_Direct_Connect_Binding = port; if (ifname) { bsc_copy_str( params->SC_Direct_Connect_Binding + sizeof(uint16_t), ifname, sizeof(params->SC_Direct_Connect_Binding) - sizeof(uint16_t)); } else { *(params->SC_Direct_Connect_Binding + sizeof(uint16_t)) = 0; } } else { memset( params->SC_Direct_Connect_Binding, 0, sizeof(params->SC_Direct_Connect_Binding)); } return true; } bool Network_Port_SC_Direct_Connect_Binding_Dirty_Set( uint32_t object_instance, const char *str) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } if (str) { snprintf( params->SC_Direct_Connect_Binding_dirty, sizeof(params->SC_Direct_Connect_Binding_dirty), "%s", str); } else { params->SC_Direct_Connect_Binding_dirty[0] = 0; } Network_Port_Changes_Pending_Set(object_instance, true); return true; } BACNET_SC_DIRECT_CONNECTION_STATUS * Network_Port_SC_Direct_Connect_Connection_Status_Get( uint32_t object_instance, uint8_t index) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return NULL; } if (index >= params->SC_Direct_Connect_Connection_Status_Count) { return NULL; } return ¶ms->SC_Direct_Connect_Connection_Status[index]; } bool Network_Port_SC_Direct_Connect_Connection_Status_Add( uint32_t object_instance, const char *uri, BACNET_SC_CONNECTION_STATE state, BACNET_DATE_TIME *connect_ts, BACNET_DATE_TIME *disconnect_ts, BACNET_HOST_N_PORT_DATA *peer_address, uint8_t *peer_VMAC, uint8_t *peer_UUID, BACNET_ERROR_CODE error, const char *error_details) { BACNET_SC_DIRECT_CONNECTION_STATUS *st; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } if (params->SC_Direct_Connect_Connection_Status_Count + 1 > ARRAY_SIZE(params->SC_Direct_Connect_Connection_Status)) { return false; } st = ¶ms->SC_Direct_Connect_Connection_Status [params->SC_Direct_Connect_Connection_Status_Count]; params->SC_Direct_Connect_Connection_Status_Count += 1; if (uri) { bsc_copy_str(st->URI, uri, sizeof(st->URI)); } else { st->URI[0] = 0; } st->State = state; st->Connect_Timestamp = *connect_ts; st->Disconnect_Timestamp = *disconnect_ts; memcpy(&st->Peer_Address, peer_address, sizeof(st->Peer_Address)); memcpy(st->Peer_VMAC, peer_VMAC, sizeof(st->Peer_VMAC)); memcpy( st->Peer_UUID.uuid.uuid128, peer_UUID, sizeof(st->Peer_UUID.uuid.uuid128)); st->Error = error; if (error_details) { bsc_copy_str( st->Error_Details, error_details, sizeof(st->Error_Details)); } else { st->Error_Details[0] = 0; } return true; } bool Network_Port_SC_Direct_Connect_Connection_Status_Delete_All( uint32_t object_instance) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } params->SC_Direct_Connect_Connection_Status_Count = 0; return true; } int Network_Port_SC_Direct_Connect_Connection_Status_Count( uint32_t object_instance) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return 0; } return params->SC_Direct_Connect_Connection_Status_Count; } /** * @brief Handle a request to encode all the the entries * @param object_instance [in] BACnet network port object instance number * @param apdu [out] Buffer in which the APDU contents are built. * @param max_apdu [in] Max length of the APDU buffer. * * @return How many bytes were encoded in the buffer, or * BACNET_STATUS_ABORT if the response would not fit within the buffer. */ int Network_Port_SC_Direct_Connect_Connection_Status_Encode( uint32_t object_instance, uint8_t *apdu, int max_apdu) { BACNET_SC_DIRECT_CONNECTION_STATUS *entry = NULL; int apdu_len = 0; unsigned index = 0; unsigned size = 0; size = Network_Port_SC_Direct_Connect_Connection_Status_Count(object_instance); for (index = 0; index < size; index++) { entry = Network_Port_SC_Direct_Connect_Connection_Status_Get( object_instance, index); apdu_len += bacapp_encode_SCDirectConnection(NULL, entry); } if (apdu_len > max_apdu) { return BACNET_STATUS_ABORT; } apdu_len = 0; for (index = 0; index < size; index++) { entry = Network_Port_SC_Direct_Connect_Connection_Status_Get( object_instance, index); apdu_len += bacapp_encode_SCDirectConnection(&apdu[apdu_len], entry); } return apdu_len; } #endif /* BSC_CONF_HUB_CONNECTORS_NUM!=0 */ BACNET_SC_FAILED_CONNECTION_REQUEST * Network_Port_SC_Failed_Connection_Requests_Get( uint32_t object_instance, uint8_t index) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return NULL; } if (index >= params->SC_Failed_Connection_Requests_Count) { return NULL; } return ¶ms->SC_Failed_Connection_Requests[index]; } bool Network_Port_SC_Failed_Connection_Requests_Add( uint32_t object_instance, BACNET_DATE_TIME *ts, BACNET_HOST_N_PORT_DATA *peer_address, uint8_t *peer_VMAC, uint8_t *peer_UUID, BACNET_ERROR_CODE error, const char *error_details) { BACNET_SC_FAILED_CONNECTION_REQUEST *entry; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } if (params->SC_Failed_Connection_Requests_Count + 1 > ARRAY_SIZE(params->SC_Failed_Connection_Requests)) { return false; } entry = ¶ms->SC_Failed_Connection_Requests [params->SC_Failed_Connection_Requests_Count]; params->SC_Failed_Connection_Requests_Count += 1; entry->Timestamp = *ts; memcpy(&entry->Peer_Address, peer_address, sizeof(entry->Peer_Address)); memcpy(entry->Peer_VMAC, peer_VMAC, sizeof(entry->Peer_VMAC)); memcpy( entry->Peer_UUID.uuid.uuid128, peer_UUID, sizeof(entry->Peer_UUID.uuid.uuid128)); entry->Error = error; if (error_details) { bsc_copy_str( entry->Error_Details, error_details, sizeof(entry->Error_Details)); } else { entry->Error_Details[0] = 0; } return true; } bool Network_Port_SC_Failed_Connection_Requests_Delete_All( uint32_t object_instance) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } params->SC_Failed_Connection_Requests_Count = 0; return true; } int Network_Port_SC_Failed_Connection_Requests_Count(uint32_t object_instance) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return 0; } return params->SC_Failed_Connection_Requests_Count; } /** * @brief Handle a request to encode all the the entries * @param object_instance [in] BACnet network port object instance number * @param apdu [out] Buffer in which the APDU contents are built. * @param max_apdu [in] Max length of the APDU buffer. * @return How many bytes were encoded in the buffer, or * BACNET_STATUS_ABORT if the response would not fit within the buffer. */ int Network_Port_SC_Failed_Connection_Requests_Encode( uint32_t object_instance, uint8_t *apdu, int max_apdu) { BACNET_SC_FAILED_CONNECTION_REQUEST *entry = NULL; int apdu_len = 0; unsigned index = 0; unsigned size = 0; size = Network_Port_SC_Failed_Connection_Requests_Count(object_instance); for (index = 0; index < size; index++) { entry = Network_Port_SC_Failed_Connection_Requests_Get( object_instance, index); apdu_len += bacapp_encode_SCFailedConnectionRequest(NULL, entry); } if (apdu_len > max_apdu) { return BACNET_STATUS_ABORT; } apdu_len = 0; for (index = 0; index < size; index++) { entry = Network_Port_SC_Failed_Connection_Requests_Get( object_instance, index); apdu_len += bacapp_encode_SCFailedConnectionRequest(&apdu[apdu_len], entry); } return apdu_len; } uint32_t Network_Port_Certificate_Key_File(uint32_t object_instance) { uint32_t id = 0; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return 0; } id = params->Certificate_Key_File; return id; } bool Network_Port_Certificate_Key_File_Set( uint32_t object_instance, uint32_t value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } params->Certificate_Key_File = value; return true; } const BACNET_UUID *Network_Port_SC_Local_UUID(uint32_t object_instance) { const BACNET_UUID *uuid = NULL; BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return NULL; } uuid = ¶ms->Local_UUID; return uuid; } bool Network_Port_SC_Local_UUID_Set( uint32_t object_instance, BACNET_UUID *value) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return false; } memcpy(¶ms->Local_UUID, value, sizeof(*value)); return true; } void Network_Port_SC_Pending_Params_Apply(uint32_t object_instance) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); if (!params) { return; } params->Max_BVLC_Length_Accepted = params->Max_BVLC_Length_Accepted_dirty; params->Max_NPDU_Length_Accepted = params->Max_NPDU_Length_Accepted_dirty; params->SC_Minimum_Reconnect_Time = params->SC_Minimum_Reconnect_Time_dirty; params->SC_Maximum_Reconnect_Time = params->SC_Maximum_Reconnect_Time_dirty; params->SC_Connect_Wait_Timeout = params->SC_Connect_Wait_Timeout_dirty; params->SC_Disconnect_Wait_Timeout = params->SC_Disconnect_Wait_Timeout_dirty; params->SC_Heartbeat_Timeout = params->SC_Heartbeat_Timeout_dirty; #if BSC_CONF_HUB_FUNCTIONS_NUM != 0 memcpy( params->SC_Primary_Hub_URI, params->SC_Primary_Hub_URI_dirty, sizeof(params->SC_Primary_Hub_URI)); memcpy( params->SC_Failover_Hub_URI, params->SC_Failover_Hub_URI_dirty, sizeof(params->SC_Failover_Hub_URI)); params->SC_Hub_Function_Enable = params->SC_Hub_Function_Enable_dirty; memcpy( params->SC_Hub_Function_Accept_URIs, params->SC_Hub_Function_Accept_URIs_dirty, sizeof(params->SC_Hub_Function_Accept_URIs)); Network_Port_SC_Hub_Function_Binding_Set( object_instance, params->SC_Hub_Function_Binding_dirty); #endif /* BSC_CONF_HUB_FUNCTIONS_NUM!=0 */ #if BSC_CONF_HUB_CONNECTORS_NUM != 0 params->SC_Direct_Connect_Initiate_Enable = params->SC_Direct_Connect_Initiate_Enable_dirty; params->SC_Direct_Connect_Accept_Enable = params->SC_Direct_Connect_Accept_Enable_dirty; memcpy( params->SC_Direct_Connect_Accept_URIs, params->SC_Direct_Connect_Accept_URIs_dirty, sizeof(params->SC_Direct_Connect_Accept_URIs)); Network_Port_SC_Direct_Connect_Binding_Set( object_instance, params->SC_Direct_Connect_Binding_dirty); #endif /* BSC_CONF_HUB_CONNECTORS_NUM!=0 */ } void Network_Port_SC_Pending_Params_Discard(uint32_t object_instance) { BACNET_SC_PARAMS *params = Network_Port_SC_Params(object_instance); uint16_t port = 0; char *ifname = NULL; if (!params) { return; } params->Max_BVLC_Length_Accepted_dirty = params->Max_BVLC_Length_Accepted; params->Max_NPDU_Length_Accepted_dirty = params->Max_NPDU_Length_Accepted; params->SC_Minimum_Reconnect_Time_dirty = params->SC_Minimum_Reconnect_Time; params->SC_Maximum_Reconnect_Time_dirty = params->SC_Maximum_Reconnect_Time; params->SC_Connect_Wait_Timeout_dirty = params->SC_Connect_Wait_Timeout; params->SC_Disconnect_Wait_Timeout_dirty = params->SC_Disconnect_Wait_Timeout; params->SC_Heartbeat_Timeout_dirty = params->SC_Heartbeat_Timeout; #if BSC_CONF_HUB_FUNCTIONS_NUM != 0 memcpy( params->SC_Primary_Hub_URI_dirty, params->SC_Primary_Hub_URI, sizeof(params->SC_Primary_Hub_URI_dirty)); memcpy( params->SC_Failover_Hub_URI_dirty, params->SC_Failover_Hub_URI, sizeof(params->SC_Failover_Hub_URI_dirty)); params->SC_Hub_Function_Enable_dirty = params->SC_Hub_Function_Enable; memcpy( params->SC_Hub_Function_Accept_URIs_dirty, params->SC_Hub_Function_Accept_URIs, sizeof(params->SC_Hub_Function_Accept_URIs)); Network_Port_SC_Hub_Function_Binding_get(object_instance, &port, &ifname); snprintf( params->SC_Hub_Function_Binding_dirty, sizeof(params->SC_Hub_Function_Binding_dirty), "%s:%d", ifname, port); #else (void)port; (void)ifname; #endif /* BSC_CONF_HUB_FUNCTIONS_NUM!=0 */ #if BSC_CONF_HUB_CONNECTORS_NUM != 0 params->SC_Direct_Connect_Initiate_Enable_dirty = params->SC_Direct_Connect_Initiate_Enable; params->SC_Direct_Connect_Accept_Enable_dirty = params->SC_Direct_Connect_Accept_Enable; memcpy( params->SC_Direct_Connect_Accept_URIs_dirty, params->SC_Direct_Connect_Accept_URIs, sizeof(params->SC_Direct_Connect_Accept_URIs)); Network_Port_SC_Direct_Connect_Binding_get(object_instance, &port, &ifname); snprintf( params->SC_Direct_Connect_Binding_dirty, sizeof(params->SC_Direct_Connect_Binding_dirty), "%s:%d", ifname, port); #endif /* BSC_CONF_HUB_CONNECTORS_NUM!=0 */ }