diff --git a/bacnet-stack/demo/gateway/main.c b/bacnet-stack/demo/gateway/main.c index e5f9c8cd..63805340 100644 --- a/bacnet-stack/demo/gateway/main.c +++ b/bacnet-stack/demo/gateway/main.c @@ -61,7 +61,6 @@ /** @file gateway/main.c Example virtual gateway application using the BACnet Stack. */ /* Prototypes */ -extern void routing_npdu_handler( BACNET_ADDRESS * src, uint8_t * pdu, uint16_t pdu_len); /* (Doxygen note: The next two lines pull all the following Javadoc * into the GatewayDemo module.) */ @@ -203,7 +202,7 @@ int main( /* process */ if (pdu_len) { - routing_npdu_handler(&src, &Rx_Buf[0], pdu_len); + routing_npdu_handler(&src, DNET_list, &Rx_Buf[0], pdu_len); } /* at least one second has passed */ elapsed_seconds = current_seconds - last_seconds; diff --git a/bacnet-stack/demo/handler/h_routed_npdu.c b/bacnet-stack/demo/handler/h_routed_npdu.c index d9920e80..710ec256 100644 --- a/bacnet-stack/demo/handler/h_routed_npdu.c +++ b/bacnet-stack/demo/handler/h_routed_npdu.c @@ -45,7 +45,6 @@ /** @file h_routed_npdu.c Handles messages at the NPDU level of the BACnet stack, * including routing and network control messages. */ -extern int DNET_list[]; /** Handler to manage the Network Layer Control Messages received in a packet. * This handler is called if the NCPI bit 7 indicates that this packet is a @@ -54,12 +53,15 @@ extern int DNET_list[]; * * @param npdu_data [in] Contains a filled-out structure with information * decoded from the NCPI and other NPDU bytes. + * @param DNET_list [in] List of our reachable downstream BACnet Network numbers. + * Normally just one valid entry; terminated with a -1 value. * @param npdu [in] Buffer containing the rest of the NPDU, following the * bytes that have already been decoded. * @param npdu_len [in] The length of the remaining NPDU message in npdu[]. */ static void network_control_handler( BACNET_NPDU_DATA * npdu_data, + int * DNET_list, uint8_t * npdu, uint16_t npdu_len) { @@ -130,9 +132,18 @@ static void network_control_handler( * NETWORK_MESSAGE_INIT_RT_TABLE_ACK and a list of all our * reachable networks. */ - if ( (npdu_len > 0) && (npdu[0] == 0) ) { - BACNET_ROUTER_PORT * router_port_list = NULL; - Send_Initialize_Routing_Table_Ack(router_port_list); + if ( npdu_len > 0) { + /* If Number of Ports is 0, send our "full" table */ + if (npdu[0] == 0) + Send_Initialize_Routing_Table_Ack( DNET_list ); + else { + /* If they sent us a list, just politely ACK it + * with no routing list of our own. But we don't DO + * anything with the info, either. + */ + int listTerminator = -1; + Send_Initialize_Routing_Table_Ack( &listTerminator ); + } break; } /* Else, fall through to do nothing. */ @@ -155,6 +166,7 @@ static void network_control_handler( static void routed_apdu_handler( BACNET_ADDRESS * src, BACNET_ADDRESS * dest, + int * DNET_list, uint8_t * apdu, uint16_t apdu_len) { @@ -186,11 +198,14 @@ static void routed_apdu_handler( * think this project's code has any use for the src info * on return from this handler, since the response has * already been sent via the apdu_handler. + * @param DNET_list [in] List of our reachable downstream BACnet Network numbers. + * Normally just one valid entry; terminated with a -1 value. * @param pdu [in] Buffer containing the NPDU and APDU of the received packet. * @param pdu_len [in] The size of the received message in the pdu[] buffer. */ void routing_npdu_handler( BACNET_ADDRESS * src, + int * DNET_list, uint8_t * pdu, uint16_t pdu_len) { @@ -207,7 +222,7 @@ void routing_npdu_handler( #endif } else if (npdu_data.network_layer_message) { if ((dest.net == 0) || (dest.net == BACNET_BROADCAST_NETWORK)) { - network_control_handler( &npdu_data, &pdu[apdu_offset], + network_control_handler( &npdu_data, DNET_list, &pdu[apdu_offset], (uint16_t) (pdu_len - apdu_offset)); } else { /* The DNET is set, but we don't support downstream routers, @@ -221,7 +236,7 @@ void routing_npdu_handler( (uint16_t) (pdu_len - apdu_offset)); } else { /* Handle the routed variety differently */ - routed_apdu_handler(src, &dest, &pdu[apdu_offset], + routed_apdu_handler(src, &dest, DNET_list, &pdu[apdu_offset], (uint16_t) (pdu_len - apdu_offset)); } } diff --git a/bacnet-stack/demo/handler/s_router.c b/bacnet-stack/demo/handler/s_router.c index 4201d1b3..4407bbe7 100644 --- a/bacnet-stack/demo/handler/s_router.c +++ b/bacnet-stack/demo/handler/s_router.c @@ -36,6 +36,7 @@ #include "apdu.h" #include "device.h" #include "datalink.h" +#include "bactext.h" /* some demo stuff needed */ #include "handlers.h" #include "txbuf.h" @@ -73,45 +74,123 @@ static void npdu_encode_npdu_network( } } -/* find a specific router, or use -1 for limit if you want unlimited */ -void Send_Who_Is_Router_To_Network( - BACNET_ADDRESS * dst, - int dnet) + +/** Function to encode and send any supported Network Layer Message. + * The payload for the message is encoded from information in the iArgs[] array. + * The contents of iArgs are are, per message type: + * - NETWORK_MESSAGE_WHO_IS_ROUTER_TO_NETWORK: Single int for DNET requested + * - NETWORK_MESSAGE_I_AM_ROUTER_TO_NETWORK: Array of DNET(s) to send, + * terminated with -1 + * + * @param network_message_type [in] The type of message to be sent. + * @param dst [in/out] If not NULL, contains the destination for the message. + * @param iArgs [in] An optional array of values whose meaning depends on + * the type of message. + * @return Number of bytes sent, or <=0 if no message was sent. + */ +int Send_Network_Layer_Message( + BACNET_NETWORK_MESSAGE_TYPE network_message_type, + BACNET_ADDRESS * dst, + int * iArgs ) { int len = 0; int pdu_len = 0; int bytes_sent = 0; + int *pVal = iArgs; /* Start with first value */ BACNET_NPDU_DATA npdu_data; + BACNET_ADDRESS bcastDest; + + /* If dst was NULL, get our (local net) broadcast MAC address. */ + if ( dst == NULL ) { + datalink_get_broadcast_address(&bcastDest); + dst = &bcastDest; + } npdu_encode_npdu_network(&npdu_data, - NETWORK_MESSAGE_WHO_IS_ROUTER_TO_NETWORK, false, - MESSAGE_PRIORITY_NORMAL); - /* fixme: should dnet/dlen/dadr be set in NPDU? */ + network_message_type, false, + MESSAGE_PRIORITY_NORMAL); + + /* We don't need src information, since a message can't originate from + * our downstream BACnet network. + */ pdu_len = - npdu_encode_pdu(&Handler_Transmit_Buffer[0], NULL, NULL, &npdu_data); - /* encode the optional DNET portion of the packet */ - if (dnet >= 0) { - len = - encode_unsigned16(&Handler_Transmit_Buffer[pdu_len], - (uint16_t) dnet); - pdu_len += len; + npdu_encode_pdu(&Handler_Transmit_Buffer[0], dst, NULL, &npdu_data); + + /* Now encode the optional payload bytes, per message type */ + switch ( network_message_type ) + { + case NETWORK_MESSAGE_WHO_IS_ROUTER_TO_NETWORK: + if (*pVal >= 0) { + len = + encode_unsigned16(&Handler_Transmit_Buffer[pdu_len], + (uint16_t) *pVal); + pdu_len += len; + } + /* else, don't encode a DNET */ + break; + + case NETWORK_MESSAGE_I_AM_ROUTER_TO_NETWORK: + while ( *pVal >= 0 ) { + len = + encode_unsigned16(&Handler_Transmit_Buffer[pdu_len], + (uint16_t) *pVal); + pdu_len += len; + pVal++; + } + break; + + default: #if PRINT_ENABLED - fprintf(stderr, "Send Who-Is-Router-To-Network message to %u\n", dnet); -#endif - } else { -#if PRINT_ENABLED - fprintf(stderr, "Send Who-Is-Router-To-Network message\n"); -#endif + fprintf(stderr, "Not sent: %s message unsupported \n", + bactext_network_layer_msg_name( network_message_type ) ); + #endif + return 0; + break; /* Will never reach this line */ } + +#if PRINT_ENABLED + if ( dst != NULL ) + fprintf(stderr, "Sending %s message to BACnet network %u \n", + bactext_network_layer_msg_name( network_message_type ), + dst->net ); + else + fprintf(stderr, "Sending %s message to local BACnet network \n", + bactext_network_layer_msg_name( network_message_type ) ); +#endif + + /* Now send the message */ bytes_sent = datalink_send_pdu(dst, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED - if (bytes_sent <= 0) + if (bytes_sent <= 0) { + int wasErrno = errno; /* preserve the errno */ fprintf(stderr, - "Failed to Send Who-Is-Router-To-Network Request (%s)!\n", - strerror(errno)); + "Failed to send %s message (%s)!\n", + bactext_network_layer_msg_name( network_message_type ), + strerror(wasErrno)); + } #endif + return bytes_sent; +} + + +/** Finds a specific router, or all reachable BACnet networks. + * The response(s) will come in I-am-router-to-network message(s). + * + * @param dst [in] If NULL, request will be broadcast to the local BACnet + * network. Optionally may designate a particular router + * destination to respond. + * @param dnet [in] Which BACnet network to request for; if -1, no DNET + * will be sent and the receiving router(s) will send + * their full list of reachable BACnet networks. + */ +void Send_Who_Is_Router_To_Network( + BACNET_ADDRESS * dst, + int dnet) +{ + Send_Network_Layer_Message( NETWORK_MESSAGE_WHO_IS_ROUTER_TO_NETWORK, + dst, &dnet ); } /** Broadcast an I-am-router-to-network message, giving the list of networks we can reach. @@ -121,44 +200,9 @@ void Send_Who_Is_Router_To_Network( void Send_I_Am_Router_To_Network( const int DNET_list[]) { - int len = 0; - int pdu_len = 0; - BACNET_ADDRESS dest; - int bytes_sent = 0; - BACNET_NPDU_DATA npdu_data; - uint16_t dnet = 0; - unsigned index = 0; - - npdu_encode_npdu_network(&npdu_data, - NETWORK_MESSAGE_I_AM_ROUTER_TO_NETWORK, false, - MESSAGE_PRIORITY_NORMAL); - pdu_len = - npdu_encode_pdu(&Handler_Transmit_Buffer[0], NULL, NULL, &npdu_data); - /* encode the optional DNET list portion of the packet */ -#if PRINT_ENABLED - fprintf(stderr, "Sending I-Am-Router-To-Network message for networks:\n"); -#endif - while (DNET_list[index] != -1) { - dnet = (uint16_t) DNET_list[index]; - len = encode_unsigned16(&Handler_Transmit_Buffer[pdu_len], dnet); - pdu_len += len; - index++; -#if PRINT_ENABLED - fprintf(stderr, " %u\n", dnet); -#endif - } - /* I-Am-Router-To-Network shall always be transmitted with - a broadcast MAC address. */ - datalink_get_broadcast_address(&dest); - bytes_sent = - datalink_send_pdu(&dest, &npdu_data, &Handler_Transmit_Buffer[0], - pdu_len); -#if PRINT_ENABLED - if (bytes_sent <= 0) - fprintf(stderr, - "Failed to send I-Am-Router-To-Network message (%s)!\n", - strerror(errno)); -#endif + /* Use a NULL dst here since we want a broadcast MAC address. */ + Send_Network_Layer_Message( NETWORK_MESSAGE_I_AM_ROUTER_TO_NETWORK, + NULL, (int *) DNET_list ); } /* */ @@ -216,16 +260,16 @@ void Send_Initialize_Routing_Table( /* */ void Send_Initialize_Routing_Table_Ack( - BACNET_ROUTER_PORT * router_port_list) + const int DNET_list[] ) { int pdu_len = 0; BACNET_ADDRESS dest; int bytes_sent = 0; BACNET_NPDU_DATA npdu_data; - + // BACNET_ROUTER_PORT * router_port_list; /* FIXME: is this parameter needed? */ - router_port_list = router_port_list; +// router_port_list = router_port_list; /* setup packet for sending */ npdu_encode_npdu_network(&npdu_data, NETWORK_MESSAGE_INIT_RT_TABLE_ACK, false, MESSAGE_PRIORITY_NORMAL);