diff --git a/bacnet-stack/Makefile b/bacnet-stack/Makefile index b78ce063..e6f366be 100644 --- a/bacnet-stack/Makefile +++ b/bacnet-stack/Makefile @@ -1,4 +1,4 @@ -#Makefile to build BACnet Application +#Makefile to build BACnet Application for the Linux Port CC = gcc BASEDIR = . #CFLAGS = -Wall -I. @@ -7,9 +7,11 @@ BASEDIR = . # Note: you can strip out symbols using the strip command # to get an idea of how big the compile really is. CFLAGS = -Wall -I. -g -DBACDL_ETHERNET=1 +#CFLAGS = -Wall -I. -Iports/linux -g -DBACDL_BIP=1 SRCS = ports/linux/main.c \ ports/linux/ethernet.c \ + ports/linux/bip.c \ handlers.c \ bacdcode.c \ bigend.c \ diff --git a/bacnet-stack/bip.h b/bacnet-stack/bip.h index a99f9e71..c7870273 100644 --- a/bacnet-stack/bip.h +++ b/bacnet-stack/bip.h @@ -68,6 +68,6 @@ uint16_t bip_receive( void bip_set_address(uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4); void bip_set_port(uint16_t port); - +void bip_set_interface_name(char *ifname); #endif diff --git a/bacnet-stack/handlers.c b/bacnet-stack/handlers.c index fa65ebbf..63d07ad6 100644 --- a/bacnet-stack/handlers.c +++ b/bacnet-stack/handlers.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include "config.h" #include "bacdef.h" #include "bacdcode.h" @@ -65,7 +67,6 @@ #define bacdl_receive bip_receive #endif - // flag to send an I-Am bool I_Am_Request = true; @@ -81,6 +82,7 @@ void UnrecognizedServiceHandler( { BACNET_ADDRESS src; int pdu_len = 0; + int bytes_sent = 0; (void)service_request; (void)service_len; @@ -100,11 +102,14 @@ void UnrecognizedServiceHandler( service_data->invoke_id, REJECT_REASON_UNRECOGNIZED_SERVICE); - (void)bacdl_send_pdu( + bytes_sent = bacdl_send_pdu( dest, // destination address &Tx_Buf[0], pdu_len); // number of bytes of data - fprintf(stderr,"Sent Reject!\n"); + if (bytes_sent > 0) + fprintf(stderr,"Sent Reject!\n"); + else + fprintf(stderr,"Failed to Send Reject (%s)!\n", strerror(errno)); } // FIXME: if we handle multiple ports, then a port neutral version @@ -113,6 +118,7 @@ void Send_IAm(void) { int pdu_len = 0; BACNET_ADDRESS dest; + int bytes_sent = 0; // I-Am is a global broadcast bacdl_get_broadcast_address(&dest); @@ -133,11 +139,14 @@ void Send_IAm(void) SEGMENTATION_NONE, Device_Vendor_Identifier()); - (void)bacdl_send_pdu( + bytes_sent = bacdl_send_pdu( &dest, // destination address &Tx_Buf[0], pdu_len); // number of bytes of data - fprintf(stderr,"Sent I-Am Request!\n"); + if (bytes_sent > 0) + fprintf(stderr,"Sent I-Am Request!\n"); + else + fprintf(stderr,"Failed to Send I-Am Request (%s)!\n", strerror(errno)); } void WhoIsHandler( @@ -211,6 +220,7 @@ void ReadPropertyHandler( int32_t array_index; BACNET_ADDRESS my_address; bool send = false; + int bytes_sent = 0; len = rp_decode_service_request( service_request, @@ -244,7 +254,7 @@ void ReadPropertyHandler( &Tx_Buf[pdu_len], service_data->invoke_id, ABORT_REASON_OTHER); - fprintf(stderr,"Sent Abort!\n"); + fprintf(stderr,"Sending Abort!\n"); send = true; } else if (service_data->segmented_message) @@ -253,7 +263,7 @@ void ReadPropertyHandler( &Tx_Buf[pdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED); - fprintf(stderr,"Sent Abort!\n"); + fprintf(stderr,"Sending Abort!\n"); send = true; } else @@ -283,7 +293,7 @@ void ReadPropertyHandler( &Tx_Buf[pdu_len], service_data->invoke_id, &rp_data); - fprintf(stderr,"Sent Read Property Ack!\n"); + fprintf(stderr,"Sending Read Property Ack!\n"); send = true; } else @@ -294,7 +304,7 @@ void ReadPropertyHandler( SERVICE_CONFIRMED_READ_PROPERTY, ERROR_CLASS_PROPERTY, ERROR_CODE_UNKNOWN_PROPERTY); - fprintf(stderr,"Sent Unknown Property Error!\n"); + fprintf(stderr,"Sending Unknown Property Error!\n"); send = true; } } @@ -306,7 +316,7 @@ void ReadPropertyHandler( SERVICE_CONFIRMED_READ_PROPERTY, ERROR_CLASS_OBJECT, ERROR_CODE_UNKNOWN_OBJECT); - fprintf(stderr,"Sent Unknown Object Error!\n"); + fprintf(stderr,"Sending Unknown Object Error!\n"); send = true; } break; @@ -332,7 +342,7 @@ void ReadPropertyHandler( &Tx_Buf[pdu_len], service_data->invoke_id, &rp_data); - fprintf(stderr,"Sent Read Property Ack!\n"); + fprintf(stderr,"Sending Read Property Ack!\n"); send = true; } else @@ -343,7 +353,7 @@ void ReadPropertyHandler( SERVICE_CONFIRMED_READ_PROPERTY, ERROR_CLASS_PROPERTY, ERROR_CODE_UNKNOWN_PROPERTY); - fprintf(stderr,"Sent Unknown Property Error!\n"); + fprintf(stderr,"Sending Unknown Property Error!\n"); send = true; } } @@ -355,7 +365,7 @@ void ReadPropertyHandler( SERVICE_CONFIRMED_READ_PROPERTY, ERROR_CLASS_OBJECT, ERROR_CODE_UNKNOWN_OBJECT); - fprintf(stderr,"Sent Unknown Object Error!\n"); + fprintf(stderr,"Sending Unknown Object Error!\n"); send = true; } break; @@ -366,17 +376,19 @@ void ReadPropertyHandler( SERVICE_CONFIRMED_READ_PROPERTY, ERROR_CLASS_OBJECT, ERROR_CODE_UNKNOWN_OBJECT); - fprintf(stderr,"Sent Unknown Object Error!\n"); + fprintf(stderr,"Sending Unknown Object Error!\n"); send = true; break; } } if (send) { - (void)bacdl_send_pdu( + bytes_sent = bacdl_send_pdu( src, // destination address &Tx_Buf[0], pdu_len); // number of bytes of data + if (bytes_sent <= 0) + fprintf(stderr,"Failed to send PDU (%s)!\n", strerror(errno)); } return; @@ -395,6 +407,7 @@ void WritePropertyHandler( bool send = false; BACNET_ERROR_CLASS error_class; BACNET_ERROR_CODE error_code; + int bytes_sent = 0; // decode the service request only len = wp_decode_service_request( @@ -426,7 +439,7 @@ void WritePropertyHandler( &Tx_Buf[pdu_len], service_data->invoke_id, ABORT_REASON_OTHER); - fprintf(stderr,"Sent Abort!\n"); + fprintf(stderr,"Sending Abort!\n"); send = true; } else if (service_data->segmented_message) @@ -435,7 +448,7 @@ void WritePropertyHandler( &Tx_Buf[pdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED); - fprintf(stderr,"Sent Abort!\n"); + fprintf(stderr,"Sending Abort!\n"); send = true; } else @@ -449,7 +462,7 @@ void WritePropertyHandler( &Tx_Buf[pdu_len], service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY); - fprintf(stderr,"Sent Write Property Simple Ack!\n"); + fprintf(stderr,"Sending Write Property Simple Ack!\n"); send = true; } else @@ -460,7 +473,7 @@ void WritePropertyHandler( SERVICE_CONFIRMED_WRITE_PROPERTY, error_class, error_code); - fprintf(stderr,"Sent Write Property Error!\n"); + fprintf(stderr,"Sending Write Property Error!\n"); send = true; } break; @@ -471,7 +484,7 @@ void WritePropertyHandler( SERVICE_CONFIRMED_WRITE_PROPERTY, ERROR_CLASS_PROPERTY, ERROR_CODE_WRITE_ACCESS_DENIED); - fprintf(stderr,"Sent Write Access Error!\n"); + fprintf(stderr,"Sending Write Access Error!\n"); send = true; break; default: @@ -481,17 +494,19 @@ void WritePropertyHandler( SERVICE_CONFIRMED_WRITE_PROPERTY, ERROR_CLASS_OBJECT, ERROR_CODE_UNKNOWN_OBJECT); - fprintf(stderr,"Sent Unknown Object Error!\n"); + fprintf(stderr,"Sending Unknown Object Error!\n"); send = true; break; } } if (send) { - (void)bacdl_send_pdu( + bytes_sent = bacdl_send_pdu( src, // destination address &Tx_Buf[0], pdu_len); // number of bytes of data + if (bytes_sent <= 0) + fprintf(stderr,"Failed to send PDU (%s)!\n", strerror(errno)); } return; diff --git a/bacnet-stack/ports/linux/bip.c b/bacnet-stack/ports/linux/bip.c index e6dddd27..33147f90 100644 --- a/bacnet-stack/ports/linux/bip.c +++ b/bacnet-stack/ports/linux/bip.c @@ -34,17 +34,17 @@ #include // for standard integer types uint8_t etc. #include // for the standard bool type. -#include #include "bacdcode.h" -#include "bip.h" +#include "bip.h" +#include "net.h" static int BIP_Receive_Socket = -1; /* port to use - stored in network byte order */ static uint16_t BIP_Port = 0; /* IP Address - stored in network byte order */ -static struct in_addr BIP_Address = {{{-1}}}; +static struct in_addr BIP_Address; /* Broadcast Address */ -static struct in_addr BIP_Broadcast_Address = {{{-1}}}; +static struct in_addr BIP_Broadcast_Address; bool bip_valid(void) { @@ -54,7 +54,7 @@ bool bip_valid(void) void bip_cleanup(void) { if (bip_valid()) - closesocket(BIP_Receive_Socket); + close(BIP_Receive_Socket); BIP_Receive_Socket = -1; return; @@ -76,7 +76,11 @@ static void set_network_address(struct in_addr *net_address, net_address->s_addr = htonl(long_data.value); } -void bip_set_address(uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4) +void bip_set_address( + uint8_t octet1, + uint8_t octet2, + uint8_t octet3, + uint8_t octet4) { set_network_address(&BIP_Address, octet1, octet2, octet3, octet4); } @@ -89,8 +93,8 @@ void bip_set_port(uint16_t port) bool bip_init(void) { int rv = 0; // return from socket lib calls - struct sockaddr_in sin = {-1}; - + struct sockaddr_in sin; + /* network global broadcast address */ set_network_address(&BIP_Broadcast_Address,255,255,255,255); /* configure standard BACnet/IP port */ @@ -110,7 +114,7 @@ bool bip_init(void) (const struct sockaddr*)&sin, sizeof(struct sockaddr)); if (rv < 0) { - closesocket(BIP_Receive_Socket); + close(BIP_Receive_Socket); BIP_Receive_Socket = -1; return false; } @@ -119,18 +123,16 @@ bool bip_init(void) } /* function to send a packet out the 802.2 socket */ -/* returns 0 on success, non-zero on failure */ +/* returns number of bytes sent on success, negative on failure */ static int bip_send( struct sockaddr_in *bip_dest, uint8_t *pdu, // any data to be sent - may be null unsigned pdu_len) // number of bytes of data { int status = -1; /* initially fail status */ - int bytes = 0; int bip_send_socket = -1; uint8_t mtu[MAX_MPDU] = { 0 }; int mtu_len = 0; - int i = 0; int rv = 0; /* return value from socket calls */ // assumes that the driver has already been initialized @@ -138,15 +140,15 @@ static int bip_send( // FIXME: can we use the same socket as receive bip? bip_send_socket = socket(AF_INET, SOCK_DGRAM, 0); if (bip_send_socket < 0) - return status; + return bip_send_socket; /* UDP is connection based */ - rv = connect(bip_send_socket, + status = connect(bip_send_socket, (const struct sockaddr*)bip_dest, sizeof(struct sockaddr)); - if (bip_send_socket < 0) + if (status < 0) { - closesocket(bip_send_socket); + close(bip_send_socket); return status; } @@ -161,13 +163,11 @@ static int bip_send( mtu_len += pdu_len; /* Send the packet */ - rv = sendto(bip_send_socket, (char *)mtu, mtu_len, 0, + status = sendto(bip_send_socket, (char *)mtu, mtu_len, 0, (struct sockaddr *)bip_dest, sizeof(struct sockaddr)); - if (rv >= 0) - status = 0; - closesocket(bip_send_socket); + close(bip_send_socket); return status; } @@ -179,10 +179,7 @@ int bip_send_pdu( uint8_t *pdu, // any data to be sent - may be null unsigned pdu_len) // number of bytes of data { - int i = 0; // counter struct sockaddr_in bip_dest; - uint32_t network_address = 0; - uint16_t network_port = 0; /* load destination IP address */ bip_dest.sin_family = AF_INET; diff --git a/bacnet-stack/ports/linux/ethernet.c b/bacnet-stack/ports/linux/ethernet.c index f5c0e755..2cc5ef59 100644 --- a/bacnet-stack/ports/linux/ethernet.c +++ b/bacnet-stack/ports/linux/ethernet.c @@ -35,74 +35,7 @@ #include // for standard integer types uint8_t etc. #include // for the standard bool type. -/* common unix sockets headers needed */ -#include /* basic system data types */ -#include /* timeval{} for select() */ -#include /* timespec{} for pselect() */ -#include /* sockaddr_in{} and other Internet defns */ -#include /* inet(3) functions */ -#include -#include /* for nonblocking */ -#include -#include -#include -#include -#include -#include /* for S_xxx file mode constants */ -#include /* for iovec{} and readv/writev */ -#include -#include -#include /* for Unix domain sockets */ - -#ifdef HAVE_SYS_SELECT_H -# include /* for convenience */ -#endif - -#ifdef HAVE_POLL_H -# include /* for convenience */ -#endif - -#ifdef HAVE_STRINGS_H -# include /* for convenience */ -#endif - -/* Three headers are normally needed for socket/file ioctl's: - * , , and . - */ -#ifdef HAVE_SYS_IOCTL_H -# include -#endif -#ifdef HAVE_SYS_FILIO_H -# include -#endif -#ifdef HAVE_SYS_SOCKIO_H -# include -#endif - -#ifdef HAVE_PTHREAD_H -# include -#endif - - -#define ENUMS -#include -#include -#include -#include /* for the glibc version number */ -#if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1 -#include -#include /* the L2 protocols */ -#else -#include -#include -#include /* The L2 protocols */ -#endif -#include -#include -#include -#include -#include - +#include "net.h" #include "bacdef.h" #include "ethernet.h" #include "bacdcode.h" @@ -248,14 +181,13 @@ bool ethernet_init(char *interface_name) } /* function to send a packet out the 802.2 socket */ -/* returns 0 on success, non-zero on failure */ +/* returns bytes sent success, negative on failure */ int ethernet_send( BACNET_ADDRESS *dest, // destination address BACNET_ADDRESS *src, // source address uint8_t *pdu, // any data to be sent - may be null unsigned pdu_len) // number of bytes of data { - int status = -1; int bytes = 0; uint8_t mtu[MAX_MPDU] = { 0 }; int mtu_len = 0; @@ -265,7 +197,7 @@ int ethernet_send( if (eth802_sockfd < 0) { fprintf(stderr, "ethernet: 802.2 socket is invalid!\n"); - return status; + return -1; } /* load destination ethernet MAC address */ if (dest->mac_len == 6) @@ -279,7 +211,7 @@ int ethernet_send( else { fprintf(stderr, "ethernet: invalid destination MAC address!\n"); - return status; + return -2; } /* load source ethernet MAC address */ @@ -294,12 +226,12 @@ int ethernet_send( else { fprintf(stderr, "ethernet: invalid source MAC address!\n"); - return status; + return -3; } if ((14 + 3 + pdu_len) > MAX_MPDU) { fprintf(stderr, "ethernet: PDU is too big to send!\n"); - return status; + return -4; } /* packet length */ mtu_len += encode_unsigned16(&mtu[12], @@ -316,20 +248,15 @@ int ethernet_send( sendto(eth802_sockfd, &mtu, mtu_len, 0, (struct sockaddr *) ð_addr, sizeof(struct sockaddr)); /* did it get sent? */ - if (bytes < 0) { + if (bytes < 0) fprintf(stderr,"ethernet: Error sending packet: %s\n", strerror(errno)); - return status; - } - // got this far - must be good! - status = 0; - - return status; + return bytes; } /* function to send a packet out the 802.2 socket */ -/* returns zero on success, non-zero on failure */ +/* returns number of bytes sent on success, negative on failure */ int ethernet_send_pdu( BACNET_ADDRESS *dest, // destination address uint8_t *pdu, // any data to be sent - may be null diff --git a/bacnet-stack/ports/linux/main.c b/bacnet-stack/ports/linux/main.c index 3b73132a..9a11ec03 100644 --- a/bacnet-stack/ports/linux/main.c +++ b/bacnet-stack/ports/linux/main.c @@ -26,26 +26,93 @@ #include #include #include +#include +#include #include "config.h" #include "bacdef.h" +#include "handlers.h" #include "bacdcode.h" #include "npdu.h" #include "apdu.h" #include "device.h" -#include "ai.h" -#include "rp.h" -#include "wp.h" -#include "iam.h" -#include "whois.h" -#include "reject.h" -#include "abort.h" -#include "bacerror.h" -#include "ethernet.h" -#include "handlers.h" +#ifdef BACDL_ETHERNET + #include "ethernet.h" +#endif +#ifdef BACDL_BIP + #include "bip.h" +#endif +#include "net.h" // buffers used for receiving static uint8_t Rx_Buf[MAX_MPDU] = {0}; +static int get_local_ifr_ioctl(char *ifname, struct ifreq *ifr, int request) +{ + int fd; + int rv; // return value + + strncpy(ifr->ifr_name, ifname, sizeof(ifr->ifr_name)); + fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (fd < 0) + rv = fd; + else + rv = ioctl(fd, request, ifr); + + return rv; +} + +static int get_local_address_ioctl( + char *ifname, + struct in_addr *addr, + int request) +{ + struct ifreq ifr = { {{0}} }; + struct sockaddr_in *tcpip_address; + int rv; // return value + + rv = get_local_ifr_ioctl(ifname,&ifr,request); + if (rv >= 0) { + tcpip_address = (struct sockaddr_in *) &ifr.ifr_addr; + memcpy(addr, &tcpip_address->sin_addr, sizeof(struct in_addr)); + } + + return rv; +} + +static void decode_network_address(struct in_addr *net_address, + uint8_t *octet1, uint8_t *octet2, uint8_t *octet3, uint8_t *octet4) +{ + union { + uint8_t byte[4]; + uint32_t value; + } long_data = {{0}}; + + long_data.value = net_address->s_addr; + + *octet1 = long_data.byte[0]; + *octet2 = long_data.byte[1]; + *octet3 = long_data.byte[2]; + *octet4 = long_data.byte[3]; +} + +static void Init_Network(char *ifname) +{ + struct in_addr local_address; + uint8_t octet1; + uint8_t octet2; + uint8_t octet3; + uint8_t octet4; + + /* setup local address */ + get_local_address_ioctl(ifname, &local_address, SIOCGIFADDR); + decode_network_address(&local_address, &octet1, &octet2, &octet3, &octet4); + #ifdef BACDL_BIP + bip_set_address(octet1, octet2, octet3, octet4); + #endif + fprintf(stderr,"IP Address: %d.%d.%d.%d\n", + (int)octet1, (int)octet2, (int)octet3, (int)octet4); +} + static void Init_Device_Parameters(void) { // configure my initial values @@ -83,17 +150,42 @@ static void Init_Service_Handlers(void) WritePropertyHandler); } +static void sig_handler(int signo) +{ + #ifdef BACDL_ETHERNET + ethernet_cleanup(); + #endif + #ifdef BACDL_BIP + bip_cleanup(); + #endif + + exit(0); +} + int main(int argc, char *argv[]) { BACNET_ADDRESS src = {0}; // address where message came from uint16_t pdu_len = 0; unsigned timeout = 100; // milliseconds + // Linux specials + signal(SIGINT, sig_handler); + signal(SIGHUP, sig_handler); + signal(SIGTERM, sig_handler); + // setup this BACnet Server Init_Device_Parameters(); Init_Service_Handlers(); + #ifdef BACDL_ETHERNET // init the physical layer if (!ethernet_init("eth0")) return 1; + #endif + #ifdef BACDL_BIP + Init_Network("eth0"); + if (!bip_init()) + return 1; + #endif + // loop forever for (;;) @@ -101,11 +193,20 @@ int main(int argc, char *argv[]) // input // returns 0 bytes on timeout + #ifdef BACDL_ETHERNET pdu_len = ethernet_receive( &src, &Rx_Buf[0], MAX_MPDU, timeout); + #endif + #ifdef BACDL_BIP + pdu_len = bip_receive( + &src, + &Rx_Buf[0], + MAX_MPDU, + timeout); + #endif // process if (pdu_len)