Feature/refactor bacnet ipv4 add unit tests (#64)
* refactor BACnet/IPv4 BVLC into encode-decode library with unit tests Added Read-Broadcast-Distribution-Table encoding and unit test. Added Read-Broadcast-Distribution-Table-Ack encoding and unit test. Added Read-Foreign-Device-Table-Ack encoding and unit test. Added some BDT/FDT diff copy functions with unit tests Added some FDT add and delete entry functions with unit tests Added some BDT set append and clear entry functions with unit tests Added some BIPv4 address conversion functions with unit tests Added non-BBMD handling unit test Added basic unit test for BBMD handler Added BBMD broadcast mask get set and unit tests Added IPv6 maintenance timer. Added ReadFDT app Fixed ReadBDT app Added Who-Is to Makefile for individual app build Fixed debugging code blocks projects by swapping bip.c for h_bbmd.c module. Ported BACnet/IPv4 to refactored BVLC for Linux, BSD, Windows Fix datalink debug for DLENV module Improve BIPv4 linux driver debug info Added BDT mask functions Reduce debug info clutter in Who-Is app by using environment option Fix TTL seconds upper bounds addition Fix CIDR prefix calculation on Linux BIPv4. Convert BSD BIPv4 to BVLCv4 Fix CMake build for BIPv4 (Linux, BSD, Windows) Added [U]nsigned to 0xBAC0 constants Cleanup POSIX and Win32 API sockets Remove unnecessary file scope variable initialization Fix routed NPDU to depend on datalink; fix warning Remove OS dependent network code from gateway Enable BBMD client in library by default Co-authored-by: Steve Karg <skarg@users.sourceforge.net> Co-authored-by: Steve Karg <steve.karg@legrand.us>
This commit is contained in:
+5
-1
@@ -125,6 +125,8 @@ add_library(${PROJECT_NAME}
|
||||
src/bacnet/bactext.h
|
||||
src/bacnet/bactimevalue.c
|
||||
src/bacnet/bactimevalue.h
|
||||
$<$<BOOL:${BACDL_BIP}>:src/bacnet/basic/bbmd/h_bbmd.c>
|
||||
$<$<BOOL:${BACDL_BIP}>:src/bacnet/basic/bbmd/h_bbmd.h>
|
||||
$<$<BOOL:${BACDL_BIP6}>:src/bacnet/basic/bbmd6/h_bbmd6.c>
|
||||
$<$<BOOL:${BACDL_BIP6}>:src/bacnet/basic/bbmd6/h_bbmd6.h>
|
||||
$<$<BOOL:${BACDL_BIP6}>:src/bacnet/basic/bbmd6/vmac.c>
|
||||
@@ -348,7 +350,6 @@ add_library(${PROJECT_NAME}
|
||||
src/bacnet/datalink/bacsec.h
|
||||
src/bacnet/datalink/bip6.h
|
||||
$<$<BOOL:${BACDL_BIP}>:src/bacnet/datalink/bip.h>
|
||||
$<$<BOOL:${BACDL_BIP}>:src/bacnet/datalink/bip.c>
|
||||
$<$<BOOL:${BACDL_BIP6}>:src/bacnet/datalink/bvlc6.c>
|
||||
$<$<BOOL:${BACDL_BIP6}>:src/bacnet/datalink/bvlc6.h>
|
||||
$<$<BOOL:${BACDL_BIP}>:src/bacnet/datalink/bvlc.h>
|
||||
@@ -579,6 +580,9 @@ if(BACNET_STACK_BUILD_APPS)
|
||||
add_executable(readbdt apps/readbdt/main.c)
|
||||
target_link_libraries(readbdt PRIVATE ${PROJECT_NAME})
|
||||
|
||||
add_executable(readfdt apps/readfdt/main.c)
|
||||
target_link_libraries(readfdt PRIVATE ${PROJECT_NAME})
|
||||
|
||||
add_executable(readfile apps/readfile/main.c)
|
||||
target_link_libraries(readfile PRIVATE ${PROJECT_NAME})
|
||||
|
||||
|
||||
@@ -57,6 +57,14 @@ gateway:
|
||||
gateway-win32:
|
||||
$(MAKE) BACNET_PORT=win32 -C apps gateway
|
||||
|
||||
.PHONY: readbdt
|
||||
readbdt:
|
||||
$(MAKE) -s -C apps $@
|
||||
|
||||
.PHONY: readfdt
|
||||
readfdt:
|
||||
$(MAKE) -s -C apps $@
|
||||
|
||||
.PHONY: server
|
||||
server:
|
||||
$(MAKE) -s -C apps $@
|
||||
@@ -73,6 +81,10 @@ mstpcrc:
|
||||
uevent:
|
||||
$(MAKE) -s -C apps $@
|
||||
|
||||
.PHONY: whois
|
||||
whois:
|
||||
$(MAKE) -C apps $@
|
||||
|
||||
.PHONY: writepropm
|
||||
writepropm:
|
||||
$(MAKE) -s -C apps $@
|
||||
|
||||
+16
-5
@@ -32,15 +32,14 @@ BACDL_DEFINE=-DBACDL_BIP6=1
|
||||
endif
|
||||
ifeq (${BACDL},)
|
||||
BACDL_DEFINE ?= -DBACDL_BIP=1
|
||||
BBMD_DEFINE ?= -DBBMD_ENABLED=1
|
||||
BBMD_DEFINE ?= -DBBMD_ENABLED=1 -DBBMD_CLIENT_ENABLED
|
||||
endif
|
||||
|
||||
ifeq (${BBMD},server)
|
||||
BBMD_DEFINE=-DBBMD_ENABLED=1
|
||||
endif
|
||||
ifeq (${BBMD},client)
|
||||
BBMD_DEFINE=-DBBMD_ENABLED=1
|
||||
BBMD_DEFINE=-DBBMD_CLIENT_ENABLED
|
||||
BBMD_DEFINE = -DBBMD_ENABLED=1 -DBBMD_CLIENT_ENABLED
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -131,7 +130,7 @@ PORT_ETHERNET_SRC = \
|
||||
PORT_BIP_SRC = \
|
||||
$(BACNET_PORT_DIR)/bip-init.c \
|
||||
$(BACNET_SRC_DIR)/bacnet/datalink/bvlc.c \
|
||||
$(BACNET_SRC_DIR)/bacnet/datalink/bip.c
|
||||
$(BACNET_SRC_DIR)/bacnet/basic/bbmd/h_bbmd.c
|
||||
|
||||
PORT_BIP6_SRC = \
|
||||
$(BACNET_PORT_DIR)/bip6.c \
|
||||
@@ -189,7 +188,7 @@ SUBDIRS = readprop writeprop readfile writefile reinit server dcc \
|
||||
writepropm uptransfer getevent uevent abort error
|
||||
|
||||
ifeq (${BACDL_DEFINE},-DBACDL_BIP=1)
|
||||
SUBDIRS += whoisrouter iamrouter initrouter readbdt
|
||||
SUBDIRS += whoisrouter iamrouter initrouter readbdt readfdt
|
||||
endif
|
||||
|
||||
ifeq (${BACNET_PORT},linux)
|
||||
@@ -258,10 +257,22 @@ iamrouter:
|
||||
initrouter:
|
||||
$(MAKE) -b -C $@
|
||||
|
||||
.PHONY: readbdt
|
||||
readbdt:
|
||||
$(MAKE) -b -C $@
|
||||
|
||||
.PHONY: readfdt
|
||||
readfdt:
|
||||
$(MAKE) -b -C $@
|
||||
|
||||
.PHONY: uevent
|
||||
uevent:
|
||||
$(MAKE) -b -C $@
|
||||
|
||||
.PHONY: whois
|
||||
whois:
|
||||
$(MAKE) -b -C $@
|
||||
|
||||
.PHONY: router
|
||||
router:
|
||||
$(MAKE) -s -b -C $@
|
||||
|
||||
+3
-2
@@ -1432,7 +1432,7 @@ int main(int argc, char *argv[])
|
||||
* My_BIP_Port will be non-zero in this case.
|
||||
*/
|
||||
if (My_BIP_Port > 0) {
|
||||
bip_set_port(htons(My_BIP_Port));
|
||||
bip_set_port(My_BIP_Port);
|
||||
}
|
||||
#endif
|
||||
address_init();
|
||||
@@ -1446,7 +1446,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
#if defined(BACDL_BIP)
|
||||
if (My_BIP_Port > 0) {
|
||||
bip_set_port(htons(0xBAC0)); /* Set back to std BACnet/IP port */
|
||||
/* Set back to std BACnet/IP port */
|
||||
bip_set_port(0xBAC0);
|
||||
}
|
||||
#endif
|
||||
/* try to bind with the target device */
|
||||
|
||||
+20
-46
@@ -31,6 +31,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include "bacnet/config.h"
|
||||
@@ -172,19 +173,20 @@ static void Initialize_Device_Addresses()
|
||||
DEVICE_OBJECT_DATA *pDev = NULL;
|
||||
/* Setup info for the main gateway device first */
|
||||
pDev = Get_Routed_Device_Object(i);
|
||||
|
||||
/* we can't use datalink_get_my_address() since it is
|
||||
mapped to routed_get_my_address() in this app
|
||||
to get the parent device address */
|
||||
#if defined(BACDL_BIP)
|
||||
uint16_t myPort;
|
||||
struct in_addr *netPtr; /* Lets us cast to this type */
|
||||
uint8_t *gatewayMac = NULL;
|
||||
uint32_t myAddr = bip_get_addr();
|
||||
gatewayMac = pDev->bacDevAddr.mac; /* Keep pointer to the main MAC */
|
||||
memcpy(pDev->bacDevAddr.mac, &myAddr, 4);
|
||||
myPort = bip_get_port();
|
||||
memcpy(&pDev->bacDevAddr.mac[4], &myPort, 2);
|
||||
pDev->bacDevAddr.mac_len = 6;
|
||||
bip_get_my_address(&pDev->bacDevAddr);
|
||||
#elif defined(BACDL_MSTP)
|
||||
pDev->bacDevAddr.mac_len = 1;
|
||||
pDev->bacDevAddr.mac[0] = dlmstp_mac_address();
|
||||
dlmstp_get_my_address(&pDev->bacDevAddr);
|
||||
#elif defined(BACDL_ARCNET)
|
||||
arcnet_get_my_address(&pDev->bacDevAddr);
|
||||
#elif defined(BACDL_ETHERNET)
|
||||
ethernet_get_my_address(&pDev->bacDevAddr);
|
||||
#elif defined(BACDL_BIP6)
|
||||
bip6_get_my_address&pDev->bacDevAddr);
|
||||
#else
|
||||
#error "No support for this Data Link Layer type "
|
||||
#endif
|
||||
@@ -193,38 +195,12 @@ static void Initialize_Device_Addresses()
|
||||
|
||||
for (i = 1; i < MAX_NUM_DEVICES; i++) {
|
||||
pDev = Get_Routed_Device_Object(i);
|
||||
if (pDev == NULL)
|
||||
if (pDev == NULL) {
|
||||
continue;
|
||||
#if defined(BACDL_BIP)
|
||||
virtual_mac = i;
|
||||
netPtr = (struct in_addr *)pDev->bacDevAddr.mac;
|
||||
#if (MAX_NUM_DEVICES > 0xFFFFFF)
|
||||
pDev->bacDevAddr.mac[0] = ((virtual_mac & 0xff000000) >> 24);
|
||||
#else
|
||||
pDev->bacDevAddr.mac[0] = gatewayMac[3];
|
||||
#endif
|
||||
#if (MAX_NUM_DEVICES > 0xFFFF)
|
||||
pDev->bacDevAddr.mac[1] = ((virtual_mac & 0xff0000) >> 16);
|
||||
#else
|
||||
pDev->bacDevAddr.mac[1] = gatewayMac[2];
|
||||
#endif
|
||||
#if (MAX_NUM_DEVICES > 0xFF)
|
||||
pDev->bacDevAddr.mac[2] = ((virtual_mac & 0xff00) >> 8);
|
||||
#else
|
||||
pDev->bacDevAddr.mac[2] = gatewayMac[1];
|
||||
#endif
|
||||
pDev->bacDevAddr.mac[3] = (virtual_mac & 0xff);
|
||||
memcpy(&pDev->bacDevAddr.mac[4], &myPort, 2);
|
||||
pDev->bacDevAddr.mac_len = 6;
|
||||
pDev->bacDevAddr.net = VIRTUAL_DNET;
|
||||
memcpy(&pDev->bacDevAddr.adr[0], &pDev->bacDevAddr.mac[0], 6);
|
||||
pDev->bacDevAddr.len = 6;
|
||||
printf(" - Routed device [%d] ID %u at %s \n", i,
|
||||
pDev->bacObj.Object_Instance_Number, inet_ntoa(*netPtr));
|
||||
#elif defined(BACDL_MSTP)
|
||||
/* Todo: set MS/TP net and port #s */
|
||||
pDev->bacDevAddr.mac_len = 2;
|
||||
#endif
|
||||
}
|
||||
virtual_mac = pDev->bacObj.Object_Instance_Number;
|
||||
encode_unsigned24(&pDev->bacDevAddr.adr[0], virtual_mac);
|
||||
pDev->bacDevAddr.len = 3;
|
||||
/* broadcast an I-Am for each routed Device now */
|
||||
Send_I_Am(&Handler_Transmit_Buffer[0]);
|
||||
}
|
||||
@@ -234,7 +210,7 @@ static void Initialize_Device_Addresses()
|
||||
*
|
||||
* @see Device_Set_Object_Instance_Number, dlenv_init, Send_I_Am,
|
||||
* datalink_receive, npdu_handler,
|
||||
* dcc_timer_seconds, bvlc_maintenance_timer,
|
||||
* dcc_timer_seconds, datalink_maintenance_timer,
|
||||
* Load_Control_State_Machine_Handler, handler_cov_task,
|
||||
* tsm_timer_milliseconds
|
||||
*
|
||||
@@ -309,9 +285,7 @@ int main(int argc, char *argv[])
|
||||
if (elapsed_seconds) {
|
||||
last_seconds = current_seconds;
|
||||
dcc_timer_seconds(elapsed_seconds);
|
||||
#if defined(BACDL_BIP) && BBMD_ENABLED
|
||||
bvlc_maintenance_timer(elapsed_seconds);
|
||||
#endif
|
||||
datalink_maintenance_timer(elapsed_seconds);
|
||||
dlenv_maintenance_timer(elapsed_seconds);
|
||||
Load_Control_State_Machine_Handler();
|
||||
elapsed_milliseconds = elapsed_seconds * 1000;
|
||||
|
||||
@@ -368,9 +368,7 @@ int main(int argc, char *argv[])
|
||||
/* increment timer - exit if timed out */
|
||||
elapsed_seconds = current_seconds - last_seconds;
|
||||
if (elapsed_seconds) {
|
||||
#if defined(BACDL_BIP) && BBMD_ENABLED
|
||||
bvlc_maintenance_timer(elapsed_seconds);
|
||||
#endif
|
||||
datalink_maintenance_timer(elapsed_seconds);
|
||||
}
|
||||
total_seconds += elapsed_seconds;
|
||||
if (total_seconds > timeout_seconds) {
|
||||
|
||||
+2
-4
@@ -197,7 +197,7 @@ static void piface_task(void)
|
||||
*
|
||||
* @see Device_Set_Object_Instance_Number, dlenv_init, Send_I_Am,
|
||||
* datalink_receive, npdu_handler,
|
||||
* dcc_timer_seconds, bvlc_maintenance_timer,
|
||||
* dcc_timer_seconds, datalink_maintenance_timer,
|
||||
* handler_cov_task,
|
||||
* tsm_timer_milliseconds
|
||||
*
|
||||
@@ -254,9 +254,7 @@ int main(int argc, char *argv[])
|
||||
if (elapsed_seconds) {
|
||||
last_seconds = current_seconds;
|
||||
dcc_timer_seconds(elapsed_seconds);
|
||||
#if defined(BACDL_BIP) && BBMD_ENABLED
|
||||
bvlc_maintenance_timer(elapsed_seconds);
|
||||
#endif
|
||||
datalink_maintenance_timer(elapsed_seconds);
|
||||
dlenv_maintenance_timer(elapsed_seconds);
|
||||
elapsed_milliseconds = elapsed_seconds * 1000;
|
||||
handler_cov_timer_seconds(elapsed_seconds);
|
||||
|
||||
+6
-10
@@ -56,8 +56,7 @@
|
||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||
|
||||
/* targets interpreted from the command line options */
|
||||
static uint32_t Target_BBMD_Address;
|
||||
static uint16_t Target_BBMD_Port;
|
||||
static BACNET_IP_ADDRESS Target_BBMD_Address;
|
||||
|
||||
static bool Error_Detected = false;
|
||||
|
||||
@@ -134,8 +133,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
/* decode the command line parameters */
|
||||
if (argc > 1) {
|
||||
Target_BBMD_Address = inet_addr(argv[1]);
|
||||
if (Target_BBMD_Address == (-1)) {
|
||||
if (!bip_get_addr_by_name(argv[1], &Target_BBMD_Address)) {
|
||||
fprintf(stderr, "IP=%s - failed to convert address.\r\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
@@ -143,14 +141,14 @@ int main(int argc, char *argv[])
|
||||
if (argc > 2) {
|
||||
port = strtol(argv[2], NULL, 0);
|
||||
if ((port > 0) && (port <= 65535)) {
|
||||
Target_BBMD_Port = htons(port);
|
||||
Target_BBMD_Address.port = (uint16_t)port;
|
||||
} else {
|
||||
fprintf(
|
||||
stderr, "port=%ld - port must be between 0-65535.\r\n", port);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
Target_BBMD_Port = htons(47808);
|
||||
Target_BBMD_Address.port = 0xBAC0U;
|
||||
}
|
||||
/* setup my info */
|
||||
Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE);
|
||||
@@ -162,7 +160,7 @@ int main(int argc, char *argv[])
|
||||
last_seconds = time(NULL);
|
||||
timeout_seconds = apdu_timeout() / 1000;
|
||||
/* send the request */
|
||||
bvlc_bbmd_read_bdt(Target_BBMD_Address, Target_BBMD_Port);
|
||||
bvlc_bbmd_read_bdt(&Target_BBMD_Address);
|
||||
/* loop forever */
|
||||
for (;;) {
|
||||
/* increment timer - exit if timed out */
|
||||
@@ -178,9 +176,7 @@ int main(int argc, char *argv[])
|
||||
/* increment timer - exit if timed out */
|
||||
elapsed_seconds = current_seconds - last_seconds;
|
||||
if (elapsed_seconds) {
|
||||
#if defined(BACDL_BIP) && BBMD_ENABLED
|
||||
bvlc_maintenance_timer(elapsed_seconds);
|
||||
#endif
|
||||
datalink_maintenance_timer(elapsed_seconds);
|
||||
}
|
||||
total_seconds += elapsed_seconds;
|
||||
if (total_seconds > timeout_seconds) {
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#Makefile to build BACnet Application for the GCC Port
|
||||
|
||||
TARGET = bacrfdt
|
||||
# BACnet objects that are used with this app
|
||||
BACNET_OBJECT_DIR = $(BACNET_SRC_DIR)/bacnet/basic/object
|
||||
SRC = main.c \
|
||||
$(BACNET_OBJECT_DIR)/client/device-client.c \
|
||||
$(BACNET_OBJECT_DIR)/netport.c
|
||||
BACNET_BASIC_SRC += \
|
||||
$(BACNET_SRC_DIR)/bacnet/basic/service/h_apdu.c \
|
||||
$(BACNET_SRC_DIR)/bacnet/basic/service/h_iam.c \
|
||||
$(BACNET_SRC_DIR)/bacnet/basic/service/h_noserv.c \
|
||||
$(BACNET_SRC_DIR)/bacnet/basic/service/h_rp.c \
|
||||
$(BACNET_SRC_DIR)/bacnet/basic/service/h_whois.c \
|
||||
$(BACNET_SRC_DIR)/bacnet/basic/service/s_iam.c \
|
||||
$(BACNET_SRC_DIR)/bacnet/basic/service/s_whois.c
|
||||
|
||||
# TARGET_EXT is defined in apps/Makefile as .exe or nothing
|
||||
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
||||
|
||||
SRCS = $(SRC) $(BACNET_SRC) $(BACNET_BASIC_SRC) $(BACNET_PORT_SRC)
|
||||
|
||||
OBJS += ${SRCS:.c=.o}
|
||||
|
||||
.PHONY: all
|
||||
all: Makefile ${TARGET_BIN}
|
||||
|
||||
${TARGET_BIN}: ${OBJS}
|
||||
${CC} ${PFLAGS} ${OBJS} ${LFLAGS} -o $@
|
||||
size $@
|
||||
cp $@ ../../bin
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
.PHONY: depend
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f core ${TARGET_BIN} ${OBJS} $(TARGET).map
|
||||
|
||||
.PHONY: include
|
||||
include: .depend
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* command line tool that sends a BACnet BVLC message, and displays the reply */
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h> /* for time */
|
||||
#include <errno.h>
|
||||
#include <ctype.h> /* for toupper */
|
||||
#include "bacnet/bactext.h"
|
||||
#include "bacnet/iam.h"
|
||||
#include "bacnet/basic/binding/address.h"
|
||||
#include "bacnet/config.h"
|
||||
#include "bacnet/bacdef.h"
|
||||
#include "bacnet/npdu.h"
|
||||
#include "bacnet/apdu.h"
|
||||
#include "bacnet/basic/object/device.h"
|
||||
#include "bacnet/datalink/datalink.h"
|
||||
#include "bacnet/datalink/bvlc.h"
|
||||
/* some demo stuff needed */
|
||||
#ifndef DEBUG_ENABLED
|
||||
#define DEBUG_ENABLED 0
|
||||
#endif
|
||||
#include "bacnet/basic/sys/debug.h"
|
||||
#include "bacnet/basic/sys/filename.h"
|
||||
#include "bacnet/basic/services.h"
|
||||
#include "bacnet/basic/services.h"
|
||||
#include "bacnet/basic/tsm/tsm.h"
|
||||
#include "bacnet/datalink/dlenv.h"
|
||||
|
||||
/* buffer used for receive */
|
||||
static uint8_t Rx_Buf[MAX_MPDU];
|
||||
|
||||
/* targets interpreted from the command line options */
|
||||
static BACNET_IP_ADDRESS Target_BBMD_Address;
|
||||
|
||||
static bool Error_Detected;
|
||||
|
||||
static void MyAbortHandler(
|
||||
BACNET_ADDRESS *src, uint8_t invoke_id, uint8_t abort_reason, bool server)
|
||||
{
|
||||
/* FIXME: verify src and invoke id */
|
||||
(void)src;
|
||||
(void)invoke_id;
|
||||
(void)server;
|
||||
printf("BACnet Abort: %s\r\n", bactext_abort_reason_name(abort_reason));
|
||||
Error_Detected = true;
|
||||
}
|
||||
|
||||
static void MyRejectHandler(
|
||||
BACNET_ADDRESS *src, uint8_t invoke_id, uint8_t reject_reason)
|
||||
{
|
||||
/* FIXME: verify src and invoke id */
|
||||
(void)src;
|
||||
(void)invoke_id;
|
||||
printf("BACnet Reject: %s\r\n", bactext_reject_reason_name(reject_reason));
|
||||
Error_Detected = true;
|
||||
}
|
||||
|
||||
static void Init_Service_Handlers(void)
|
||||
{
|
||||
Device_Init(NULL);
|
||||
/* we need to handle who-is
|
||||
to support dynamic device binding to us */
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||
/* set the handler for all the services we don't implement
|
||||
It is required to send the proper reject message... */
|
||||
apdu_set_unrecognized_service_handler_handler(handler_unrecognized_service);
|
||||
/* we must implement read property - it's required! */
|
||||
apdu_set_confirmed_handler(
|
||||
SERVICE_CONFIRMED_READ_PROPERTY, handler_read_property);
|
||||
/* handle the reply (request) coming back */
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM, handler_i_am_add);
|
||||
/* handle any errors coming back */
|
||||
apdu_set_abort_handler(MyAbortHandler);
|
||||
apdu_set_reject_handler(MyRejectHandler);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
BACNET_ADDRESS src = { 0 }; /* address where message came from */
|
||||
uint16_t pdu_len = 0;
|
||||
unsigned timeout = 100; /* milliseconds */
|
||||
time_t total_seconds = 0;
|
||||
time_t elapsed_seconds = 0;
|
||||
time_t last_seconds = 0;
|
||||
time_t current_seconds = 0;
|
||||
time_t timeout_seconds = 0;
|
||||
long port = 0;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s IP [port]\r\n", filename_remove_path(argv[0]));
|
||||
return 0;
|
||||
}
|
||||
if ((argc > 1) && (strcmp(argv[1], "--help") == 0)) {
|
||||
printf(
|
||||
"Send a Read-Foreign-Device-Table message to a BBMD.\r\n"
|
||||
"\r\n"
|
||||
"IP:\r\n"
|
||||
"IP address of the BBMD in dotted decimal notation\r\n"
|
||||
"[port]\r\n"
|
||||
"optional BACnet/IP port number (default=47808=0xBAC0)\r\n"
|
||||
"\r\n"
|
||||
"To send a Read-Foreign-Device-Table message to a BBMD\r\n"
|
||||
"at 192.168.0.1 using port 47808:\r\n"
|
||||
"%s 192.168.0.1 47808\r\n",
|
||||
filename_remove_path(argv[0]));
|
||||
return 0;
|
||||
}
|
||||
/* decode the command line parameters */
|
||||
if (argc > 1) {
|
||||
if (!bip_get_addr_by_name(argv[1], &Target_BBMD_Address)) {
|
||||
fprintf(stderr, "IP=%s - failed to convert address.\r\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (argc > 2) {
|
||||
port = strtol(argv[2], NULL, 0);
|
||||
if ((port > 0) && (port <= 65535)) {
|
||||
Target_BBMD_Address.port = (uint16_t)port;
|
||||
} else {
|
||||
fprintf(
|
||||
stderr, "port=%ld - port must be between 0-65535.\r\n", port);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
Target_BBMD_Address.port = 0xBAC0U;
|
||||
}
|
||||
/* setup my info */
|
||||
Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE);
|
||||
Init_Service_Handlers();
|
||||
address_init();
|
||||
dlenv_init();
|
||||
atexit(datalink_cleanup);
|
||||
/* configure the timeout values */
|
||||
last_seconds = time(NULL);
|
||||
timeout_seconds = apdu_timeout() / 1000;
|
||||
/* send the request */
|
||||
bvlc_bbmd_read_fdt(&Target_BBMD_Address);
|
||||
/* loop forever */
|
||||
for (;;) {
|
||||
/* increment timer - exit if timed out */
|
||||
current_seconds = time(NULL);
|
||||
/* returns 0 bytes on timeout */
|
||||
pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout);
|
||||
/* process */
|
||||
if (pdu_len) {
|
||||
npdu_handler(&src, &Rx_Buf[0], pdu_len);
|
||||
}
|
||||
if (Error_Detected)
|
||||
break;
|
||||
/* increment timer - exit if timed out */
|
||||
elapsed_seconds = current_seconds - last_seconds;
|
||||
if (elapsed_seconds) {
|
||||
datalink_maintenance_timer(elapsed_seconds);
|
||||
}
|
||||
total_seconds += elapsed_seconds;
|
||||
if (total_seconds > timeout_seconds) {
|
||||
break;
|
||||
}
|
||||
/* keep track of time for next check */
|
||||
last_seconds = current_seconds;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -25,7 +25,7 @@ PORT_BIP6_SRC = \
|
||||
PORT_BIP_SRC = \
|
||||
$(BACNET_PORT_DIR)/bip-init.c \
|
||||
$(BACNET_SRC_DIR)/bacnet/datalink/bvlc.c \
|
||||
$(BACNET_SRC_DIR)/bacnet/datalink/bip.c
|
||||
$(BACNET_SRC_DIR)/bacnet/basic/bbmd/h_bbmd.c
|
||||
|
||||
# WARNINGS, DEBUGGING, OPTIMIZATION are defined in common apps Makefile
|
||||
# BACNET_DEFINES is defined in common apps Makefile
|
||||
|
||||
@@ -998,13 +998,12 @@ static void datalink_init(void)
|
||||
{
|
||||
char *pEnv = NULL;
|
||||
BACNET_ADDRESS my_address = { 0 };
|
||||
extern bool BIP_Debug;
|
||||
|
||||
/* BACnet/IP Initialization */
|
||||
BIP_Debug = true;
|
||||
bip_debug_enable();
|
||||
pEnv = getenv("BACNET_IP_PORT");
|
||||
if (pEnv) {
|
||||
bip_set_port(htons((uint16_t)strtol(pEnv, NULL, 0)));
|
||||
bip_set_port((uint16_t)strtol(pEnv, NULL, 0));
|
||||
} else {
|
||||
/* BIP_Port is statically initialized to 0xBAC0,
|
||||
* so if it is different, then it was programmatically altered,
|
||||
@@ -1012,8 +1011,8 @@ static void datalink_init(void)
|
||||
* Unless it is set below 1024, since:
|
||||
* "The range for well-known ports managed by the IANA is 0-1023."
|
||||
*/
|
||||
if (ntohs(bip_get_port()) < 1024) {
|
||||
bip_set_port(htons(0xBAC0));
|
||||
if (bip_get_port() < 1024) {
|
||||
bip_set_port(0xBAC0U);
|
||||
}
|
||||
}
|
||||
if (!bip_init(getenv("BACNET_IFACE"))) {
|
||||
@@ -1169,6 +1168,7 @@ int main(int argc, char *argv[])
|
||||
if (elapsed_seconds) {
|
||||
last_seconds = current_seconds;
|
||||
bvlc_maintenance_timer(elapsed_seconds);
|
||||
bvlc6_maintenance_timer(elapsed_seconds);
|
||||
}
|
||||
if (Exit_Requested) {
|
||||
break;
|
||||
|
||||
+2
-2
@@ -299,7 +299,7 @@ bool read_config(char *filepath)
|
||||
if (result) {
|
||||
current->params.bip_params.port = param;
|
||||
} else {
|
||||
current->params.bip_params.port = 0xBAC0;
|
||||
current->params.bip_params.port = 0xBAC0U;
|
||||
}
|
||||
result =
|
||||
config_setting_lookup_int(port, "network", (int *)¶m);
|
||||
@@ -477,7 +477,7 @@ bool parse_cmd(int argc, char *argv[])
|
||||
}
|
||||
|
||||
/* setup default parameters */
|
||||
current->params.bip_params.port = 0xBAC0; /* 47808 */
|
||||
current->params.bip_params.port = 0xBAC0U; /* 47808 */
|
||||
current->route_info.net = get_next_free_dnet();
|
||||
|
||||
/* check if interface is valid */
|
||||
|
||||
+2
-4
@@ -173,7 +173,7 @@ static void print_help(const char *filename)
|
||||
*
|
||||
* @see Device_Set_Object_Instance_Number, dlenv_init, Send_I_Am,
|
||||
* datalink_receive, npdu_handler,
|
||||
* dcc_timer_seconds, bvlc_maintenance_timer,
|
||||
* dcc_timer_seconds, datalink_maintenance_timer,
|
||||
* Load_Control_State_Machine_Handler, handler_cov_task,
|
||||
* tsm_timer_milliseconds
|
||||
*
|
||||
@@ -275,9 +275,7 @@ int main(int argc, char *argv[])
|
||||
if (elapsed_seconds) {
|
||||
last_seconds = current_seconds;
|
||||
dcc_timer_seconds(elapsed_seconds);
|
||||
#if defined(BACDL_BIP) && BBMD_ENABLED
|
||||
bvlc_maintenance_timer(elapsed_seconds);
|
||||
#endif
|
||||
datalink_maintenance_timer(elapsed_seconds);
|
||||
dlenv_maintenance_timer(elapsed_seconds);
|
||||
Load_Control_State_Machine_Handler();
|
||||
elapsed_milliseconds = elapsed_seconds * 1000;
|
||||
|
||||
+13
-9
@@ -60,6 +60,8 @@ static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||
static int32_t Target_Object_Instance_Min = -1;
|
||||
static int32_t Target_Object_Instance_Max = -1;
|
||||
static bool Error_Detected = false;
|
||||
/* debug info printing */
|
||||
static bool BACnet_Debug_Enabled;
|
||||
|
||||
#define BAC_ADDRESS_MULT 1
|
||||
|
||||
@@ -130,11 +132,11 @@ static void my_i_am_handler(
|
||||
(void)service_len;
|
||||
len = iam_decode_service_request(
|
||||
service_request, &device_id, &max_apdu, &segmentation, &vendor_id);
|
||||
#if PRINT_ENABLED
|
||||
if (BACnet_Debug_Enabled) {
|
||||
fprintf(stderr, "Received I-Am Request");
|
||||
#endif
|
||||
}
|
||||
if (len != -1) {
|
||||
#if PRINT_ENABLED
|
||||
if (BACnet_Debug_Enabled) {
|
||||
fprintf(stderr, " from %lu, MAC = ", (unsigned long)device_id);
|
||||
if ((src->mac_len == 6) && (src->len == 0)) {
|
||||
fprintf(stderr, "%u.%u.%u.%u %02X%02X\n", (unsigned)src->mac[0],
|
||||
@@ -150,12 +152,12 @@ static void my_i_am_handler(
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
address_table_add(device_id, max_apdu, src);
|
||||
} else {
|
||||
#if PRINT_ENABLED
|
||||
if (BACnet_Debug_Enabled) {
|
||||
fprintf(stderr, ", but unable to decode it.\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -342,6 +344,10 @@ int main(int argc, char *argv[])
|
||||
unsigned int target_args = 0;
|
||||
char *filename = NULL;
|
||||
|
||||
/* check for local environment settings */
|
||||
if (getenv("BACNET_DEBUG")) {
|
||||
BACnet_Debug_Enabled = true;
|
||||
}
|
||||
/* decode any command line parameters */
|
||||
filename = filename_remove_path(argv[0]);
|
||||
for (argi = 1; argi < argc; argi++) {
|
||||
@@ -461,9 +467,7 @@ int main(int argc, char *argv[])
|
||||
/* increment timer - exit if timed out */
|
||||
elapsed_seconds = current_seconds - last_seconds;
|
||||
if (elapsed_seconds) {
|
||||
#if defined(BACDL_BIP) && BBMD_ENABLED
|
||||
bvlc_maintenance_timer(elapsed_seconds);
|
||||
#endif
|
||||
datalink_maintenance_timer(elapsed_seconds);
|
||||
}
|
||||
total_seconds += elapsed_seconds;
|
||||
if (total_seconds > timeout_seconds) {
|
||||
|
||||
@@ -296,9 +296,7 @@ int main(int argc, char *argv[])
|
||||
/* increment timer - exit if timed out */
|
||||
elapsed_seconds = current_seconds - last_seconds;
|
||||
if (elapsed_seconds) {
|
||||
#if defined(BACDL_BIP) && BBMD_ENABLED
|
||||
bvlc_maintenance_timer(elapsed_seconds);
|
||||
#endif
|
||||
datalink_maintenance_timer(elapsed_seconds);
|
||||
}
|
||||
total_seconds += elapsed_seconds;
|
||||
if (total_seconds > timeout_seconds) {
|
||||
|
||||
@@ -43,7 +43,15 @@
|
||||
|
||||
/** @file linux/bip-init.c Initializes BACnet/IP interface (Linux). */
|
||||
|
||||
bool BIP_Debug = false;
|
||||
static bool BIP_Debug = false;
|
||||
|
||||
/**
|
||||
* @brief Enabled debug printing of BACnet/IPv4
|
||||
*/
|
||||
void bip_debug_enable(void)
|
||||
{
|
||||
BIP_Debug = true;
|
||||
}
|
||||
|
||||
/* gets an IP address by name, where name can be a
|
||||
string that is an IP address in dotted form, or
|
||||
|
||||
@@ -130,13 +130,13 @@ uint8_t *bip_get_broadcast_addr(void)
|
||||
|
||||
void bip_set_port(uint16_t port)
|
||||
{ /* in network byte order */
|
||||
BIP_Port = port;
|
||||
BIP_Port = htons(port);
|
||||
}
|
||||
|
||||
/* returns network byte order */
|
||||
uint16_t bip_get_port(void)
|
||||
{
|
||||
return BIP_Port;
|
||||
return ntohs(BIP_Port);
|
||||
}
|
||||
|
||||
static int bip_decode_bip_address(BACNET_ADDRESS * bac_addr,
|
||||
|
||||
@@ -36,8 +36,6 @@
|
||||
|
||||
#define BVLL_TYPE_BACNET_IP (0x81)
|
||||
|
||||
extern bool BIP_Debug;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
@@ -80,9 +78,9 @@ extern "C" {
|
||||
|
||||
unsigned timeout); /* milliseconds to wait for a packet */
|
||||
|
||||
/* use network byte order for setting */
|
||||
/* use host byte order for setting */
|
||||
void bip_set_port(uint16_t port);
|
||||
/* returns network byte order */
|
||||
/* returns host byte order */
|
||||
uint16_t bip_get_port(void);
|
||||
|
||||
/* use network byte order for setting */
|
||||
@@ -102,6 +100,7 @@ extern "C" {
|
||||
an IP address in network byte order */
|
||||
long bip_getaddrbyname(const char *host_name);
|
||||
|
||||
void bip_debug_enable(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
|
||||
/*=============== SEEPROM ================*/
|
||||
/* data version - use to check valid version */
|
||||
#define SEEPROM_ID 0xBAC0
|
||||
#define SEEPROM_ID 0xBAC0U
|
||||
#define SEEPROM_VERSION 0x0001
|
||||
|
||||
#define SEEPROM_BYTES_MAX (2*1024)
|
||||
|
||||
+424
-58
@@ -34,16 +34,387 @@
|
||||
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include "bacnet/bacdcode.h"
|
||||
#include "bacnet/datalink/bip.h"
|
||||
#include "bacport.h"
|
||||
#include <ifaddrs.h>
|
||||
#include "bacnet/bacdcode.h"
|
||||
#include "bacnet/bacint.h"
|
||||
#include "bacnet/datalink/bip.h"
|
||||
#include "bacnet/basic/sys/debug.h"
|
||||
#include "bacnet/basic/bbmd/h_bbmd.h"
|
||||
#include "bacport.h"
|
||||
|
||||
/** @file linux/bip-init.c Initializes BACnet/IP interface (BSD/MAC OS X). */
|
||||
/**
|
||||
* @file
|
||||
* @brief Initializes BACnet/IP interface (BSD/MAC OS X).
|
||||
*/
|
||||
|
||||
bool BIP_Debug = true;
|
||||
/* unix socket */
|
||||
static int BIP_Socket = -1;
|
||||
|
||||
void *get_addr_ptr(
|
||||
/* NOTE: we store address and port in network byte order
|
||||
since BACnet/IP uses network byte order for all address byte arrays
|
||||
*/
|
||||
/* port to use - stored here in network byte order */
|
||||
/* Initialize to 0 - this will force initialization in demo apps */
|
||||
static uint16_t BIP_Port;
|
||||
/* IP address - stored here in network byte order */
|
||||
static struct in_addr BIP_Address;
|
||||
/* IP broadcast address - stored here in network byte order */
|
||||
static struct in_addr BIP_Broadcast_Addr;
|
||||
/* enable debugging */
|
||||
static bool BIP_Debug = false;
|
||||
|
||||
/**
|
||||
* @brief Print the IPv4 address with debug info
|
||||
* @param str - debug info string
|
||||
* @param addr - IPv4 address
|
||||
*/
|
||||
static void debug_print_ipv4(const char *str, const struct in_addr *addr,
|
||||
const unsigned int port, const unsigned int count)
|
||||
{
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "BIP: %s %s:%hu (%u bytes)\n", str, inet_ntoa(*addr),
|
||||
ntohs(port), count);
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enabled debug printing of BACnet/IPv4
|
||||
*/
|
||||
void bip_debug_enable(void)
|
||||
{
|
||||
BIP_Debug = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the BACnet IPv4 UDP port number
|
||||
* @param port - IPv4 UDP port number - in host byte order
|
||||
*/
|
||||
void bip_set_port(uint16_t port)
|
||||
{
|
||||
BIP_Port = htons(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the BACnet IPv4 UDP port number
|
||||
* @return IPv4 UDP port number - in host byte order
|
||||
*/
|
||||
uint16_t bip_get_port(void)
|
||||
{
|
||||
return ntohs(BIP_Port);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the IPv4 address for my interface. Used for sending src address.
|
||||
* @param addr - BACnet datalink address
|
||||
*/
|
||||
void bip_get_my_address(BACNET_ADDRESS *addr)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
|
||||
if (addr) {
|
||||
addr->mac_len = 6;
|
||||
memcpy(&addr->mac[0], &BIP_Address.s_addr, 4);
|
||||
memcpy(&addr->mac[4], &BIP_Port, 2);
|
||||
/* local only, no routing */
|
||||
addr->net = 0;
|
||||
/* no SLEN */
|
||||
addr->len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
/* no SADR */
|
||||
addr->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the IPv4 broadcast address for my interface.
|
||||
*
|
||||
* @param addr - BACnet datalink address
|
||||
*/
|
||||
void bip_get_broadcast_address(BACNET_ADDRESS *dest)
|
||||
{
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
dest->mac_len = 6;
|
||||
memcpy(&dest->mac[0], &BIP_Broadcast_Addr.s_addr, 4);
|
||||
memcpy(&dest->mac[4], &BIP_Port, 2);
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* no SLEN */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
/* no SADR */
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the BACnet/IP address
|
||||
*
|
||||
* @param addr - network IPv4 address
|
||||
*/
|
||||
bool bip_set_addr(BACNET_IP_ADDRESS *addr)
|
||||
{
|
||||
/* not something we do within this driver */
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the BACnet/IP address
|
||||
* @param addr - network IPv4 address
|
||||
* @return true if the address was retrieved
|
||||
*/
|
||||
bool bip_get_addr(BACNET_IP_ADDRESS *addr)
|
||||
{
|
||||
if (addr) {
|
||||
memcpy(&addr->address[0], &BIP_Address.s_addr, 4);
|
||||
addr->port = ntohs(BIP_Port);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the BACnet/IP address
|
||||
* @param addr - network IPv4 address
|
||||
* @return true if the address was set
|
||||
*/
|
||||
bool bip_set_broadcast_addr(BACNET_IP_ADDRESS *addr)
|
||||
{
|
||||
/* not something we do within this driver */
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the BACnet/IP address
|
||||
*
|
||||
* @return BACnet/IP address
|
||||
*/
|
||||
bool bip_get_broadcast_addr(BACNET_IP_ADDRESS *addr)
|
||||
{
|
||||
if (addr) {
|
||||
memcpy(&addr->address[0], &BIP_Broadcast_Addr.s_addr, 4);
|
||||
addr->port = ntohs(BIP_Port);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the BACnet/IP subnet mask CIDR prefix
|
||||
* @return true if the subnet mask CIDR prefix is set
|
||||
*/
|
||||
bool bip_set_subnet_prefix(uint8_t prefix)
|
||||
{
|
||||
/* not something we do within this driver */
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the BACnet/IP subnet mask CIDR prefix
|
||||
* @return subnet mask CIDR prefix 1..32
|
||||
*/
|
||||
uint8_t bip_get_subnet_prefix(void)
|
||||
{
|
||||
uint32_t address = 0;
|
||||
uint32_t broadcast = 0;
|
||||
uint32_t test_broadcast = 0;
|
||||
uint32_t mask = 0xFFFFFFFE;
|
||||
uint8_t prefix = 0;
|
||||
|
||||
address = BIP_Address.s_addr;
|
||||
broadcast = BIP_Broadcast_Addr.s_addr;
|
||||
/* calculate the subnet prefix from the broadcast address */
|
||||
for (prefix = 1; prefix <= 32; prefix++) {
|
||||
test_broadcast = (address & mask) | (~mask);
|
||||
if (test_broadcast == broadcast) {
|
||||
break;
|
||||
}
|
||||
mask = mask<<1;
|
||||
}
|
||||
|
||||
return prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* The send function for BACnet/IP driver layer
|
||||
*
|
||||
* @param dest - Points to a BACNET_IP_ADDRESS structure containing the
|
||||
* destination address.
|
||||
* @param mtu - the bytes of data to send
|
||||
* @param mtu_len - the number of bytes of data to send
|
||||
*
|
||||
* @return Upon successful completion, returns the number of bytes sent.
|
||||
* Otherwise, -1 shall be returned and errno set to indicate the error.
|
||||
*/
|
||||
int bip_send_mpdu(BACNET_IP_ADDRESS *dest, uint8_t *mtu, uint16_t mtu_len)
|
||||
{
|
||||
struct sockaddr_in bip_dest = { 0 };
|
||||
|
||||
/* assumes that the driver has already been initialized */
|
||||
if (BIP_Socket < 0) {
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "BIP: driver not initialized!\n");
|
||||
fflush(stderr);
|
||||
}
|
||||
return BIP_Socket;
|
||||
}
|
||||
/* load destination IP address */
|
||||
bip_dest.sin_family = AF_INET;
|
||||
memcpy(&bip_dest.sin_addr.s_addr, &dest->address[0], 4);
|
||||
bip_dest.sin_port = htons(dest->port);
|
||||
/* Send the packet */
|
||||
debug_print_ipv4("Sending MPDU->", &bip_dest.sin_addr, bip_dest.sin_port,
|
||||
mtu_len);
|
||||
return sendto(BIP_Socket, (char *)mtu, mtu_len, 0,
|
||||
(struct sockaddr *)&bip_dest, sizeof(struct sockaddr));
|
||||
}
|
||||
|
||||
/**
|
||||
* BACnet/IP Datalink Receive handler.
|
||||
*
|
||||
* @param src - returns the source address
|
||||
* @param npdu - returns the NPDU buffer
|
||||
* @param max_npdu -maximum size of the NPDU buffer
|
||||
* @param timeout - number of milliseconds to wait for a packet
|
||||
*
|
||||
* @return Number of bytes received, or 0 if none or timeout.
|
||||
*/
|
||||
uint16_t bip_receive(
|
||||
BACNET_ADDRESS *src, uint8_t *npdu, uint16_t max_npdu, unsigned timeout)
|
||||
{
|
||||
uint16_t npdu_len = 0; /* return value */
|
||||
fd_set read_fds;
|
||||
int max = 0;
|
||||
struct timeval select_timeout;
|
||||
struct sockaddr_in sin = { 0 };
|
||||
BACNET_IP_ADDRESS addr = { { 0 } };
|
||||
socklen_t sin_len = sizeof(sin);
|
||||
int received_bytes = 0;
|
||||
int offset = 0;
|
||||
uint16_t i = 0;
|
||||
|
||||
/* Make sure the socket is open */
|
||||
if (BIP_Socket < 0) {
|
||||
return 0;
|
||||
}
|
||||
/* we could just use a non-blocking socket, but that consumes all
|
||||
the CPU time. We can use a timeout; it is only supported as
|
||||
a select. */
|
||||
if (timeout >= 1000) {
|
||||
select_timeout.tv_sec = timeout / 1000;
|
||||
select_timeout.tv_usec =
|
||||
1000 * (timeout - select_timeout.tv_sec * 1000);
|
||||
} else {
|
||||
select_timeout.tv_sec = 0;
|
||||
select_timeout.tv_usec = 1000 * timeout;
|
||||
}
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(BIP_Socket, &read_fds);
|
||||
max = BIP_Socket;
|
||||
/* see if there is a packet for us */
|
||||
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) {
|
||||
received_bytes = recvfrom(BIP_Socket, (char *)&npdu[0], max_npdu, 0,
|
||||
(struct sockaddr *)&sin, &sin_len);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
/* See if there is a problem */
|
||||
if (received_bytes < 0) {
|
||||
return 0;
|
||||
}
|
||||
/* no problem, just no bytes */
|
||||
if (received_bytes == 0) {
|
||||
return 0;
|
||||
}
|
||||
/* the signature of a BACnet/IPv packet */
|
||||
if (npdu[0] != BVLL_TYPE_BACNET_IP) {
|
||||
return 0;
|
||||
}
|
||||
/* Data link layer addressing between B/IPv4 nodes consists of a 32-bit
|
||||
IPv4 address followed by a two-octet UDP port number (both of which
|
||||
shall be transmitted with the most significant octet first). This
|
||||
address shall be referred to as a B/IPv4 address.
|
||||
*/
|
||||
memcpy(&addr.address[0], &sin.sin_addr.s_addr, 4);
|
||||
addr.port = ntohs(sin.sin_port);
|
||||
debug_print_ipv4("Received MPDU->", &sin.sin_addr, sin.sin_port,
|
||||
received_bytes);
|
||||
/* pass the packet into the BBMD handler */
|
||||
offset = bvlc_handler(&addr, src, npdu, received_bytes);
|
||||
if (offset > 0) {
|
||||
npdu_len = received_bytes - offset;
|
||||
debug_print_ipv4("Received NPDU->", &sin.sin_addr, sin.sin_port,
|
||||
npdu_len);
|
||||
if (npdu_len <= max_npdu) {
|
||||
/* shift the buffer to return a valid NPDU */
|
||||
for (i = 0; i < npdu_len; i++) {
|
||||
npdu[i] = npdu[offset + i];
|
||||
}
|
||||
} else {
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "BIP: NPDU dropped!\n");
|
||||
fflush(stderr);
|
||||
}
|
||||
npdu_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return npdu_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* The common send function for BACnet/IP application layer
|
||||
*
|
||||
* @param dest - Points to a #BACNET_ADDRESS structure containing the
|
||||
* destination address.
|
||||
* @param npdu_data - Points to a BACNET_NPDU_DATA structure containing the
|
||||
* destination network layer control flags and data.
|
||||
* @param mtu - the bytes of data to send
|
||||
* @param mtu_len - the number of bytes of data to send
|
||||
* @return Upon successful completion, returns the number of bytes sent.
|
||||
* Otherwise, -1 shall be returned and errno set to indicate the error.
|
||||
*/
|
||||
int bip_send_pdu(BACNET_ADDRESS *dest,
|
||||
BACNET_NPDU_DATA *npdu_data,
|
||||
uint8_t *pdu,
|
||||
unsigned pdu_len)
|
||||
{
|
||||
return bvlc_send_pdu(dest, npdu_data, pdu, pdu_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief gets an IP address by hostname (or string of numbers)
|
||||
*
|
||||
* gets an IP address by name, where name can be a string that is an
|
||||
* IP address in dotted form, or a name that is a domain name
|
||||
*
|
||||
* @param host_name - the host name
|
||||
* @return true if the address was retrieved
|
||||
*/
|
||||
bool bip_get_addr_by_name(const char *host_name, BACNET_IP_ADDRESS *addr)
|
||||
{
|
||||
struct hostent *host_ent;
|
||||
|
||||
if ((host_ent = gethostbyname(host_name)) == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (addr) {
|
||||
/* Host addresses in a struct hostent structure are always
|
||||
given in network byte order */
|
||||
/* h_addr: This is a synonym for h_addr_list[0];
|
||||
in other words, it is the first host address.*/
|
||||
memcpy(&addr->address[0], host_ent->h_addr, 4);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void *get_addr_ptr(
|
||||
struct sockaddr *sockaddr_ptr)
|
||||
{
|
||||
void *addr_ptr;
|
||||
@@ -55,22 +426,6 @@ void *get_addr_ptr(
|
||||
return addr_ptr;
|
||||
}
|
||||
|
||||
/* gets an IP address by name, where name can be a
|
||||
string that is an IP address in dotted form, or
|
||||
a name that is a domain name
|
||||
returns 0 if not found, or
|
||||
an IP address in network byte order */
|
||||
long bip_getaddrbyname(
|
||||
const char *host_name)
|
||||
{
|
||||
struct hostent *host_ent;
|
||||
|
||||
if ((host_ent = gethostbyname(host_name)) == NULL)
|
||||
return 0;
|
||||
|
||||
return *(long *) host_ent->h_addr;
|
||||
}
|
||||
|
||||
/** Gets the local IP address and local broadcast address from the system,
|
||||
* and saves it into the BACnet/IP data structures.
|
||||
*
|
||||
@@ -118,6 +473,24 @@ static int get_local_address(
|
||||
return rv;
|
||||
}
|
||||
|
||||
/** Get the netmask of the BACnet/IP's interface via an getifaddrs() call.
|
||||
* @param netmask [out] The netmask, in host order.
|
||||
* @return 0 on success, else the error from the getifaddrs() call.
|
||||
*/
|
||||
int bip_get_local_netmask(
|
||||
struct in_addr *netmask)
|
||||
{
|
||||
int rv;
|
||||
char *ifname = getenv("BACNET_IFACE"); /* will probably be null */
|
||||
if (ifname == NULL)
|
||||
ifname = "en0";
|
||||
printf("ifname %s", ifname);
|
||||
char *request = "netmask";
|
||||
rv = get_local_address(ifname, netmask, request);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/** Gets the local IP address and local broadcast address from the system,
|
||||
* and saves it into the BACnet/IP data structures.
|
||||
*
|
||||
@@ -137,23 +510,26 @@ void bip_set_interface(
|
||||
if (rv < 0) {
|
||||
local_address.s_addr = 0;
|
||||
}
|
||||
bip_set_addr(local_address.s_addr);
|
||||
BIP_Address.s_addr = local_address.s_addr;
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "Interface: %s\n", ifname);
|
||||
fprintf(stderr, "IP Address: %s\n", inet_ntoa(local_address));
|
||||
fprintf(stderr, "BIP: Interface: %s\n", ifname);
|
||||
fprintf(stderr, "BIP: Address: %s\n", inet_ntoa(local_address));
|
||||
fflush(stderr);
|
||||
}
|
||||
/* setup local broadcast address */
|
||||
request = "broadaddr";
|
||||
rv = get_local_address(ifname, &broadcast_address, request);
|
||||
if (rv < 0) {
|
||||
broadcast_address.s_addr = ~0;
|
||||
BIP_Broadcast_Addr.s_addr = ~0;
|
||||
} else {
|
||||
BIP_Broadcast_Addr.s_addr = broadcast_address.s_addr;
|
||||
}
|
||||
bip_set_broadcast_addr(broadcast_address.s_addr);
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "IP Broadcast Address: %s\n",
|
||||
inet_ntoa(broadcast_address));
|
||||
fprintf(stderr, "UDP Port: 0x%04X [%hu]\n", ntohs(bip_get_port()),
|
||||
ntohs(bip_get_port()));
|
||||
fprintf(stderr, "BIP: Broadcast Address: %s\n",
|
||||
inet_ntoa(BIP_Broadcast_Addr));
|
||||
fprintf(stderr, "BIP: UDP Port: 0x%04X [%hu]\n", ntohs(BIP_Port),
|
||||
ntohs(BIP_Port));
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +566,7 @@ bool bip_init(
|
||||
}
|
||||
/* assumes that the driver has already been initialized */
|
||||
sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
bip_set_socket(sock_fd);
|
||||
BIP_Socket = sock_fd;
|
||||
if (sock_fd < 0)
|
||||
return false;
|
||||
/* Allow us to use the same socket for sending and receiving */
|
||||
@@ -201,7 +577,7 @@ bool bip_init(
|
||||
sizeof(sockopt));
|
||||
if (status < 0) {
|
||||
close(sock_fd);
|
||||
bip_set_socket(-1);
|
||||
BIP_Socket = -1;
|
||||
return status;
|
||||
}
|
||||
/* allow us to send a broadcast */
|
||||
@@ -210,25 +586,34 @@ bool bip_init(
|
||||
sizeof(sockopt));
|
||||
if (status < 0) {
|
||||
close(sock_fd);
|
||||
bip_set_socket(-1);
|
||||
BIP_Socket = -1;
|
||||
return false;
|
||||
}
|
||||
/* bind the socket to the local port number and IP address */
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
sin.sin_port = bip_get_port();
|
||||
sin.sin_port = BIP_Port;
|
||||
memset(&(sin.sin_zero), '\0', sizeof(sin.sin_zero));
|
||||
status =
|
||||
bind(sock_fd, (const struct sockaddr *) &sin, sizeof(struct sockaddr));
|
||||
if (status < 0) {
|
||||
close(sock_fd);
|
||||
bip_set_socket(-1);
|
||||
BIP_Socket = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determine if this BACnet/IP datalink is valid
|
||||
* @return true if the BACnet/IP datalink is valid
|
||||
*/
|
||||
bool bip_valid(void)
|
||||
{
|
||||
return (BIP_Socket != -1);
|
||||
}
|
||||
|
||||
/** Cleanup and close out the BACnet/IP services by closing the socket.
|
||||
* @ingroup DLBIP
|
||||
*/
|
||||
@@ -237,29 +622,10 @@ void bip_cleanup(
|
||||
{
|
||||
int sock_fd = 0;
|
||||
|
||||
if (bip_valid()) {
|
||||
sock_fd = bip_socket();
|
||||
close(sock_fd);
|
||||
if (BIP_Socket != -1) {
|
||||
close(BIP_Socket);
|
||||
}
|
||||
bip_set_socket(-1);
|
||||
BIP_Socket = -1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** Get the netmask of the BACnet/IP's interface via an getifaddrs() call.
|
||||
* @param netmask [out] The netmask, in host order.
|
||||
* @return 0 on success, else the error from the getifaddrs() call.
|
||||
*/
|
||||
int bip_get_local_netmask(
|
||||
struct in_addr *netmask)
|
||||
{
|
||||
int rv;
|
||||
char *ifname = getenv("BACNET_IFACE"); /* will probably be null */
|
||||
if (ifname == NULL)
|
||||
ifname = "en0";
|
||||
printf("ifname %s", ifname);
|
||||
char *request = "netmask";
|
||||
rv = get_local_address(ifname, netmask, request);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include "bacnet/datalink/bip.h"
|
||||
|
||||
long bip_getaddrbyname(
|
||||
long bip_get_addr_by_name(
|
||||
const char *host_name)
|
||||
{
|
||||
return 0;
|
||||
@@ -36,7 +36,7 @@ bool bip_init(char *ifname)
|
||||
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info);
|
||||
|
||||
bip_set_interface(ifname);
|
||||
bip_set_port(htons(0xBAC0));
|
||||
bip_set_port(0xBAC0U);
|
||||
bip_set_addr(ip_info.ip.addr);
|
||||
bip_set_broadcast_addr((ip_info.ip.addr&ip_info.netmask.addr)|(~ip_info.netmask.addr));
|
||||
|
||||
@@ -44,7 +44,7 @@ bool bip_init(char *ifname)
|
||||
struct sockaddr_in saddr = { 0 };
|
||||
|
||||
saddr.sin_family = PF_INET;
|
||||
saddr.sin_port = htons(0xBAC0);
|
||||
saddr.sin_port = htons(0xBAC0U);
|
||||
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in));
|
||||
|
||||
|
||||
@@ -101,12 +101,15 @@
|
||||
#include <netdb.h>
|
||||
#include "bacnet/bacnet_stack_exports.h"
|
||||
|
||||
/** @file linux/net.h Includes Linux network headers. */
|
||||
/** @file linux/bacport.h Includes Linux network headers. */
|
||||
|
||||
/* Local helper functions for this port */
|
||||
BACNET_STACK_EXPORT
|
||||
extern int bip_get_local_netmask(
|
||||
struct in_addr *netmask);
|
||||
|
||||
extern int bip_get_local_address_ioctl(
|
||||
char *ifname,
|
||||
struct in_addr *addr,
|
||||
int request);
|
||||
|
||||
#endif
|
||||
|
||||
+451
-87
@@ -35,33 +35,389 @@
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include "bacnet/bacdcode.h"
|
||||
#include "bacnet/bacint.h"
|
||||
#include "bacnet/datalink/bip.h"
|
||||
#include "bacnet/basic/sys/debug.h"
|
||||
#include "bacnet/basic/bbmd/h_bbmd.h"
|
||||
#include "bacport.h"
|
||||
|
||||
/** @file linux/bip-init.c Initializes BACnet/IP interface (Linux). */
|
||||
|
||||
bool BIP_Debug = false;
|
||||
/* unix socket */
|
||||
static int BIP_Socket = -1;
|
||||
|
||||
/* gets an IP address by name, where name can be a
|
||||
string that is an IP address in dotted form, or
|
||||
a name that is a domain name
|
||||
returns 0 if not found, or
|
||||
an IP address in network byte order */
|
||||
long bip_getaddrbyname(
|
||||
const char *host_name)
|
||||
/* NOTE: we store address and port in network byte order
|
||||
since BACnet/IP uses network byte order for all address byte arrays
|
||||
*/
|
||||
/* port to use - stored here in network byte order */
|
||||
/* Initialize to 0 - this will force initialization in demo apps */
|
||||
static uint16_t BIP_Port;
|
||||
/* IP address - stored here in network byte order */
|
||||
static struct in_addr BIP_Address;
|
||||
/* IP broadcast address - stored here in network byte order */
|
||||
static struct in_addr BIP_Broadcast_Addr;
|
||||
/* enable debugging */
|
||||
static bool BIP_Debug = false;
|
||||
|
||||
/**
|
||||
* @brief Print the IPv4 address with debug info
|
||||
* @param str - debug info string
|
||||
* @param addr - IPv4 address
|
||||
*/
|
||||
static void debug_print_ipv4(const char *str, const struct in_addr *addr,
|
||||
const unsigned int port, const unsigned int count)
|
||||
{
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "BIP: %s %s:%hu (%u bytes)\n", str, inet_ntoa(*addr),
|
||||
ntohs(port), count);
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enabled debug printing of BACnet/IPv4
|
||||
*/
|
||||
void bip_debug_enable(void)
|
||||
{
|
||||
BIP_Debug = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the BACnet IPv4 UDP port number
|
||||
* @param port - IPv4 UDP port number - in host byte order
|
||||
*/
|
||||
void bip_set_port(uint16_t port)
|
||||
{
|
||||
BIP_Port = htons(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the BACnet IPv4 UDP port number
|
||||
* @return IPv4 UDP port number - in host byte order
|
||||
*/
|
||||
uint16_t bip_get_port(void)
|
||||
{
|
||||
return ntohs(BIP_Port);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the IPv4 address for my interface. Used for sending src address.
|
||||
* @param addr - BACnet datalink address
|
||||
*/
|
||||
void bip_get_my_address(BACNET_ADDRESS *addr)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
|
||||
if (addr) {
|
||||
addr->mac_len = 6;
|
||||
memcpy(&addr->mac[0], &BIP_Address.s_addr, 4);
|
||||
memcpy(&addr->mac[4], &BIP_Port, 2);
|
||||
/* local only, no routing */
|
||||
addr->net = 0;
|
||||
/* no SLEN */
|
||||
addr->len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
/* no SADR */
|
||||
addr->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the IPv4 broadcast address for my interface.
|
||||
*
|
||||
* @param addr - BACnet datalink address
|
||||
*/
|
||||
void bip_get_broadcast_address(BACNET_ADDRESS *dest)
|
||||
{
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
dest->mac_len = 6;
|
||||
memcpy(&dest->mac[0], &BIP_Broadcast_Addr.s_addr, 4);
|
||||
memcpy(&dest->mac[4], &BIP_Port, 2);
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* no SLEN */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
/* no SADR */
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the BACnet/IP address
|
||||
*
|
||||
* @param addr - network IPv4 address
|
||||
*/
|
||||
bool bip_set_addr(BACNET_IP_ADDRESS *addr)
|
||||
{
|
||||
/* not something we do within this driver */
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the BACnet/IP address
|
||||
* @param addr - network IPv4 address
|
||||
* @return true if the address was retrieved
|
||||
*/
|
||||
bool bip_get_addr(BACNET_IP_ADDRESS *addr)
|
||||
{
|
||||
if (addr) {
|
||||
memcpy(&addr->address[0], &BIP_Address.s_addr, 4);
|
||||
addr->port = ntohs(BIP_Port);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the BACnet/IP address
|
||||
* @param addr - network IPv4 address
|
||||
* @return true if the address was set
|
||||
*/
|
||||
bool bip_set_broadcast_addr(BACNET_IP_ADDRESS *addr)
|
||||
{
|
||||
/* not something we do within this driver */
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the BACnet/IP address
|
||||
*
|
||||
* @return BACnet/IP address
|
||||
*/
|
||||
bool bip_get_broadcast_addr(BACNET_IP_ADDRESS *addr)
|
||||
{
|
||||
if (addr) {
|
||||
memcpy(&addr->address[0], &BIP_Broadcast_Addr.s_addr, 4);
|
||||
addr->port = ntohs(BIP_Port);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the BACnet/IP subnet mask CIDR prefix
|
||||
* @return true if the subnet mask CIDR prefix is set
|
||||
*/
|
||||
bool bip_set_subnet_prefix(uint8_t prefix)
|
||||
{
|
||||
/* not something we do within this driver */
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the BACnet/IP subnet mask CIDR prefix
|
||||
* @return subnet mask CIDR prefix 1..32
|
||||
*/
|
||||
uint8_t bip_get_subnet_prefix(void)
|
||||
{
|
||||
uint32_t address = 0;
|
||||
uint32_t broadcast = 0;
|
||||
uint32_t test_broadcast = 0;
|
||||
uint32_t mask = 0xFFFFFFFE;
|
||||
uint8_t prefix = 0;
|
||||
|
||||
address = BIP_Address.s_addr;
|
||||
broadcast = BIP_Broadcast_Addr.s_addr;
|
||||
/* calculate the subnet prefix from the broadcast address */
|
||||
for (prefix = 1; prefix <= 32; prefix++) {
|
||||
test_broadcast = (address & mask) | (~mask);
|
||||
if (test_broadcast == broadcast) {
|
||||
break;
|
||||
}
|
||||
mask = mask<<1;
|
||||
}
|
||||
|
||||
return prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* The send function for BACnet/IP driver layer
|
||||
*
|
||||
* @param dest - Points to a BACNET_IP_ADDRESS structure containing the
|
||||
* destination address.
|
||||
* @param mtu - the bytes of data to send
|
||||
* @param mtu_len - the number of bytes of data to send
|
||||
*
|
||||
* @return Upon successful completion, returns the number of bytes sent.
|
||||
* Otherwise, -1 shall be returned and errno set to indicate the error.
|
||||
*/
|
||||
int bip_send_mpdu(BACNET_IP_ADDRESS *dest, uint8_t *mtu, uint16_t mtu_len)
|
||||
{
|
||||
struct sockaddr_in bip_dest = { 0 };
|
||||
|
||||
/* assumes that the driver has already been initialized */
|
||||
if (BIP_Socket < 0) {
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "BIP: driver not initialized!\n");
|
||||
fflush(stderr);
|
||||
}
|
||||
return BIP_Socket;
|
||||
}
|
||||
/* load destination IP address */
|
||||
bip_dest.sin_family = AF_INET;
|
||||
memcpy(&bip_dest.sin_addr.s_addr, &dest->address[0], 4);
|
||||
bip_dest.sin_port = htons(dest->port);
|
||||
/* Send the packet */
|
||||
debug_print_ipv4("Sending MPDU->", &bip_dest.sin_addr, bip_dest.sin_port,
|
||||
mtu_len);
|
||||
return sendto(BIP_Socket, (char *)mtu, mtu_len, 0,
|
||||
(struct sockaddr *)&bip_dest, sizeof(struct sockaddr));
|
||||
}
|
||||
|
||||
/**
|
||||
* BACnet/IP Datalink Receive handler.
|
||||
*
|
||||
* @param src - returns the source address
|
||||
* @param npdu - returns the NPDU buffer
|
||||
* @param max_npdu -maximum size of the NPDU buffer
|
||||
* @param timeout - number of milliseconds to wait for a packet
|
||||
*
|
||||
* @return Number of bytes received, or 0 if none or timeout.
|
||||
*/
|
||||
uint16_t bip_receive(
|
||||
BACNET_ADDRESS *src, uint8_t *npdu, uint16_t max_npdu, unsigned timeout)
|
||||
{
|
||||
uint16_t npdu_len = 0; /* return value */
|
||||
fd_set read_fds;
|
||||
int max = 0;
|
||||
struct timeval select_timeout;
|
||||
struct sockaddr_in sin = { 0 };
|
||||
BACNET_IP_ADDRESS addr = { { 0 } };
|
||||
socklen_t sin_len = sizeof(sin);
|
||||
int received_bytes = 0;
|
||||
int offset = 0;
|
||||
uint16_t i = 0;
|
||||
|
||||
/* Make sure the socket is open */
|
||||
if (BIP_Socket < 0) {
|
||||
return 0;
|
||||
}
|
||||
/* we could just use a non-blocking socket, but that consumes all
|
||||
the CPU time. We can use a timeout; it is only supported as
|
||||
a select. */
|
||||
if (timeout >= 1000) {
|
||||
select_timeout.tv_sec = timeout / 1000;
|
||||
select_timeout.tv_usec =
|
||||
1000 * (timeout - select_timeout.tv_sec * 1000);
|
||||
} else {
|
||||
select_timeout.tv_sec = 0;
|
||||
select_timeout.tv_usec = 1000 * timeout;
|
||||
}
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(BIP_Socket, &read_fds);
|
||||
max = BIP_Socket;
|
||||
/* see if there is a packet for us */
|
||||
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) {
|
||||
received_bytes = recvfrom(BIP_Socket, (char *)&npdu[0], max_npdu, 0,
|
||||
(struct sockaddr *)&sin, &sin_len);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
/* See if there is a problem */
|
||||
if (received_bytes < 0) {
|
||||
return 0;
|
||||
}
|
||||
/* no problem, just no bytes */
|
||||
if (received_bytes == 0) {
|
||||
return 0;
|
||||
}
|
||||
/* the signature of a BACnet/IPv packet */
|
||||
if (npdu[0] != BVLL_TYPE_BACNET_IP) {
|
||||
return 0;
|
||||
}
|
||||
/* Data link layer addressing between B/IPv4 nodes consists of a 32-bit
|
||||
IPv4 address followed by a two-octet UDP port number (both of which
|
||||
shall be transmitted with the most significant octet first). This
|
||||
address shall be referred to as a B/IPv4 address.
|
||||
*/
|
||||
memcpy(&addr.address[0], &sin.sin_addr.s_addr, 4);
|
||||
addr.port = ntohs(sin.sin_port);
|
||||
debug_print_ipv4("Received MPDU->", &sin.sin_addr, sin.sin_port,
|
||||
received_bytes);
|
||||
/* pass the packet into the BBMD handler */
|
||||
offset = bvlc_handler(&addr, src, npdu, received_bytes);
|
||||
if (offset > 0) {
|
||||
npdu_len = received_bytes - offset;
|
||||
debug_print_ipv4("Received NPDU->", &sin.sin_addr, sin.sin_port,
|
||||
npdu_len);
|
||||
if (npdu_len <= max_npdu) {
|
||||
/* shift the buffer to return a valid NPDU */
|
||||
for (i = 0; i < npdu_len; i++) {
|
||||
npdu[i] = npdu[offset + i];
|
||||
}
|
||||
} else {
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "BIP: NPDU dropped!\n");
|
||||
fflush(stderr);
|
||||
}
|
||||
npdu_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return npdu_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* The common send function for BACnet/IP application layer
|
||||
*
|
||||
* @param dest - Points to a #BACNET_ADDRESS structure containing the
|
||||
* destination address.
|
||||
* @param npdu_data - Points to a BACNET_NPDU_DATA structure containing the
|
||||
* destination network layer control flags and data.
|
||||
* @param mtu - the bytes of data to send
|
||||
* @param mtu_len - the number of bytes of data to send
|
||||
* @return Upon successful completion, returns the number of bytes sent.
|
||||
* Otherwise, -1 shall be returned and errno set to indicate the error.
|
||||
*/
|
||||
int bip_send_pdu(BACNET_ADDRESS *dest,
|
||||
BACNET_NPDU_DATA *npdu_data,
|
||||
uint8_t *pdu,
|
||||
unsigned pdu_len)
|
||||
{
|
||||
return bvlc_send_pdu(dest, npdu_data, pdu, pdu_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief gets an IP address by hostname (or string of numbers)
|
||||
*
|
||||
* gets an IP address by name, where name can be a string that is an
|
||||
* IP address in dotted form, or a name that is a domain name
|
||||
*
|
||||
* @param host_name - the host name
|
||||
* @return true if the address was retrieved
|
||||
*/
|
||||
bool bip_get_addr_by_name(const char *host_name, BACNET_IP_ADDRESS *addr)
|
||||
{
|
||||
struct hostent *host_ent;
|
||||
|
||||
if ((host_ent = gethostbyname(host_name)) == NULL)
|
||||
return 0;
|
||||
if ((host_ent = gethostbyname(host_name)) == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return *(long *) host_ent->h_addr;
|
||||
if (addr) {
|
||||
/* Host addresses in a struct hostent structure are always
|
||||
given in network byte order */
|
||||
/* h_addr: This is a synonym for h_addr_list[0];
|
||||
in other words, it is the first host address.*/
|
||||
memcpy(&addr->address[0], host_ent->h_addr, 4);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int get_local_ifr_ioctl(
|
||||
char *ifname,
|
||||
struct ifreq *ifr,
|
||||
int request)
|
||||
/**
|
||||
* @brief Issue a specific request for an interface via an ioctl() call.
|
||||
* @param ifname - the interface name
|
||||
* @param ifr - interface request
|
||||
* @param request - the ioctl() request
|
||||
* @return 0 on success, else the error from the ioctl() call.
|
||||
*/
|
||||
static int get_local_ifr_ioctl(char *ifname, struct ifreq *ifr, int request)
|
||||
{
|
||||
int fd;
|
||||
int rv; /* return value */
|
||||
@@ -78,70 +434,81 @@ static int get_local_ifr_ioctl(
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* forward prototype required for compilers */
|
||||
int get_local_address_ioctl(
|
||||
char *ifname,
|
||||
struct in_addr *addr,
|
||||
int request);
|
||||
|
||||
int get_local_address_ioctl(
|
||||
char *ifname,
|
||||
struct in_addr *addr,
|
||||
int request)
|
||||
/**
|
||||
* @brief Issue a specific request foor an interface via an ioctl() call.
|
||||
* @param ifname - the interface name
|
||||
* @param addr [out] the address in host order.
|
||||
* @param request - the ioctl() request
|
||||
* @return 0 on success, else the error from the ioctl() call.
|
||||
*/
|
||||
int bip_get_local_address_ioctl(char *ifname, struct in_addr *addr, int request)
|
||||
{
|
||||
struct ifreq ifr = { {{0}} };
|
||||
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;
|
||||
tcpip_address = (struct sockaddr_in *)&ifr.ifr_addr;
|
||||
memcpy(addr, &tcpip_address->sin_addr, sizeof(struct in_addr));
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the netmask of the BACnet/IP's interface via an ioctl() call.
|
||||
* @param netmask [out] The netmask, in host order.
|
||||
* @return 0 on success, else the error from the ioctl() call.
|
||||
*/
|
||||
int bip_get_local_netmask(struct in_addr *netmask)
|
||||
{
|
||||
int rv;
|
||||
char *ifname = getenv("BACNET_IFACE"); /* will probably be null */
|
||||
if (ifname == NULL) {
|
||||
ifname = "eth0";
|
||||
}
|
||||
rv = bip_get_local_address_ioctl(ifname, netmask, SIOCGIFNETMASK);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/** Gets the local IP address and local broadcast address from the system,
|
||||
* and saves it into the BACnet/IP data structures.
|
||||
*
|
||||
* @param ifname [in] The named interface to use for the network layer.
|
||||
* Eg, for Linux, ifname is eth0, ath0, arc0, and others.
|
||||
*/
|
||||
void bip_set_interface(
|
||||
char *ifname)
|
||||
void bip_set_interface(char *ifname)
|
||||
{
|
||||
struct in_addr local_address;
|
||||
struct in_addr broadcast_address;
|
||||
struct in_addr netmask;
|
||||
int rv = 0;
|
||||
|
||||
/* setup local address */
|
||||
rv = get_local_address_ioctl(ifname, &local_address, SIOCGIFADDR);
|
||||
rv = bip_get_local_address_ioctl(ifname, &local_address, SIOCGIFADDR);
|
||||
if (rv < 0) {
|
||||
local_address.s_addr = 0;
|
||||
}
|
||||
bip_set_addr(local_address.s_addr);
|
||||
BIP_Address.s_addr = local_address.s_addr;
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "Interface: %s\n", ifname);
|
||||
fprintf(stderr, "IP Address: %s\n", inet_ntoa(local_address));
|
||||
fprintf(stderr, "BIP: Interface: %s\n", ifname);
|
||||
fprintf(stderr, "BIP: Address: %s\n", inet_ntoa(local_address));
|
||||
fflush(stderr);
|
||||
}
|
||||
/* setup local broadcast address */
|
||||
rv = get_local_address_ioctl(ifname, &netmask, SIOCGIFNETMASK);
|
||||
|
||||
rv = bip_get_local_address_ioctl(ifname, &netmask, SIOCGIFNETMASK);
|
||||
if (rv < 0) {
|
||||
broadcast_address.s_addr = ~0;
|
||||
BIP_Broadcast_Addr.s_addr = ~0;
|
||||
} else {
|
||||
BIP_Broadcast_Addr = local_address;
|
||||
BIP_Broadcast_Addr.s_addr |= (~netmask.s_addr);
|
||||
}
|
||||
else {
|
||||
broadcast_address = local_address;
|
||||
broadcast_address.s_addr |= (~netmask.s_addr);
|
||||
}
|
||||
bip_set_broadcast_addr(broadcast_address.s_addr);
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "IP Broadcast Address: %s\n",
|
||||
inet_ntoa(broadcast_address));
|
||||
fprintf(stderr, "UDP Port: 0x%04X [%hu]\n", ntohs(bip_get_port()),
|
||||
ntohs(bip_get_port()));
|
||||
fprintf(stderr, "BIP: Broadcast Address: %s\n",
|
||||
inet_ntoa(BIP_Broadcast_Addr));
|
||||
fprintf(stderr, "BIP: UDP Port: 0x%04X [%hu]\n", ntohs(BIP_Port),
|
||||
ntohs(BIP_Port));
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,87 +529,84 @@ void bip_set_interface(
|
||||
* @return True if the socket is successfully opened for BACnet/IP,
|
||||
* else False if the socket functions fail.
|
||||
*/
|
||||
bool bip_init(
|
||||
char *ifname)
|
||||
bool bip_init(char *ifname)
|
||||
{
|
||||
int status = 0; /* return from socket lib calls */
|
||||
struct sockaddr_in sin;
|
||||
int sockopt = 0;
|
||||
int sock_fd = -1;
|
||||
char *ifname_default = "eth0";
|
||||
|
||||
if (ifname)
|
||||
if (ifname) {
|
||||
bip_set_interface(ifname);
|
||||
else
|
||||
bip_set_interface("eth0");
|
||||
} else {
|
||||
bip_set_interface(ifname_default);
|
||||
}
|
||||
if (BIP_Address.s_addr == 0) {
|
||||
fprintf(stderr, "BIP: Failed to get an IP address from %s!\n",
|
||||
ifname?ifname:ifname_default);
|
||||
fflush(stderr);
|
||||
return false;
|
||||
}
|
||||
/* assumes that the driver has already been initialized */
|
||||
sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
bip_set_socket(sock_fd);
|
||||
if (sock_fd < 0)
|
||||
BIP_Socket = sock_fd;
|
||||
if (sock_fd < 0) {
|
||||
return false;
|
||||
}
|
||||
/* Allow us to use the same socket for sending and receiving */
|
||||
/* This makes sure that the src port is correct when sending */
|
||||
sockopt = 1;
|
||||
status =
|
||||
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &sockopt,
|
||||
sizeof(sockopt));
|
||||
status = setsockopt(
|
||||
sock_fd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt));
|
||||
if (status < 0) {
|
||||
close(sock_fd);
|
||||
bip_set_socket(-1);
|
||||
BIP_Socket = -1;
|
||||
return status;
|
||||
}
|
||||
/* allow us to send a broadcast */
|
||||
status =
|
||||
setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, &sockopt,
|
||||
sizeof(sockopt));
|
||||
status = setsockopt(
|
||||
sock_fd, SOL_SOCKET, SO_BROADCAST, &sockopt, sizeof(sockopt));
|
||||
if (status < 0) {
|
||||
close(sock_fd);
|
||||
bip_set_socket(-1);
|
||||
BIP_Socket = -1;
|
||||
return false;
|
||||
}
|
||||
/* bind the socket to the local port number and IP address */
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
sin.sin_port = bip_get_port();
|
||||
sin.sin_port = BIP_Port;
|
||||
memset(&(sin.sin_zero), '\0', sizeof(sin.sin_zero));
|
||||
status =
|
||||
bind(sock_fd, (const struct sockaddr *) &sin, sizeof(struct sockaddr));
|
||||
bind(sock_fd, (const struct sockaddr *)&sin, sizeof(struct sockaddr));
|
||||
if (status < 0) {
|
||||
close(sock_fd);
|
||||
bip_set_socket(-1);
|
||||
BIP_Socket = -1;
|
||||
return false;
|
||||
}
|
||||
bvlc_init();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determine if this BACnet/IP datalink is valid
|
||||
* @return true if the BACnet/IP datalink is valid
|
||||
*/
|
||||
bool bip_valid(void)
|
||||
{
|
||||
return (BIP_Socket != -1);
|
||||
}
|
||||
|
||||
/** Cleanup and close out the BACnet/IP services by closing the socket.
|
||||
* @ingroup DLBIP
|
||||
*/
|
||||
void bip_cleanup(
|
||||
void)
|
||||
void bip_cleanup(void)
|
||||
{
|
||||
int sock_fd = 0;
|
||||
|
||||
if (bip_valid()) {
|
||||
sock_fd = bip_socket();
|
||||
close(sock_fd);
|
||||
if (BIP_Socket != -1) {
|
||||
close(BIP_Socket);
|
||||
}
|
||||
bip_set_socket(-1);
|
||||
BIP_Socket = -1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** Get the netmask of the BACnet/IP's interface via an ioctl() call.
|
||||
* @param netmask [out] The netmask, in host order.
|
||||
* @return 0 on success, else the error from the ioctl() call.
|
||||
*/
|
||||
int bip_get_local_netmask(
|
||||
struct in_addr *netmask)
|
||||
{
|
||||
int rv;
|
||||
char *ifname = getenv("BACNET_IFACE"); /* will probably be null */
|
||||
if (ifname == NULL)
|
||||
ifname = "eth0";
|
||||
rv = get_local_address_ioctl(ifname, netmask, SIOCGIFNETMASK);
|
||||
return rv;
|
||||
}
|
||||
|
||||
+1
-1
@@ -414,7 +414,7 @@ bool bip6_init(
|
||||
bip6_set_interface("eth0");
|
||||
}
|
||||
if (BIP6_Addr.port == 0) {
|
||||
bip6_set_port(0xBAC0);
|
||||
bip6_set_port(0xBAC0U);
|
||||
}
|
||||
debug_printf("BIP6: IPv6 UDP port: 0x%04X\n", htons(BIP6_Addr.port));
|
||||
if (BIP6_Broadcast_Addr.address[0] == 0) {
|
||||
|
||||
+11
-7
@@ -44,7 +44,7 @@
|
||||
/** @file bip.c Configuration and Operations for BACnet/IP */
|
||||
|
||||
/* port to use - stored in network byte order */
|
||||
static uint16_t BIP_Port = 0xBAC0;
|
||||
static uint16_t BIP_Port = 0xBAC0U;
|
||||
static bool BIP_Port_Changed;
|
||||
/* IP Address - stored in network byte order */
|
||||
static struct in_addr BIP_Address;
|
||||
@@ -102,13 +102,17 @@ uint32_t bip_get_broadcast_addr(
|
||||
return BIP_Broadcast_Address.s_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the BACnet IPv4 UDP port number
|
||||
* @param port - IPv4 UDP port number - in host byte order
|
||||
*/
|
||||
void bip_set_port(
|
||||
uint16_t port)
|
||||
{ /* in network byte order */
|
||||
if (BIP_Port != port) {
|
||||
{
|
||||
if (BIP_Port != htons(port)) {
|
||||
BIP_Port_Changed = true;
|
||||
BIP_Port = port;
|
||||
}
|
||||
BIP_Port = htons(port);
|
||||
}
|
||||
}
|
||||
|
||||
bool bip_port_changed(void)
|
||||
@@ -116,11 +120,11 @@ bool bip_port_changed(void)
|
||||
return BIP_Port_Changed;
|
||||
}
|
||||
|
||||
/* returns network byte order */
|
||||
/* returns host byte order */
|
||||
uint16_t bip_get_port(
|
||||
void)
|
||||
{
|
||||
return BIP_Port;
|
||||
return ntohs(BIP_Port);
|
||||
}
|
||||
|
||||
static void bip_mac_to_addr(
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@
|
||||
|
||||
static int BIP_Socket = -1;
|
||||
/* port to use - stored in host byte order */
|
||||
static uint16_t BIP_Port = 0xBAC0;
|
||||
static uint16_t BIP_Port = 0xBAC0U;
|
||||
/* IP Address - stored in host byte order */
|
||||
static struct in_addr BIP_Address;
|
||||
/* Broadcast Address - stored in host byte order */
|
||||
|
||||
@@ -42,9 +42,15 @@
|
||||
#if (!defined(USE_INADDR) || (USE_INADDR == 0)) && \
|
||||
(!defined(USE_CLASSADDR) || (USE_CLASSADDR == 0))
|
||||
#include <iphlpapi.h>
|
||||
#if defined(_MSC_VER)
|
||||
#pragma comment(lib, "IPHLPAPI.lib")
|
||||
#endif
|
||||
#endif
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#if defined(_MSC_VER)
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#ifdef __MINGW32__
|
||||
@@ -71,10 +77,6 @@ and globals in favor of more secure versions. */
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
#define close closesocket
|
||||
|
||||
typedef int socklen_t;
|
||||
|
||||
#ifdef _WIN32
|
||||
#define strncasecmp(x, y, z) _strnicmp(x, y, z)
|
||||
#endif
|
||||
|
||||
+594
-216
@@ -38,167 +38,64 @@
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include "bacnet/bacdcode.h"
|
||||
#include "bacnet/bacint.h"
|
||||
#include "bacnet/config.h"
|
||||
#include "bacnet/datalink/bip.h"
|
||||
#include "bacnet/basic/sys/debug.h"
|
||||
#include "bacnet/basic/bbmd/h_bbmd.h"
|
||||
#include "bacport.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
#pragma comment(lib, "IPHLPAPI.lib")
|
||||
/* alternate methods of choosing broadcast address */
|
||||
#ifndef USE_INADDR
|
||||
#define USE_INADDR 0
|
||||
#endif
|
||||
#ifndef USE_CLASSADDR
|
||||
#define USE_CLASSADDR 0
|
||||
#endif
|
||||
|
||||
bool BIP_Debug = false;
|
||||
/* Windows socket */
|
||||
static SOCKET BIP_Socket = INVALID_SOCKET;
|
||||
|
||||
/* gets an IP address by name, where name can be a
|
||||
string that is an IP address in dotted form, or
|
||||
a name that is a domain name
|
||||
returns 0 if not found, or
|
||||
an IP address in network byte order */
|
||||
long bip_getaddrbyname(
|
||||
const char *host_name)
|
||||
/* NOTE: we store address and port in network byte order
|
||||
since BACnet/IP uses network byte order for all address byte arrays
|
||||
*/
|
||||
/* port to use - stored here in network byte order */
|
||||
/* Initialize to 0 - this will force initialization in demo apps */
|
||||
static uint16_t BIP_Port;
|
||||
/* IP address - stored here in network byte order */
|
||||
static struct in_addr BIP_Address;
|
||||
/* IP broadcast address - stored here in network byte order */
|
||||
static struct in_addr BIP_Broadcast_Address;
|
||||
|
||||
/* enable debugging */
|
||||
static bool BIP_Debug = false;
|
||||
|
||||
/**
|
||||
* @brief Print the IPv4 address with debug info
|
||||
* @param str - debug info string
|
||||
* @param addr - IPv4 address
|
||||
*/
|
||||
static void debug_print_ipv4(const char *str, const struct in_addr *addr,
|
||||
const unsigned int port, const unsigned int count)
|
||||
{
|
||||
struct hostent *host_ent;
|
||||
|
||||
if ((host_ent = gethostbyname(host_name)) == NULL)
|
||||
return 0;
|
||||
|
||||
return *(long *) host_ent->h_addr;
|
||||
}
|
||||
|
||||
/* To fill a need, we invent the gethostaddr() function. */
|
||||
static long gethostaddr(
|
||||
void)
|
||||
{
|
||||
struct hostent *host_ent;
|
||||
char host_name[255];
|
||||
|
||||
if (gethostname(host_name, sizeof(host_name)) != 0)
|
||||
return -1;
|
||||
|
||||
if ((host_ent = gethostbyname(host_name)) == NULL)
|
||||
return -1;
|
||||
if (BIP_Debug) {
|
||||
printf("host: %s at %u.%u.%u.%u\n", host_name,
|
||||
(unsigned) ((uint8_t *) host_ent->h_addr)[0],
|
||||
(unsigned) ((uint8_t *) host_ent->h_addr)[1],
|
||||
(unsigned) ((uint8_t *) host_ent->h_addr)[2],
|
||||
(unsigned) ((uint8_t *) host_ent->h_addr)[3]);
|
||||
fprintf(stderr, "BIP: %s %s:%hu (%u bytes)\n", str, inet_ntoa(*addr),
|
||||
ntohs(port), count);
|
||||
fflush(stderr);
|
||||
}
|
||||
/* note: network byte order */
|
||||
return *(long *) host_ent->h_addr;
|
||||
}
|
||||
|
||||
#if (!defined(USE_INADDR) || (USE_INADDR == 0)) && \
|
||||
(!defined(USE_CLASSADDR) || (USE_CLASSADDR == 0))
|
||||
/* returns the subnet mask in network byte order */
|
||||
static uint32_t getIpMaskForIpAddress(
|
||||
uint32_t ipAddress)
|
||||
/**
|
||||
* @brief Enabled debug printing of BACnet/IPv4
|
||||
*/
|
||||
void bip_debug_enable(void)
|
||||
{
|
||||
/* Allocate information for up to 16 NICs */
|
||||
IP_ADAPTER_INFO AdapterInfo[16];
|
||||
/* Save memory size of buffer */
|
||||
DWORD dwBufLen = sizeof(AdapterInfo);
|
||||
uint32_t ipMask = INADDR_BROADCAST;
|
||||
bool found = false;
|
||||
|
||||
PIP_ADAPTER_INFO pAdapterInfo;
|
||||
|
||||
/* GetAdapterInfo:
|
||||
[out] buffer to receive data
|
||||
[in] size of receive data buffer */
|
||||
DWORD dwStatus = GetAdaptersInfo(AdapterInfo,
|
||||
&dwBufLen);
|
||||
if (dwStatus == ERROR_SUCCESS) {
|
||||
/* Verify return value is valid, no buffer overflow
|
||||
Contains pointer to current adapter info */
|
||||
pAdapterInfo = AdapterInfo;
|
||||
|
||||
do {
|
||||
IP_ADDR_STRING *pIpAddressInfo = &pAdapterInfo->IpAddressList;
|
||||
do {
|
||||
unsigned long adapterAddress =
|
||||
inet_addr(pIpAddressInfo->IpAddress.String);
|
||||
unsigned long adapterMask =
|
||||
inet_addr(pIpAddressInfo->IpMask.String);
|
||||
if (adapterAddress == ipAddress) {
|
||||
ipMask = adapterMask;
|
||||
found = true;
|
||||
}
|
||||
pIpAddressInfo = pIpAddressInfo->Next;
|
||||
} while (pIpAddressInfo && !found);
|
||||
/* Progress through linked list */
|
||||
pAdapterInfo = pAdapterInfo->Next;
|
||||
/* Terminate on last adapter */
|
||||
} while (pAdapterInfo && !found);
|
||||
}
|
||||
|
||||
return ipMask;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void set_broadcast_address(
|
||||
uint32_t net_address)
|
||||
{
|
||||
#if defined(USE_INADDR) && USE_INADDR
|
||||
/* Note: sometimes INADDR_BROADCAST does not let me get
|
||||
any unicast messages. Not sure why... */
|
||||
net_address = net_address;
|
||||
bip_set_broadcast_addr(INADDR_BROADCAST);
|
||||
#elif defined(USE_CLASSADDR) && USE_CLASSADDR
|
||||
long broadcast_address = 0;
|
||||
|
||||
if (IN_CLASSA(ntohl(net_address)))
|
||||
broadcast_address =
|
||||
(ntohl(net_address) & ~IN_CLASSA_HOST) | IN_CLASSA_HOST;
|
||||
else if (IN_CLASSB(ntohl(net_address)))
|
||||
broadcast_address =
|
||||
(ntohl(net_address) & ~IN_CLASSB_HOST) | IN_CLASSB_HOST;
|
||||
else if (IN_CLASSC(ntohl(net_address)))
|
||||
broadcast_address =
|
||||
(ntohl(net_address) & ~IN_CLASSC_HOST) | IN_CLASSC_HOST;
|
||||
else if (IN_CLASSD(ntohl(net_address)))
|
||||
broadcast_address =
|
||||
(ntohl(net_address) & ~IN_CLASSD_HOST) | IN_CLASSD_HOST;
|
||||
else
|
||||
broadcast_address = INADDR_BROADCAST;
|
||||
bip_set_broadcast_addr(htonl(broadcast_address));
|
||||
#else
|
||||
/* these are network byte order variables */
|
||||
long broadcast_address = 0;
|
||||
long net_mask = 0;
|
||||
|
||||
net_mask = getIpMaskForIpAddress(net_address);
|
||||
if (BIP_Debug) {
|
||||
struct in_addr address;
|
||||
address.s_addr = net_mask;
|
||||
printf("IP Mask: %s\n", inet_ntoa(address));
|
||||
}
|
||||
broadcast_address = (net_address & net_mask) | (~net_mask);
|
||||
bip_set_broadcast_addr(broadcast_address);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* on Windows, ifname is the dotted ip address of the interface */
|
||||
void bip_set_interface(
|
||||
char *ifname)
|
||||
{
|
||||
struct in_addr address;
|
||||
|
||||
/* setup local address */
|
||||
if (bip_get_addr() == 0) {
|
||||
bip_set_addr(inet_addr(ifname));
|
||||
}
|
||||
if (BIP_Debug) {
|
||||
address.s_addr = bip_get_addr();
|
||||
fprintf(stderr, "Interface: %s\n", ifname);
|
||||
}
|
||||
/* setup local broadcast address */
|
||||
if (bip_get_broadcast_addr() == 0) {
|
||||
address.s_addr = bip_get_addr();
|
||||
set_broadcast_address(address.s_addr);
|
||||
}
|
||||
BIP_Debug = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the text string for Windows Error Codes
|
||||
*/
|
||||
static char *winsock_error_code_text(
|
||||
int code)
|
||||
{
|
||||
@@ -316,6 +213,510 @@ static char *winsock_error_code_text(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print the text string for the last Windows Error Code
|
||||
*/
|
||||
static void print_last_error(const char *info)
|
||||
{
|
||||
int Code = WSAGetLastError();
|
||||
fprintf(stderr, "BIP: %s [error code %i] %s\n",
|
||||
info, Code, winsock_error_code_text(Code));
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the Windows Socket Layer
|
||||
*/
|
||||
static void bip_init_windows(void)
|
||||
{
|
||||
static bool initialized = false;
|
||||
int Result;
|
||||
WSADATA wd;
|
||||
|
||||
if (!initialized) {
|
||||
Result = WSAStartup((1 << 8) | 1, &wd);
|
||||
/*Result = WSAStartup(MAKEWORD(2,2), &wd); */
|
||||
if (Result != 0) {
|
||||
print_last_error("TCP/IP stack initialization failed");
|
||||
exit(1);
|
||||
}
|
||||
initialized = true;
|
||||
atexit(bip_cleanup);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the BACnet IPv4 UDP port number
|
||||
* @param port - IPv4 UDP port number - in host byte order
|
||||
*/
|
||||
void bip_set_port(uint16_t port)
|
||||
{
|
||||
BIP_Port = htons(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the BACnet IPv4 UDP port number
|
||||
* @return IPv4 UDP port number - in host byte order
|
||||
*/
|
||||
uint16_t bip_get_port(void)
|
||||
{
|
||||
return ntohs(BIP_Port);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the IPv4 address for my interface. Used for sending src address.
|
||||
* @param addr - BACnet datalink address
|
||||
*/
|
||||
void bip_get_my_address(BACNET_ADDRESS *addr)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
|
||||
if (addr) {
|
||||
addr->mac_len = 6;
|
||||
memcpy(&addr->mac[0], &BIP_Address.s_addr, 4);
|
||||
memcpy(&addr->mac[4], &BIP_Port, 2);
|
||||
/* local only, no routing */
|
||||
addr->net = 0;
|
||||
/* no SLEN */
|
||||
addr->len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
/* no SADR */
|
||||
addr->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the IPv4 broadcast address for my interface.
|
||||
*
|
||||
* @param addr - BACnet datalink address
|
||||
*/
|
||||
void bip_get_broadcast_address(BACNET_ADDRESS *dest)
|
||||
{
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
dest->mac_len = 6;
|
||||
memcpy(&dest->mac[0], &BIP_Broadcast_Address.s_addr, 4);
|
||||
memcpy(&dest->mac[4], &BIP_Port, 2);
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* no SLEN */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
/* no SADR */
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the BACnet/IP address
|
||||
*
|
||||
* @param addr - network IPv4 address
|
||||
*/
|
||||
bool bip_set_addr(BACNET_IP_ADDRESS *addr)
|
||||
{
|
||||
/* not something we do here within this application */
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the BACnet/IP address
|
||||
* @param addr - network IPv4 address
|
||||
* @return true if the address was retrieved
|
||||
*/
|
||||
bool bip_get_addr(BACNET_IP_ADDRESS *addr)
|
||||
{
|
||||
if (addr) {
|
||||
memcpy(&addr->address[0], &BIP_Address.s_addr, 4);
|
||||
addr->port = ntohs(BIP_Port);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the BACnet/IP address
|
||||
* @param addr - network IPv4 address
|
||||
* @return true if the address was set
|
||||
*/
|
||||
bool bip_set_broadcast_addr(BACNET_IP_ADDRESS *addr)
|
||||
{
|
||||
/* not something we do within this application */
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the BACnet/IP address
|
||||
*
|
||||
* @return BACnet/IP address
|
||||
*/
|
||||
bool bip_get_broadcast_addr(BACNET_IP_ADDRESS *addr)
|
||||
{
|
||||
if (addr) {
|
||||
memcpy(&addr->address[0], &BIP_Broadcast_Address.s_addr, 4);
|
||||
addr->port = ntohs(BIP_Port);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the BACnet/IP subnet mask CIDR prefix
|
||||
* @return true if the subnet mask CIDR prefix is set
|
||||
*/
|
||||
bool bip_set_subnet_prefix(uint8_t prefix)
|
||||
{
|
||||
/* not something we do within this application */
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the BACnet/IP subnet mask CIDR prefix
|
||||
* @return subnet mask CIDR prefix
|
||||
*/
|
||||
uint8_t bip_get_subnet_prefix(void)
|
||||
{
|
||||
uint32_t address = 0;
|
||||
uint32_t broadcast = 0;
|
||||
uint32_t test_broadcast = 0;
|
||||
uint32_t mask = 0xFFFFFFFE;
|
||||
uint8_t prefix = 0;
|
||||
|
||||
address = BIP_Broadcast_Address.s_addr;
|
||||
broadcast = BIP_Broadcast_Address.s_addr;
|
||||
/* calculate the subnet prefix from the broadcast address */
|
||||
for (prefix = 1; prefix <= 32; prefix++) {
|
||||
test_broadcast = (address & mask) | (~mask);
|
||||
if (test_broadcast == broadcast) {
|
||||
break;
|
||||
}
|
||||
mask = mask<<1;
|
||||
}
|
||||
|
||||
return prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* The send function for BACnet/IP driver layer
|
||||
*
|
||||
* @param dest - Points to a BACNET_IP_ADDRESS structure containing the
|
||||
* destination address.
|
||||
* @param mtu - the bytes of data to send
|
||||
* @param mtu_len - the number of bytes of data to send
|
||||
*
|
||||
* @return Upon successful completion, returns the number of bytes sent.
|
||||
* Otherwise, -1 shall be returned and errno set to indicate the error.
|
||||
*/
|
||||
int bip_send_mpdu(BACNET_IP_ADDRESS *dest, uint8_t *mtu, uint16_t mtu_len)
|
||||
{
|
||||
struct sockaddr_in bip_dest = { 0 };
|
||||
int rv = 0;
|
||||
|
||||
/* assumes that the driver has already been initialized */
|
||||
if (BIP_Socket == INVALID_SOCKET) {
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "BIP: driver not initialized!\n");
|
||||
fflush(stderr);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/* load destination IP address */
|
||||
bip_dest.sin_family = AF_INET;
|
||||
memcpy(&bip_dest.sin_addr.s_addr, &dest->address[0], 4);
|
||||
bip_dest.sin_port = htons(dest->port);
|
||||
/* Send the packet */
|
||||
debug_print_ipv4("Sending MPDU->", &bip_dest.sin_addr, bip_dest.sin_port,
|
||||
mtu_len);
|
||||
rv = sendto(BIP_Socket, (char *)mtu, mtu_len, 0,
|
||||
(struct sockaddr *)&bip_dest, sizeof(struct sockaddr));
|
||||
if (rv == SOCKET_ERROR) {
|
||||
print_last_error("sendto");
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* BACnet/IP Datalink Receive handler.
|
||||
*
|
||||
* @param src - returns the source address
|
||||
* @param npdu - returns the NPDU buffer
|
||||
* @param max_npdu -maximum size of the NPDU buffer
|
||||
* @param timeout - number of milliseconds to wait for a packet
|
||||
*
|
||||
* @return Number of bytes received, or 0 if none or timeout.
|
||||
*/
|
||||
uint16_t bip_receive(
|
||||
BACNET_ADDRESS *src, uint8_t *npdu, uint16_t max_npdu, unsigned timeout)
|
||||
{
|
||||
uint16_t npdu_len = 0; /* return value */
|
||||
fd_set read_fds;
|
||||
int max = 0;
|
||||
struct timeval select_timeout;
|
||||
struct sockaddr_in sin = { 0 };
|
||||
BACNET_IP_ADDRESS addr = { { 0 } };
|
||||
socklen_t sin_len = sizeof(sin);
|
||||
int received_bytes = 0;
|
||||
int offset = 0;
|
||||
uint16_t i = 0;
|
||||
|
||||
/* Make sure the socket is open */
|
||||
if (BIP_Socket == INVALID_SOCKET) {
|
||||
return 0;
|
||||
}
|
||||
/* we could just use a non-blocking socket, but that consumes all
|
||||
the CPU time. We can use a timeout; it is only supported as
|
||||
a select. */
|
||||
if (timeout >= 1000) {
|
||||
select_timeout.tv_sec = timeout / 1000;
|
||||
select_timeout.tv_usec =
|
||||
1000 * (timeout - select_timeout.tv_sec * 1000);
|
||||
} else {
|
||||
select_timeout.tv_sec = 0;
|
||||
select_timeout.tv_usec = 1000 * timeout;
|
||||
}
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(BIP_Socket, &read_fds);
|
||||
max = BIP_Socket;
|
||||
/* see if there is a packet for us */
|
||||
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) {
|
||||
received_bytes = recvfrom(BIP_Socket, (char *)&npdu[0], max_npdu, 0,
|
||||
(struct sockaddr *)&sin, &sin_len);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
/* See if there is a problem */
|
||||
if (received_bytes < 0) {
|
||||
return 0;
|
||||
}
|
||||
/* no problem, just no bytes */
|
||||
if (received_bytes == 0) {
|
||||
return 0;
|
||||
}
|
||||
/* the signature of a BACnet/IPv packet */
|
||||
if (npdu[0] != BVLL_TYPE_BACNET_IP) {
|
||||
return 0;
|
||||
}
|
||||
/* Data link layer addressing between B/IPv4 nodes consists of a 32-bit
|
||||
IPv4 address followed by a two-octet UDP port number (both of which
|
||||
shall be transmitted with the most significant octet first). This
|
||||
address shall be referred to as a B/IPv4 address.
|
||||
*/
|
||||
memcpy(&addr.address[0], &sin.sin_addr.s_addr, 4);
|
||||
addr.port = ntohs(sin.sin_port);
|
||||
debug_print_ipv4("Received MPDU->", &sin.sin_addr, sin.sin_port,
|
||||
received_bytes);
|
||||
/* pass the packet into the BBMD handler */
|
||||
offset = bvlc_handler(&addr, src, npdu, received_bytes);
|
||||
if (offset > 0) {
|
||||
npdu_len = received_bytes - offset;
|
||||
if (npdu_len <= max_npdu) {
|
||||
/* shift the buffer to return a valid NPDU */
|
||||
for (i = 0; i < npdu_len; i++) {
|
||||
npdu[i] = npdu[offset + i];
|
||||
}
|
||||
} else {
|
||||
npdu_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return npdu_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* The common send function for BACnet/IP application layer
|
||||
*
|
||||
* @param dest - Points to a #BACNET_ADDRESS structure containing the
|
||||
* destination address.
|
||||
* @param npdu_data - Points to a BACNET_NPDU_DATA structure containing the
|
||||
* destination network layer control flags and data.
|
||||
* @param mtu - the bytes of data to send
|
||||
* @param mtu_len - the number of bytes of data to send
|
||||
* @return Upon successful completion, returns the number of bytes sent.
|
||||
* Otherwise, -1 shall be returned and errno set to indicate the error.
|
||||
*/
|
||||
int bip_send_pdu(BACNET_ADDRESS *dest,
|
||||
BACNET_NPDU_DATA *npdu_data,
|
||||
uint8_t *pdu,
|
||||
unsigned pdu_len)
|
||||
{
|
||||
return bvlc_send_pdu(dest, npdu_data, pdu, pdu_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief gets an IP address by hostname (or string of numbers)
|
||||
*
|
||||
* gets an IP address by name, where name can be a string that is an
|
||||
* IP address in dotted form, or a name that is a domain name
|
||||
*
|
||||
* @param host_name - the host name
|
||||
* @return true if the address was retrieved
|
||||
*/
|
||||
bool bip_get_addr_by_name(const char *host_name, BACNET_IP_ADDRESS *addr)
|
||||
{
|
||||
struct hostent *host_ent;
|
||||
|
||||
bip_init_windows();
|
||||
if ((host_ent = gethostbyname(host_name)) == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (addr) {
|
||||
/* Host addresses in a struct hostent structure are always
|
||||
given in network byte order */
|
||||
/* h_addr: This is a synonym for h_addr_list[0];
|
||||
in other words, it is the first host address.*/
|
||||
memcpy(&addr->address[0], host_ent->h_addr, 4);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* To fill a need, we invent the gethostaddr() function. */
|
||||
static long gethostaddr(
|
||||
void)
|
||||
{
|
||||
struct hostent *host_ent;
|
||||
char host_name[255];
|
||||
|
||||
if (gethostname(host_name, sizeof(host_name)) != 0) {
|
||||
print_last_error("gethostname");
|
||||
exit(1);
|
||||
}
|
||||
if ((host_ent = gethostbyname(host_name)) == NULL) {
|
||||
print_last_error("gethostbyname");
|
||||
exit(1);
|
||||
}
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "BIP: host %s at %u.%u.%u.%u\n", host_name,
|
||||
(unsigned) ((uint8_t *) host_ent->h_addr)[0],
|
||||
(unsigned) ((uint8_t *) host_ent->h_addr)[1],
|
||||
(unsigned) ((uint8_t *) host_ent->h_addr)[2],
|
||||
(unsigned) ((uint8_t *) host_ent->h_addr)[3]);
|
||||
fflush(stderr);
|
||||
}
|
||||
/* note: network byte order */
|
||||
return *(long *) host_ent->h_addr;
|
||||
}
|
||||
|
||||
#if ((USE_INADDR == 0) || (USE_CLASSADDR == 0))
|
||||
/* returns the subnet mask in network byte order */
|
||||
static uint32_t getIpMaskForIpAddress(
|
||||
uint32_t ipAddress)
|
||||
{
|
||||
/* Allocate information for up to 16 NICs */
|
||||
IP_ADAPTER_INFO AdapterInfo[16];
|
||||
/* Save memory size of buffer */
|
||||
DWORD dwBufLen = sizeof(AdapterInfo);
|
||||
uint32_t ipMask = INADDR_BROADCAST;
|
||||
bool found = false;
|
||||
|
||||
PIP_ADAPTER_INFO pAdapterInfo;
|
||||
|
||||
/* GetAdapterInfo:
|
||||
[out] buffer to receive data
|
||||
[in] size of receive data buffer */
|
||||
DWORD dwStatus = GetAdaptersInfo(AdapterInfo,
|
||||
&dwBufLen);
|
||||
if (dwStatus == ERROR_SUCCESS) {
|
||||
/* Verify return value is valid, no buffer overflow
|
||||
Contains pointer to current adapter info */
|
||||
pAdapterInfo = AdapterInfo;
|
||||
|
||||
do {
|
||||
IP_ADDR_STRING *pIpAddressInfo = &pAdapterInfo->IpAddressList;
|
||||
do {
|
||||
unsigned long adapterAddress =
|
||||
inet_addr(pIpAddressInfo->IpAddress.String);
|
||||
unsigned long adapterMask =
|
||||
inet_addr(pIpAddressInfo->IpMask.String);
|
||||
if (adapterAddress == ipAddress) {
|
||||
ipMask = adapterMask;
|
||||
found = true;
|
||||
}
|
||||
pIpAddressInfo = pIpAddressInfo->Next;
|
||||
} while (pIpAddressInfo && !found);
|
||||
/* Progress through linked list */
|
||||
pAdapterInfo = pAdapterInfo->Next;
|
||||
/* Terminate on last adapter */
|
||||
} while (pAdapterInfo && !found);
|
||||
}
|
||||
|
||||
return ipMask;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void set_broadcast_address(
|
||||
uint32_t net_address)
|
||||
{
|
||||
#if USE_INADDR
|
||||
/* Note: sometimes INADDR_BROADCAST does not let me get
|
||||
any unicast messages. Not sure why... */
|
||||
(void)net_address;
|
||||
BIP_Broadcast_Address.s_addr = INADDR_BROADCAST;
|
||||
#elif USE_CLASSADDR
|
||||
long broadcast_address = 0;
|
||||
|
||||
if (IN_CLASSA(ntohl(net_address)))
|
||||
broadcast_address =
|
||||
(ntohl(net_address) & ~IN_CLASSA_HOST) | IN_CLASSA_HOST;
|
||||
else if (IN_CLASSB(ntohl(net_address)))
|
||||
broadcast_address =
|
||||
(ntohl(net_address) & ~IN_CLASSB_HOST) | IN_CLASSB_HOST;
|
||||
else if (IN_CLASSC(ntohl(net_address)))
|
||||
broadcast_address =
|
||||
(ntohl(net_address) & ~IN_CLASSC_HOST) | IN_CLASSC_HOST;
|
||||
else if (IN_CLASSD(ntohl(net_address)))
|
||||
broadcast_address =
|
||||
(ntohl(net_address) & ~IN_CLASSD_HOST) | IN_CLASSD_HOST;
|
||||
else
|
||||
broadcast_address = INADDR_BROADCAST;
|
||||
BIP_Broadcast_Address.s_addr = htonl(broadcast_address));
|
||||
#else
|
||||
/* these are network byte order variables */
|
||||
long broadcast_address = 0;
|
||||
long net_mask = 0;
|
||||
|
||||
net_mask = getIpMaskForIpAddress(net_address);
|
||||
if (BIP_Debug) {
|
||||
struct in_addr address;
|
||||
address.s_addr = net_mask;
|
||||
fprintf(stderr, "BIP: net mask: %s\n", inet_ntoa(address));
|
||||
fflush(stderr);
|
||||
}
|
||||
broadcast_address = (net_address & net_mask) | (~net_mask);
|
||||
BIP_Broadcast_Address.s_addr = broadcast_address;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the local IP address and local broadcast address from the
|
||||
* system, and saves it into the BACnet/IP data structures.
|
||||
*
|
||||
* @param ifname [in] The named interface to use for the network layer.
|
||||
* Eg, for Windows, ifname is the dotted ip address of the interface
|
||||
*/
|
||||
void bip_set_interface(
|
||||
char *ifname)
|
||||
{
|
||||
bip_init_windows();
|
||||
/* setup local address */
|
||||
if (BIP_Address.s_addr == 0) {
|
||||
BIP_Address.s_addr = inet_addr(ifname);
|
||||
}
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "BIP: Interface: %s\n", ifname);
|
||||
fprintf(stderr, "BIP: Address: %s\n", inet_ntoa(BIP_Address));
|
||||
fflush(stderr);
|
||||
}
|
||||
/* setup local broadcast address */
|
||||
if (BIP_Broadcast_Address.s_addr == 0) {
|
||||
set_broadcast_address(BIP_Address.s_addr);
|
||||
}
|
||||
}
|
||||
|
||||
/** Initialize the BACnet/IP services at the given interface.
|
||||
* @ingroup DLBIP
|
||||
* -# Gets the local IP address and local broadcast address from the system,
|
||||
@@ -339,56 +740,33 @@ bool bip_init(
|
||||
int rv = 0; /* return from socket lib calls */
|
||||
struct sockaddr_in sin = { -1 };
|
||||
int value = 1;
|
||||
int sock_fd = -1;
|
||||
int Result;
|
||||
int Code;
|
||||
WSADATA wd;
|
||||
struct in_addr address;
|
||||
struct in_addr broadcast_address;
|
||||
SOCKET sock_fd = INVALID_SOCKET;
|
||||
|
||||
Result = WSAStartup((1 << 8) | 1, &wd);
|
||||
/*Result = WSAStartup(MAKEWORD(2,2), &wd); */
|
||||
if (Result != 0) {
|
||||
Code = WSAGetLastError();
|
||||
printf("TCP/IP stack initialization failed\n" " error code: %i %s\n",
|
||||
Code, winsock_error_code_text(Code));
|
||||
exit(1);
|
||||
}
|
||||
atexit(bip_cleanup);
|
||||
|
||||
if (ifname)
|
||||
bip_init_windows();
|
||||
if (ifname) {
|
||||
bip_set_interface(ifname);
|
||||
}
|
||||
/* has address been set? */
|
||||
address.s_addr = bip_get_addr();
|
||||
if (address.s_addr == 0) {
|
||||
address.s_addr = gethostaddr();
|
||||
if (address.s_addr == (unsigned) -1) {
|
||||
Code = WSAGetLastError();
|
||||
printf("Get host address failed\n" " error code: %i %s\n", Code,
|
||||
winsock_error_code_text(Code));
|
||||
exit(1);
|
||||
}
|
||||
bip_set_addr(address.s_addr);
|
||||
}
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "IP Address: %s\n", inet_ntoa(address));
|
||||
if (BIP_Address.s_addr == 0) {
|
||||
BIP_Address.s_addr = gethostaddr();
|
||||
}
|
||||
/* has broadcast address been set? */
|
||||
if (bip_get_broadcast_addr() == 0) {
|
||||
set_broadcast_address(address.s_addr);
|
||||
if (BIP_Broadcast_Address.s_addr == 0) {
|
||||
set_broadcast_address(BIP_Address.s_addr);
|
||||
}
|
||||
if (BIP_Debug) {
|
||||
broadcast_address.s_addr = bip_get_broadcast_addr();
|
||||
fprintf(stderr, "IP Broadcast Address: %s\n",
|
||||
inet_ntoa(broadcast_address));
|
||||
fprintf(stderr, "UDP Port: 0x%04X [%hu]\n", ntohs(bip_get_port()),
|
||||
ntohs(bip_get_port()));
|
||||
fprintf(stderr, "BIP: Address: %s\n", inet_ntoa(BIP_Address));
|
||||
fprintf(stderr, "BIP: Broadcast Address: %s\n",
|
||||
inet_ntoa(BIP_Broadcast_Address));
|
||||
fprintf(stderr, "BIP: UDP Port: 0x%04X [%hu]\n", ntohs(BIP_Port),
|
||||
ntohs(BIP_Port));
|
||||
fflush(stderr);
|
||||
}
|
||||
/* assumes that the driver has already been initialized */
|
||||
sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
bip_set_socket(sock_fd);
|
||||
BIP_Socket = sock_fd;
|
||||
if (sock_fd < 0) {
|
||||
fprintf(stderr, "bip: failed to allocate a socket.\n");
|
||||
print_last_error("failed to allocate a socket");
|
||||
return false;
|
||||
}
|
||||
/* Allow us to use the same socket for sending and receiving */
|
||||
@@ -396,36 +774,23 @@ bool bip_init(
|
||||
rv = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &value,
|
||||
sizeof(value));
|
||||
if (rv < 0) {
|
||||
fprintf(stderr, "bip: failed to set REUSEADDR socket option.\n");
|
||||
close(sock_fd);
|
||||
bip_set_socket(-1);
|
||||
print_last_error("failed to set REUSEADDR socket option");
|
||||
closesocket(sock_fd);
|
||||
BIP_Socket = INVALID_SOCKET;
|
||||
return false;
|
||||
}
|
||||
/* Enables transmission and receipt of broadcast messages on the socket. */
|
||||
rv = setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, (char *) &value,
|
||||
sizeof(value));
|
||||
if (rv < 0) {
|
||||
fprintf(stderr, "bip: failed to set BROADCAST socket option.\n");
|
||||
close(sock_fd);
|
||||
bip_set_socket(-1);
|
||||
print_last_error("failed to set BROADCAST socket option");
|
||||
closesocket(sock_fd);
|
||||
BIP_Socket = INVALID_SOCKET;
|
||||
return false;
|
||||
}
|
||||
#if 0
|
||||
/* probably only for Apple... */
|
||||
/* rebind a port that is already in use.
|
||||
Note: all users of the port must specify this flag */
|
||||
rv = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEPORT, (char *) &value,
|
||||
sizeof(value));
|
||||
if (rv < 0) {
|
||||
fprintf(stderr, "bip: failed to set REUSEPORT socket option.\n");
|
||||
close(sock_fd);
|
||||
bip_set_socket(-1);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
/* bind the socket to the local port number and IP address */
|
||||
sin.sin_family = AF_INET;
|
||||
#if defined(USE_INADDR) && USE_INADDR
|
||||
#if USE_INADDR
|
||||
/* by setting sin.sin_addr.s_addr to INADDR_ANY,
|
||||
I am telling the IP stack to automatically fill
|
||||
in the IP address of the machine the process
|
||||
@@ -442,36 +807,49 @@ bool bip_init(
|
||||
#else
|
||||
/* or we could use the specific adapter address
|
||||
note: already in network byte order */
|
||||
sin.sin_addr.s_addr = address.s_addr;
|
||||
sin.sin_addr.s_addr = BIP_Address.s_addr;
|
||||
#endif
|
||||
sin.sin_port = bip_get_port();
|
||||
sin.sin_port = BIP_Port;
|
||||
memset(&(sin.sin_zero), '\0', sizeof(sin.sin_zero));
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "BIP: bind %s:%hu\n", inet_ntoa(sin.sin_addr),
|
||||
ntohs(sin.sin_port));
|
||||
fflush(stderr);
|
||||
}
|
||||
rv = bind(sock_fd, (const struct sockaddr *) &sin,
|
||||
sizeof(struct sockaddr));
|
||||
if (rv < 0) {
|
||||
fprintf(stderr, "bip: failed to bind to %s port %hu\n",
|
||||
inet_ntoa(sin.sin_addr), ntohs(bip_get_port()));
|
||||
close(sock_fd);
|
||||
bip_set_socket(-1);
|
||||
print_last_error("failed to bind");
|
||||
closesocket(sock_fd);
|
||||
BIP_Socket = INVALID_SOCKET;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determine if this BACnet/IP datalink is valid
|
||||
* @return true if the BACnet/IP datalink is valid
|
||||
*/
|
||||
bool bip_valid(void)
|
||||
{
|
||||
return (BIP_Socket != INVALID_SOCKET);
|
||||
}
|
||||
|
||||
/** Cleanup and close out the BACnet/IP services by closing the socket.
|
||||
* @ingroup DLBIP
|
||||
*/
|
||||
void bip_cleanup(
|
||||
void)
|
||||
{
|
||||
int sock_fd = 0;
|
||||
SOCKET sock_fd = 0;
|
||||
|
||||
if (bip_valid()) {
|
||||
sock_fd = bip_socket();
|
||||
close(sock_fd);
|
||||
if (BIP_Socket != INVALID_SOCKET) {
|
||||
sock_fd = BIP_Socket;
|
||||
closesocket(sock_fd);
|
||||
}
|
||||
bip_set_socket(-1);
|
||||
BIP_Socket = INVALID_SOCKET;
|
||||
WSACleanup();
|
||||
|
||||
return;
|
||||
|
||||
+1
-1
@@ -530,7 +530,7 @@ bool bip6_init(
|
||||
exit(1);
|
||||
}
|
||||
if (BIP6_Addr.port == 0) {
|
||||
bip6_set_port(0xBAC0);
|
||||
bip6_set_port(0xBAC0U);
|
||||
}
|
||||
debug_printf("BIP6: IPv6 UDP port: 0x%04X\n", BIP6_Addr.port);
|
||||
bip6_set_interface(ifname);
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ BACNET_PORT_DIR ?= $(realpath ../ports/$(BACNET_PORT))
|
||||
BACNET_PORT_SRC ?= \
|
||||
$(BACNET_PORT_DIR)/bip-init.c \
|
||||
$(BACNET_SRC_DIR)/bacnet/datalink/bvlc.c \
|
||||
$(BACNET_SRC_DIR)/bacnet/datalink/bip.c
|
||||
$(BACNET_SRC_DIR)/bacnet/basic/bbmd/h_bbmd.c
|
||||
|
||||
# include file search paths
|
||||
BACNET_INCLUDES = -I$(BACNET_SRC_DIR) -I$(BACNET_PORT_DIR)
|
||||
|
||||
@@ -1472,33 +1472,6 @@ typedef enum {
|
||||
/* for definition by ASHRAE. */
|
||||
} BACNET_SERVICES_SUPPORTED;
|
||||
|
||||
typedef enum {
|
||||
BVLC_RESULT = 0,
|
||||
BVLC_WRITE_BROADCAST_DISTRIBUTION_TABLE = 1,
|
||||
BVLC_READ_BROADCAST_DIST_TABLE = 2,
|
||||
BVLC_READ_BROADCAST_DIST_TABLE_ACK = 3,
|
||||
BVLC_FORWARDED_NPDU = 4,
|
||||
BVLC_REGISTER_FOREIGN_DEVICE = 5,
|
||||
BVLC_READ_FOREIGN_DEVICE_TABLE = 6,
|
||||
BVLC_READ_FOREIGN_DEVICE_TABLE_ACK = 7,
|
||||
BVLC_DELETE_FOREIGN_DEVICE_TABLE_ENTRY = 8,
|
||||
BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK = 9,
|
||||
BVLC_ORIGINAL_UNICAST_NPDU = 10,
|
||||
BVLC_ORIGINAL_BROADCAST_NPDU = 11,
|
||||
BVLC_SECURE_BVLL = 12,
|
||||
MAX_BVLC_FUNCTION = 13
|
||||
} BACNET_BVLC_FUNCTION;
|
||||
|
||||
typedef enum {
|
||||
BVLC_RESULT_SUCCESSFUL_COMPLETION = 0x0000,
|
||||
BVLC_RESULT_WRITE_BROADCAST_DISTRIBUTION_TABLE_NAK = 0x0010,
|
||||
BVLC_RESULT_READ_BROADCAST_DISTRIBUTION_TABLE_NAK = 0x0020,
|
||||
BVLC_RESULT_REGISTER_FOREIGN_DEVICE_NAK = 0X0030,
|
||||
BVLC_RESULT_READ_FOREIGN_DEVICE_TABLE_NAK = 0x0040,
|
||||
BVLC_RESULT_DELETE_FOREIGN_DEVICE_TABLE_ENTRY_NAK = 0x0050,
|
||||
BVLC_RESULT_DISTRIBUTE_BROADCAST_TO_NETWORK_NAK = 0x0060
|
||||
} BACNET_BVLC_RESULT;
|
||||
|
||||
/* Bit String Enumerations */
|
||||
typedef enum {
|
||||
STATUS_FLAG_IN_ALARM = 0,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* @file
|
||||
* @author Steve Karg
|
||||
* @date February 2020
|
||||
* @brief Header file for a basic BBMD for BVLC IPv4 handler
|
||||
*
|
||||
* @section LICENSE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef BVLC_HANDLER_H
|
||||
#define BVLC_HANDLER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacnet/bacnet_stack_exports.h"
|
||||
#include "bacnet/bacdef.h"
|
||||
#include "bacnet/datalink/bvlc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* user application function prototypes */
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_handler(BACNET_IP_ADDRESS *addr,
|
||||
BACNET_ADDRESS *src,
|
||||
uint8_t *npdu,
|
||||
uint16_t npdu_len);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_send_pdu(BACNET_ADDRESS *dest,
|
||||
BACNET_NPDU_DATA *npdu_data,
|
||||
uint8_t *pdu,
|
||||
unsigned pdu_len);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint16_t bvlc_get_last_result(void);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint8_t bvlc_get_function_code(void);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_maintenance_timer(uint16_t seconds);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_init(void);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_debug_enable(void);
|
||||
|
||||
/* send a Read BDT request */
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_bbmd_read_bdt(BACNET_IP_ADDRESS *bbmd_addr);
|
||||
/* send a Read FDT request */
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_bbmd_read_fdt(BACNET_IP_ADDRESS *bbmd_addr);
|
||||
|
||||
/* registers with a bbmd as a foreign device */
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_register_with_bbmd(
|
||||
BACNET_IP_ADDRESS *address, uint16_t time_to_live_seconds);
|
||||
|
||||
/* Local interface to manage BBMD.
|
||||
* The interface user needs to handle mutual exclusion if needed i.e.
|
||||
* BACnet packet is not being handled when the BBMD table is modified.
|
||||
*/
|
||||
|
||||
/* Get broadcast distribution table list */
|
||||
BACNET_STACK_EXPORT
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bvlc_bdt_list(void);
|
||||
|
||||
/* Invalidate all entries in the broadcast distribution table */
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_bdt_list_clear(void);
|
||||
|
||||
/* Backup broadcast distribution table to a file.
|
||||
* Filename is the BBMD_BACKUP_FILE constant
|
||||
*/
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_bdt_backup_local(void);
|
||||
|
||||
/* Restore broadcast distribution from a file.
|
||||
* Filename is the BBMD_BACKUP_FILE constant
|
||||
*/
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_bdt_restore_local(void);
|
||||
|
||||
/* Set global IP address of a NAT enabled router which is used in forwarded
|
||||
* messages. Enables NAT handling.
|
||||
*/
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_set_global_address_for_nat(const BACNET_IP_ADDRESS *addr);
|
||||
|
||||
/* Disable NAT handling of BBMD.
|
||||
*/
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_disable_nat(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -0,0 +1,47 @@
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../../../../src
|
||||
TEST_DIR = ../../../../test
|
||||
INCLUDES = -I$(SRC_DIR) -I$(TEST_DIR)
|
||||
DEFINES = -DBIG_ENDIAN=0 -DBACDL_BIP -DBBMD_ENABLED=1 -DTEST -DTEST_BBMD_HANDLER
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = $(SRC_DIR)/bacnet/basic/bbmd/h_bbmd.c \
|
||||
$(SRC_DIR)/bacnet/bacdcode.c \
|
||||
$(SRC_DIR)/bacnet/bacint.c \
|
||||
$(SRC_DIR)/bacnet/bacstr.c \
|
||||
$(SRC_DIR)/bacnet/bacreal.c \
|
||||
$(SRC_DIR)/bacnet/datalink/bvlc.c \
|
||||
$(SRC_DIR)/bacnet/basic/sys/debug.c \
|
||||
$(TEST_DIR)/ctest.c
|
||||
|
||||
TARGET_NAME = bbmd
|
||||
ifeq ($(OS),Windows_NT)
|
||||
TARGET_EXT = .exe
|
||||
else
|
||||
TARGET_EXT =
|
||||
endif
|
||||
TARGET = $(TARGET_NAME)$(TARGET_EXT)
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS) *.bak *.1 *.ini
|
||||
|
||||
test: ${TARGET}
|
||||
./${TARGET}
|
||||
|
||||
include: .depend
|
||||
@@ -70,31 +70,31 @@ static BACNET_IP6_BROADCAST_DISTRIBUTION_TABLE_ENTRY
|
||||
static BACNET_IP6_FOREIGN_DEVICE_TABLE_ENTRY FD_Table[MAX_FD6_ENTRIES];
|
||||
#endif
|
||||
|
||||
#if defined(BACDL_BIP6) && BBMD6_ENABLED
|
||||
/** A timer function that is called about once a second.
|
||||
*
|
||||
* @param seconds - number of elapsed seconds since the last call
|
||||
*/
|
||||
void bbmd6_maintenance_timer(time_t seconds)
|
||||
void bvlc6_maintenance_timer(uint16_t seconds)
|
||||
{
|
||||
#if defined(BACDL_BIP6) && BBMD6_ENABLED
|
||||
unsigned i = 0;
|
||||
|
||||
for (i = 0; i < MAX_FD_ENTRIES; i++) {
|
||||
for (i = 0; i < MAX_FD6_ENTRIES; i++) {
|
||||
if (FD_Table[i].valid) {
|
||||
if (FD_Table[i].seconds_remaining) {
|
||||
if (FD_Table[i].seconds_remaining < seconds) {
|
||||
FD_Table[i].seconds_remaining = 0;
|
||||
if (FD_Table[i].ttl_seconds_remaining) {
|
||||
if (FD_Table[i].ttl_seconds_remaining < seconds) {
|
||||
FD_Table[i].ttl_seconds_remaining = 0;
|
||||
} else {
|
||||
FD_Table[i].seconds_remaining -= seconds;
|
||||
FD_Table[i].ttl_seconds_remaining -= seconds;
|
||||
}
|
||||
if (FD_Table[i].seconds_remaining == 0) {
|
||||
if (FD_Table[i].ttl_seconds_remaining == 0) {
|
||||
FD_Table[i].valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the IPv6 source address from a VMAC address structure
|
||||
@@ -1113,7 +1113,7 @@ static void test_BBMD_Result(Test *pTest)
|
||||
|
||||
bvlc6_address_set(&addr, BIP6_MULTICAST_LINK_LOCAL, 0, 0, 0, 0, 0, 0,
|
||||
BIP6_MULTICAST_GROUP_ID);
|
||||
addr.port = 0xBAC0;
|
||||
addr.port = 0xBAC0U;
|
||||
bvlc6_vmac_address_set(&src, vmac_src);
|
||||
for (i = 0; i < 6; i++) {
|
||||
mtu_len =
|
||||
|
||||
@@ -47,22 +47,31 @@ extern "C" {
|
||||
BACNET_ADDRESS * src,
|
||||
uint8_t * npdu,
|
||||
uint16_t npdu_len);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc6_send_pdu(BACNET_ADDRESS *dest,
|
||||
BACNET_NPDU_DATA *npdu_data,
|
||||
uint8_t *pdu,
|
||||
unsigned pdu_len);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc6_register_with_bbmd(
|
||||
BACNET_IP6_ADDRESS *bbmd_addr,
|
||||
uint32_t vmac_src,
|
||||
uint16_t time_to_live_seconds);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint16_t bvlc6_get_last_result(
|
||||
void);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint8_t bvlc6_get_function_code(
|
||||
void);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc6_maintenance_timer(
|
||||
uint16_t seconds);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc6_init(void);
|
||||
|
||||
|
||||
@@ -270,7 +270,7 @@ bool address_mac_from_ascii(BACNET_MAC_ADDRESS *mac, char *arg)
|
||||
mac->adr[2] = a[2];
|
||||
mac->adr[3] = a[3];
|
||||
if (c == 4) {
|
||||
port = 0xBAC0;
|
||||
port = 0xBAC0U;
|
||||
} else {
|
||||
port = (uint16_t)p;
|
||||
}
|
||||
|
||||
@@ -38,13 +38,11 @@
|
||||
#include "bacnet/basic/object/device.h"
|
||||
#include "bacnet/basic/sys/debug.h"
|
||||
#include "bacnet/basic/services.h"
|
||||
#include "bacnet/datalink/datalink.h"
|
||||
|
||||
#if PRINT_ENABLED
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#if defined(BACDL_BIP)
|
||||
#include "bacnet/datalink/bvlc.h"
|
||||
#endif
|
||||
|
||||
/** @file h_routed_npdu.c Handles messages at the NPDU level of the BACnet
|
||||
* stack, including routing and network control messages. */
|
||||
|
||||
@@ -139,7 +139,7 @@ bool apdu_service_supported(BACNET_SERVICES_SUPPORTED service_supported)
|
||||
/* Check to see if the current Device supports this service.
|
||||
*/
|
||||
int len = Routed_Device_Service_Approval(
|
||||
service_supported, 0, NULL, 0);
|
||||
confirmed_service_supported[i], 0, NULL, 0);
|
||||
if (len > 0)
|
||||
break; /* Not supported - return false */
|
||||
#endif
|
||||
|
||||
@@ -1,385 +0,0 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include "bacnet/bacdcode.h"
|
||||
#include "bacnet/bacint.h"
|
||||
#include "bacnet/datalink/bip.h"
|
||||
#include "bacnet/datalink/bvlc.h"
|
||||
#include "bacport.h" /* custom per port */
|
||||
#if PRINT_ENABLED
|
||||
#include <stdio.h> /* for standard i/o, like printing */
|
||||
#endif
|
||||
|
||||
/** @file bip.c Configuration and Operations for BACnet/IP */
|
||||
|
||||
static int BIP_Socket = -1;
|
||||
/* port to use - stored in network byte order */
|
||||
static uint16_t BIP_Port = 0; /* this will force initialization in demos */
|
||||
/* IP Address - stored in network byte order */
|
||||
static struct in_addr BIP_Address;
|
||||
/* Broadcast Address - stored in network byte order */
|
||||
static struct in_addr BIP_Broadcast_Address;
|
||||
|
||||
/** Setter for the BACnet/IP socket handle.
|
||||
*
|
||||
* @param sock_fd [in] Handle for the BACnet/IP socket.
|
||||
*/
|
||||
void bip_set_socket(int sock_fd)
|
||||
{
|
||||
BIP_Socket = sock_fd;
|
||||
}
|
||||
|
||||
/** Getter for the BACnet/IP socket handle.
|
||||
*
|
||||
* @return The handle to the BACnet/IP socket.
|
||||
*/
|
||||
int bip_socket(void)
|
||||
{
|
||||
return BIP_Socket;
|
||||
}
|
||||
|
||||
bool bip_valid(void)
|
||||
{
|
||||
return (BIP_Socket != -1);
|
||||
}
|
||||
|
||||
void bip_set_addr(uint32_t net_address)
|
||||
{ /* in network byte order */
|
||||
BIP_Address.s_addr = net_address;
|
||||
}
|
||||
|
||||
/* returns network byte order */
|
||||
uint32_t bip_get_addr(void)
|
||||
{
|
||||
return BIP_Address.s_addr;
|
||||
}
|
||||
|
||||
void bip_set_broadcast_addr(uint32_t net_address)
|
||||
{ /* in network byte order */
|
||||
BIP_Broadcast_Address.s_addr = net_address;
|
||||
}
|
||||
|
||||
/* returns network byte order */
|
||||
uint32_t bip_get_broadcast_addr(void)
|
||||
{
|
||||
return BIP_Broadcast_Address.s_addr;
|
||||
}
|
||||
|
||||
void bip_set_port(uint16_t port)
|
||||
{ /* in network byte order */
|
||||
BIP_Port = port;
|
||||
}
|
||||
|
||||
/* returns network byte order */
|
||||
uint16_t bip_get_port(void)
|
||||
{
|
||||
return BIP_Port;
|
||||
}
|
||||
|
||||
static int bip_decode_bip_address(BACNET_ADDRESS *bac_addr,
|
||||
struct in_addr *address, /* in network format */
|
||||
uint16_t *port)
|
||||
{ /* in network format */
|
||||
int len = 0;
|
||||
|
||||
if (bac_addr) {
|
||||
memcpy(&address->s_addr, &bac_addr->mac[0], 4);
|
||||
memcpy(port, &bac_addr->mac[4], 2);
|
||||
len = 6;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/** Function to send a packet out the BACnet/IP socket (Annex J).
|
||||
* @ingroup DLBIP
|
||||
*
|
||||
* @param dest [in] Destination address (may encode an IP address and port #).
|
||||
* @param npdu_data [in] The NPDU header (Network) information (not used).
|
||||
* @param pdu [in] Buffer of data to be sent - may be null (why?).
|
||||
* @param pdu_len [in] Number of bytes in the pdu buffer.
|
||||
* @return Number of bytes sent on success, negative number on failure.
|
||||
*/
|
||||
int bip_send_pdu(BACNET_ADDRESS *dest, /* destination address */
|
||||
BACNET_NPDU_DATA *npdu_data, /* network information */
|
||||
uint8_t *pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
struct sockaddr_in bip_dest = { 0 };
|
||||
uint8_t mtu[MAX_MPDU] = { 0 };
|
||||
int mtu_len = 0;
|
||||
int bytes_sent = 0;
|
||||
/* addr and port in host format */
|
||||
struct in_addr address;
|
||||
uint16_t port = 0;
|
||||
|
||||
(void)npdu_data;
|
||||
/* assumes that the driver has already been initialized */
|
||||
if (BIP_Socket < 0) {
|
||||
return BIP_Socket;
|
||||
}
|
||||
|
||||
mtu[0] = BVLL_TYPE_BACNET_IP;
|
||||
bip_dest.sin_family = AF_INET;
|
||||
if ((dest->net == BACNET_BROADCAST_NETWORK) || (dest->mac_len == 0)) {
|
||||
/* broadcast */
|
||||
address.s_addr = BIP_Broadcast_Address.s_addr;
|
||||
port = BIP_Port;
|
||||
mtu[1] = BVLC_ORIGINAL_BROADCAST_NPDU;
|
||||
} else if ((dest->net > 0) && (dest->len == 0)) {
|
||||
/* network specific broadcast */
|
||||
if (dest->mac_len == 6) {
|
||||
bip_decode_bip_address(dest, &address, &port);
|
||||
} else {
|
||||
address.s_addr = BIP_Broadcast_Address.s_addr;
|
||||
port = BIP_Port;
|
||||
}
|
||||
mtu[1] = BVLC_ORIGINAL_BROADCAST_NPDU;
|
||||
} else if (dest->mac_len == 6) {
|
||||
bip_decode_bip_address(dest, &address, &port);
|
||||
mtu[1] = BVLC_ORIGINAL_UNICAST_NPDU;
|
||||
} else {
|
||||
/* invalid address */
|
||||
return -1;
|
||||
}
|
||||
bip_dest.sin_addr.s_addr = address.s_addr;
|
||||
bip_dest.sin_port = port;
|
||||
mtu_len = 2;
|
||||
mtu_len += encode_unsigned16(
|
||||
&mtu[mtu_len], (uint16_t)(pdu_len + 4 /*inclusive */));
|
||||
memcpy(&mtu[mtu_len], pdu, pdu_len);
|
||||
mtu_len += pdu_len;
|
||||
|
||||
/* Send the packet */
|
||||
bytes_sent = sendto(BIP_Socket, (char *)mtu, mtu_len, 0,
|
||||
(struct sockaddr *)&bip_dest, sizeof(struct sockaddr));
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
/** Implementation of the receive() function for BACnet/IP; receives one
|
||||
* packet, verifies its BVLC header, and removes the BVLC header from
|
||||
* the PDU data before returning.
|
||||
*
|
||||
* @param src [out] Source of the packet - who should receive any response.
|
||||
* @param pdu [out] A buffer to hold the PDU portion of the received packet,
|
||||
* after the BVLC portion has been stripped
|
||||
* off.
|
||||
* @param max_pdu [in] Size of the pdu[] buffer.
|
||||
* @param timeout [in] The number of milliseconds to wait for a packet.
|
||||
* @return The number of octets (remaining) in the PDU, or zero on failure.
|
||||
*/
|
||||
uint16_t bip_receive(BACNET_ADDRESS *src, /* source address */
|
||||
uint8_t *pdu, /* PDU data */
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
unsigned timeout)
|
||||
{
|
||||
int received_bytes = 0;
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
fd_set read_fds;
|
||||
int max = 0;
|
||||
struct timeval select_timeout;
|
||||
struct sockaddr_in sin = { 0 };
|
||||
socklen_t sin_len = sizeof(sin);
|
||||
uint16_t i = 0;
|
||||
int function = 0;
|
||||
|
||||
/* Make sure the socket is open */
|
||||
if (BIP_Socket < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* we could just use a non-blocking socket, but that consumes all
|
||||
the CPU time. We can use a timeout; it is only supported as
|
||||
a select. */
|
||||
if (timeout >= 1000) {
|
||||
select_timeout.tv_sec = timeout / 1000;
|
||||
select_timeout.tv_usec =
|
||||
1000 * (timeout - select_timeout.tv_sec * 1000);
|
||||
} else {
|
||||
select_timeout.tv_sec = 0;
|
||||
select_timeout.tv_usec = 1000 * timeout;
|
||||
}
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(BIP_Socket, &read_fds);
|
||||
max = BIP_Socket;
|
||||
/* see if there is a packet for us */
|
||||
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) {
|
||||
received_bytes = recvfrom(BIP_Socket, (char *)&pdu[0], max_pdu, 0,
|
||||
(struct sockaddr *)&sin, &sin_len);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* See if there is a problem */
|
||||
if (received_bytes < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* no problem, just no bytes */
|
||||
if (received_bytes == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* the signature of a BACnet/IP packet */
|
||||
if (pdu[0] != BVLL_TYPE_BACNET_IP) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bvlc_for_non_bbmd(&sin, pdu, received_bytes) > 0) {
|
||||
/* Handled, usually with a NACK. */
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "BIP: BVLC discarded!\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
function = bvlc_get_function_code(); /* aka, pdu[1] */
|
||||
if ((function == BVLC_ORIGINAL_UNICAST_NPDU) ||
|
||||
(function == BVLC_ORIGINAL_BROADCAST_NPDU)) {
|
||||
/* ignore messages from me */
|
||||
if ((sin.sin_addr.s_addr == BIP_Address.s_addr) &&
|
||||
(sin.sin_port == BIP_Port)) {
|
||||
pdu_len = 0;
|
||||
#if 0
|
||||
fprintf(stderr, "BIP: src is me. Discarded!\n");
|
||||
#endif
|
||||
} else {
|
||||
/* data in src->mac[] is in network format */
|
||||
src->mac_len = 6;
|
||||
memcpy(&src->mac[0], &sin.sin_addr.s_addr, 4);
|
||||
memcpy(&src->mac[4], &sin.sin_port, 2);
|
||||
/* FIXME: check destination address */
|
||||
/* see if it is broadcast or for us */
|
||||
/* decode the length of the PDU - length is inclusive of BVLC */
|
||||
(void)decode_unsigned16(&pdu[2], &pdu_len);
|
||||
/* subtract off the BVLC header */
|
||||
pdu_len -= 4;
|
||||
if (pdu_len < max_pdu) {
|
||||
#if 0
|
||||
fprintf(stderr, "BIP: NPDU[%hu]:", pdu_len);
|
||||
#endif
|
||||
/* shift the buffer to return a valid PDU */
|
||||
for (i = 0; i < pdu_len; i++) {
|
||||
pdu[i] = pdu[4 + i];
|
||||
#if 0
|
||||
fprintf(stderr, "%02X ", pdu[i]);
|
||||
#endif
|
||||
}
|
||||
#if 0
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
}
|
||||
/* ignore packets that are too large */
|
||||
/* clients should check my max-apdu first */
|
||||
else {
|
||||
pdu_len = 0;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "BIP: PDU too large. Discarded!.\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} else if (function == BVLC_FORWARDED_NPDU) {
|
||||
memcpy(&sin.sin_addr.s_addr, &pdu[4], 4);
|
||||
memcpy(&sin.sin_port, &pdu[8], 2);
|
||||
if ((sin.sin_addr.s_addr == BIP_Address.s_addr) &&
|
||||
(sin.sin_port == BIP_Port)) {
|
||||
/* ignore messages from me */
|
||||
pdu_len = 0;
|
||||
} else {
|
||||
/* data in src->mac[] is in network format */
|
||||
src->mac_len = 6;
|
||||
memcpy(&src->mac[0], &sin.sin_addr.s_addr, 4);
|
||||
memcpy(&src->mac[4], &sin.sin_port, 2);
|
||||
/* FIXME: check destination address */
|
||||
/* see if it is broadcast or for us */
|
||||
/* decode the length of the PDU - length is inclusive of BVLC */
|
||||
(void)decode_unsigned16(&pdu[2], &pdu_len);
|
||||
/* subtract off the BVLC header */
|
||||
pdu_len -= 10;
|
||||
if (pdu_len < max_pdu) {
|
||||
/* shift the buffer to return a valid PDU */
|
||||
for (i = 0; i < pdu_len; i++) {
|
||||
pdu[i] = pdu[4 + 6 + i];
|
||||
}
|
||||
} else {
|
||||
/* ignore packets that are too large */
|
||||
/* clients should check my max-apdu first */
|
||||
pdu_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
void bip_get_my_address(BACNET_ADDRESS *my_address)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (my_address) {
|
||||
my_address->mac_len = 6;
|
||||
memcpy(&my_address->mac[0], &BIP_Address.s_addr, 4);
|
||||
memcpy(&my_address->mac[4], &BIP_Port, 2);
|
||||
my_address->net = 0; /* local only, no routing */
|
||||
my_address->len = 0; /* no SLEN */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
/* no SADR */
|
||||
my_address->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void bip_get_broadcast_address(BACNET_ADDRESS *dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
dest->mac_len = 6;
|
||||
memcpy(&dest->mac[0], &BIP_Broadcast_Address.s_addr, 4);
|
||||
memcpy(&dest->mac[4], &BIP_Port, 2);
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* no SLEN */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
/* no SADR */
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
+75
-91
@@ -1,26 +1,26 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*********************************************************************/
|
||||
*
|
||||
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*********************************************************************/
|
||||
#ifndef BIP_H
|
||||
#define BIP_H
|
||||
|
||||
@@ -30,15 +30,13 @@
|
||||
#include "bacnet/bacnet_stack_exports.h"
|
||||
#include "bacnet/bacdef.h"
|
||||
#include "bacnet/npdu.h"
|
||||
#include "bacport.h"
|
||||
#include "bacnet/datalink/bvlc.h"
|
||||
|
||||
/* specific defines for BACnet/IP over Ethernet */
|
||||
#define MAX_HEADER (1 + 1 + 2)
|
||||
#define MAX_MPDU (MAX_HEADER+MAX_PDU)
|
||||
|
||||
#define BVLL_TYPE_BACNET_IP (0x81)
|
||||
|
||||
extern bool BIP_Debug;
|
||||
#define BIP_HEADER_MAX (1 + 1 + 2)
|
||||
#define BIP_MPDU_MAX (BIP_HEADER_MAX + MAX_PDU)
|
||||
/* for legacy demo applications */
|
||||
#define MAX_MPDU BIP_MPDU_MAX
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -48,88 +46,74 @@ extern "C" {
|
||||
/* on Linux, ifname is eth0, ath0, arc0, and others.
|
||||
on Windows, ifname is the dotted ip address of the interface */
|
||||
BACNET_STACK_EXPORT
|
||||
bool bip_init(
|
||||
char *ifname);
|
||||
bool bip_init(char *ifname);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void bip_set_interface(
|
||||
char *ifname);
|
||||
void bip_set_interface(char *ifname);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void bip_cleanup(
|
||||
void);
|
||||
void bip_cleanup(void);
|
||||
|
||||
/* common BACnet/IP functions */
|
||||
BACNET_STACK_EXPORT
|
||||
void bip_set_socket(
|
||||
int sock_fd);
|
||||
BACNET_STACK_EXPORT
|
||||
int bip_socket(
|
||||
void);
|
||||
BACNET_STACK_EXPORT
|
||||
bool bip_valid(
|
||||
void);
|
||||
BACNET_STACK_EXPORT
|
||||
void bip_get_broadcast_address(
|
||||
BACNET_ADDRESS * dest); /* destination address */
|
||||
BACNET_STACK_EXPORT
|
||||
void bip_get_my_address(
|
||||
BACNET_ADDRESS * my_address);
|
||||
bool bip_valid(void);
|
||||
|
||||
/* function to send a packet out the BACnet/IP socket */
|
||||
/* returns zero on success, non-zero on failure */
|
||||
BACNET_STACK_EXPORT
|
||||
int bip_send_pdu(
|
||||
BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len); /* number of bytes of data */
|
||||
void bip_get_broadcast_address(BACNET_ADDRESS *dest);
|
||||
|
||||
/* receives a BACnet/IP packet */
|
||||
/* returns the number of octets in the PDU, or zero on failure */
|
||||
BACNET_STACK_EXPORT
|
||||
uint16_t bip_receive(
|
||||
BACNET_ADDRESS * src, /* source address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
unsigned timeout); /* milliseconds to wait for a packet */
|
||||
void bip_get_my_address(BACNET_ADDRESS *my_address);
|
||||
|
||||
/* use network byte order for setting */
|
||||
BACNET_STACK_EXPORT
|
||||
void bip_set_port(
|
||||
uint16_t port);
|
||||
int bip_send_pdu(BACNET_ADDRESS *dest,
|
||||
BACNET_NPDU_DATA *npdu_data,
|
||||
uint8_t *pdu,
|
||||
unsigned pdu_len);
|
||||
|
||||
/* implement in ports module */
|
||||
BACNET_STACK_EXPORT
|
||||
int bip_send_mpdu(BACNET_IP_ADDRESS *dest, uint8_t *mtu, uint16_t mtu_len);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint16_t bip_receive(BACNET_ADDRESS *src,
|
||||
uint8_t *pdu,
|
||||
uint16_t max_pdu,
|
||||
unsigned timeout);
|
||||
|
||||
/* use host byte order for setting UDP port */
|
||||
BACNET_STACK_EXPORT
|
||||
void bip_set_port(uint16_t port);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bip_port_changed(void);
|
||||
/* returns network byte order */
|
||||
BACNET_STACK_EXPORT
|
||||
uint16_t bip_get_port(
|
||||
void);
|
||||
|
||||
/* use network byte order for setting */
|
||||
/* returns host byte order of UDP port */
|
||||
BACNET_STACK_EXPORT
|
||||
void bip_set_addr(
|
||||
uint32_t net_address);
|
||||
/* returns network byte order */
|
||||
BACNET_STACK_EXPORT
|
||||
uint32_t bip_get_addr(
|
||||
void);
|
||||
uint16_t bip_get_port(void);
|
||||
|
||||
/* use network byte order for setting */
|
||||
BACNET_STACK_EXPORT
|
||||
void bip_set_broadcast_addr(
|
||||
uint32_t net_address);
|
||||
/* returns network byte order */
|
||||
BACNET_STACK_EXPORT
|
||||
uint32_t bip_get_broadcast_addr(
|
||||
void);
|
||||
bool bip_set_addr(BACNET_IP_ADDRESS *addr);
|
||||
|
||||
/* gets an IP address by name, where name can be a
|
||||
string that is an IP address in dotted form, or
|
||||
a name that is a domain name
|
||||
returns 0 if not found, or
|
||||
an IP address in network byte order */
|
||||
BACNET_STACK_EXPORT
|
||||
long bip_getaddrbyname(
|
||||
const char *host_name);
|
||||
bool bip_get_addr(BACNET_IP_ADDRESS *addr);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bip_get_addr_by_name(const char *host_name, BACNET_IP_ADDRESS *addr);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bip_set_broadcast_addr(BACNET_IP_ADDRESS *addr);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bip_get_broadcast_addr(BACNET_IP_ADDRESS *addr);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bip_set_subnet_prefix(uint8_t prefix);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint8_t bip_get_subnet_prefix(void);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void bip_debug_enable(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
+2980
-1618
File diff suppressed because it is too large
Load Diff
+467
-169
@@ -1,203 +1,501 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*********************************************************************/
|
||||
*
|
||||
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*********************************************************************/
|
||||
#ifndef BVLC_H
|
||||
#define BVLC_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <time.h>
|
||||
#include "bacnet/bacnet_stack_exports.h"
|
||||
#include "bacnet/bacdef.h"
|
||||
#include "bacnet/npdu.h"
|
||||
#include "bacnet/datalink/bip.h"
|
||||
|
||||
struct sockaddr_in; /* Defined elsewhere, needed here. */
|
||||
/**
|
||||
* BVLL for BACnet/IPv4
|
||||
* @{
|
||||
*/
|
||||
#define BVLL_TYPE_BACNET_IP (0x81)
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
/**
|
||||
* B/IPv4 BVLL Messages
|
||||
* @{
|
||||
*/
|
||||
#define BVLC_RESULT 0
|
||||
#define BVLC_WRITE_BROADCAST_DISTRIBUTION_TABLE 1
|
||||
#define BVLC_READ_BROADCAST_DIST_TABLE 2
|
||||
#define BVLC_READ_BROADCAST_DIST_TABLE_ACK 3
|
||||
#define BVLC_FORWARDED_NPDU 4
|
||||
#define BVLC_REGISTER_FOREIGN_DEVICE 5
|
||||
#define BVLC_READ_FOREIGN_DEVICE_TABLE 6
|
||||
#define BVLC_READ_FOREIGN_DEVICE_TABLE_ACK 7
|
||||
#define BVLC_DELETE_FOREIGN_DEVICE_TABLE_ENTRY 8
|
||||
#define BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK 9
|
||||
#define BVLC_ORIGINAL_UNICAST_NPDU 10
|
||||
#define BVLC_ORIGINAL_BROADCAST_NPDU 11
|
||||
#define BVLC_SECURE_BVLL 12
|
||||
|
||||
#endif /* __cplusplus */
|
||||
/** @} */
|
||||
|
||||
#if defined(BBMD_ENABLED) && BBMD_ENABLED
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_maintenance_timer(
|
||||
time_t seconds);
|
||||
#else
|
||||
#define bvlc_maintenance_timer(x)
|
||||
#endif
|
||||
/**
|
||||
* BVLC Result Code
|
||||
* @{
|
||||
*/
|
||||
#define BVLC_RESULT_SUCCESSFUL_COMPLETION 0x0000
|
||||
#define BVLC_RESULT_WRITE_BROADCAST_DISTRIBUTION_TABLE_NAK 0x0010
|
||||
#define BVLC_RESULT_READ_BROADCAST_DISTRIBUTION_TABLE_NAK 0x0020
|
||||
#define BVLC_RESULT_REGISTER_FOREIGN_DEVICE_NAK 0X0030
|
||||
#define BVLC_RESULT_READ_FOREIGN_DEVICE_TABLE_NAK 0x0040
|
||||
#define BVLC_RESULT_DELETE_FOREIGN_DEVICE_TABLE_ENTRY_NAK 0x0050
|
||||
#define BVLC_RESULT_DISTRIBUTE_BROADCAST_TO_NETWORK_NAK 0x0060
|
||||
|
||||
typedef struct {
|
||||
/* number of bytes in the IPv4 address */
|
||||
#define IP_ADDRESS_MAX 4
|
||||
|
||||
/**
|
||||
* BACnet IPv4 Address
|
||||
*
|
||||
* Data link layer addressing between B/IPv4 nodes consists of a 32-bit
|
||||
* IPv4 address followed by a two-octet UDP port number (both of which
|
||||
* shall be transmitted with the most significant octet first).
|
||||
* This address shall be referred to as a B/IPv4 address.
|
||||
* @{
|
||||
*/
|
||||
typedef struct BACnet_IP_Address {
|
||||
uint8_t address[IP_ADDRESS_MAX];
|
||||
uint16_t port;
|
||||
} BACNET_IP_ADDRESS;
|
||||
/* number of bytes in the B/IPv4 address */
|
||||
#define BIP_ADDRESS_MAX 6
|
||||
|
||||
/**
|
||||
* BACnet IPv4 Broadcast Distribution Mask
|
||||
*
|
||||
* The Broadcast Distribution Mask is a 4-octet field that
|
||||
* indicates how broadcast messages are to be distributed on
|
||||
* the IP subnet served by the BBMD.
|
||||
* @{
|
||||
*/
|
||||
typedef struct BACnet_IP_Broadcast_Distribution_Mask {
|
||||
uint8_t address[IP_ADDRESS_MAX];
|
||||
} BACNET_IP_BROADCAST_DISTRIBUTION_MASK;
|
||||
/* number of bytes in the B/IPv4 Broadcast Distribution Mask */
|
||||
#define BACNET_IP_BDT_MASK_SIZE IP_ADDRESS_MAX
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* BACnet/IP Broadcast Distribution Table (BDT)
|
||||
*
|
||||
* The BDT consists of one entry for the address of the BBMD
|
||||
* for the local IP subnet and an entry for the BBMD on each
|
||||
* remote IP subnet to which broadcasts are to be forwarded.
|
||||
* Each entry consists of the 6-octet B/IP address with which
|
||||
* the BBMD is accessed and a 4-octet broadcast distribution mask.
|
||||
* @{
|
||||
*/
|
||||
struct BACnet_IP_Broadcast_Distribution_Table_Entry;
|
||||
typedef struct BACnet_IP_Broadcast_Distribution_Table_Entry {
|
||||
/* true if valid entry - false if not */
|
||||
bool valid;
|
||||
/* BACnet/IP address */
|
||||
struct in_addr dest_address; /* in network format */
|
||||
/* BACnet/IP port number - not always 47808=BAC0h */
|
||||
uint16_t dest_port; /* in network format */
|
||||
BACNET_IP_ADDRESS dest_address;
|
||||
/* Broadcast Distribution Mask */
|
||||
struct in_addr broadcast_mask; /* in tework format */
|
||||
} BBMD_TABLE_ENTRY;
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_MASK broadcast_mask;
|
||||
struct BACnet_IP_Broadcast_Distribution_Table_Entry *next;
|
||||
} BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY;
|
||||
/* number of bytes in a B/IPv4 roadcast Distribution Table entry */
|
||||
#define BACNET_IP_BDT_ENTRY_SIZE (BIP_ADDRESS_MAX + BACNET_IP_BDT_MASK_SIZE)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* Foreign Device Table (FDT)
|
||||
*
|
||||
* Each device that registers as a foreign device shall be placed
|
||||
* in an entry in the BBMD's Foreign Device Table (FDT). Each
|
||||
* entry shall consist of the 6-octet B/IP address of the registrant;
|
||||
* the 2-octet Time-to-Live value supplied at the time of
|
||||
* registration; and a 2-octet value representing the number of
|
||||
* seconds remaining before the BBMD will purge the registrant's FDT
|
||||
* entry if no re-registration occurs. This value will be initialized
|
||||
* to the 2-octet Time-to-Live value supplied at the time of
|
||||
* registration.
|
||||
* @{
|
||||
*/
|
||||
struct BACnet_IP_Foreign_Device_Table_Entry;
|
||||
typedef struct BACnet_IP_Foreign_Device_Table_Entry {
|
||||
bool valid;
|
||||
/* BACnet/IP address */
|
||||
BACNET_IP_ADDRESS dest_address;
|
||||
/* requested time-to-live value */
|
||||
uint16_t ttl_seconds;
|
||||
/* our counter - includes 30 second grace period */
|
||||
uint16_t ttl_seconds_remaining;
|
||||
struct BACnet_IP_Foreign_Device_Table_Entry *next;
|
||||
} BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY;
|
||||
#define BACNET_IP_FDT_ENTRY_SIZE 10
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint16_t bvlc_receive(
|
||||
BACNET_ADDRESS * src, /* returns the source address */
|
||||
uint8_t * npdu, /* returns the NPDU */
|
||||
uint16_t max_npdu, /* amount of space available in the NPDU */
|
||||
unsigned timeout); /* number of milliseconds to wait for a packet */
|
||||
int bvlc_encode_address(
|
||||
uint8_t *pdu, uint16_t pdu_size, const BACNET_IP_ADDRESS *ip_address);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_send_pdu(
|
||||
BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len);
|
||||
int bvlc_decode_address(
|
||||
uint8_t *pdu, uint16_t pdu_len, BACNET_IP_ADDRESS *ip_address);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_send_mpdu(
|
||||
struct sockaddr_in *dest,
|
||||
uint8_t * mtu,
|
||||
uint16_t mtu_len);
|
||||
bool bvlc_address_copy(BACNET_IP_ADDRESS *dst, const BACNET_IP_ADDRESS *src);
|
||||
|
||||
#if defined(BBMD_CLIENT_ENABLED) && BBMD_CLIENT_ENABLED
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_write_bdt_init(
|
||||
uint8_t * pdu,
|
||||
unsigned entries);
|
||||
bool bvlc_address_different(
|
||||
const BACNET_IP_ADDRESS *dst, const BACNET_IP_ADDRESS *src);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_read_fdt(
|
||||
uint8_t * pdu);
|
||||
bool bvlc_address_from_ascii(BACNET_IP_ADDRESS *dst, const char *addrstr);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_delete_fdt_entry(
|
||||
uint8_t * pdu,
|
||||
uint32_t address, /* in network byte order */
|
||||
uint16_t port); /* in network byte order */
|
||||
bool bvlc_address_port_from_ascii(
|
||||
BACNET_IP_ADDRESS *dst, const char *addrstr, const char *portstr);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_original_unicast_npdu(
|
||||
uint8_t * pdu,
|
||||
uint8_t * npdu,
|
||||
unsigned npdu_length);
|
||||
void bvlc_address_from_network(BACNET_IP_ADDRESS *dst, uint32_t addr);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_original_broadcast_npdu(
|
||||
uint8_t * pdu,
|
||||
uint8_t * npdu,
|
||||
unsigned npdu_length);
|
||||
bool bvlc_address_set(BACNET_IP_ADDRESS *addr,
|
||||
uint8_t addr0,
|
||||
uint8_t addr1,
|
||||
uint8_t addr2,
|
||||
uint8_t addr3);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_address_get(BACNET_IP_ADDRESS *addr,
|
||||
uint8_t *addr0,
|
||||
uint8_t *addr1,
|
||||
uint8_t *addr2,
|
||||
uint8_t *addr3);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_ip_address_to_bacnet_local(
|
||||
BACNET_ADDRESS *addr, BACNET_IP_ADDRESS *ipaddr);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_ip_address_from_bacnet_local(
|
||||
BACNET_IP_ADDRESS *ipaddr, BACNET_ADDRESS *addr);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_ip_address_to_bacnet_remote(
|
||||
BACNET_ADDRESS *addr, uint16_t dnet, BACNET_IP_ADDRESS *ipaddr);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_ip_address_from_bacnet_remote(
|
||||
BACNET_IP_ADDRESS *ipaddr, uint16_t *dnet, BACNET_ADDRESS *addr);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_broadcast_distribution_mask(uint8_t *pdu,
|
||||
uint16_t pdu_size,
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_MASK *bd_mask);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_decode_broadcast_distribution_mask(uint8_t *pdu,
|
||||
uint16_t pdu_len,
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_MASK *bd_mask);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_broadcast_distribution_table_entry(uint8_t *pdu,
|
||||
uint16_t pdu_size,
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_entry);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_decode_broadcast_distribution_table_entry(uint8_t *pdu,
|
||||
uint16_t pdu_len,
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_entry);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_broadcast_distribution_table_link_array(
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_list,
|
||||
const size_t bdt_array_size);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint16_t bvlc_broadcast_distribution_table_count(
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_list);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint16_t bvlc_broadcast_distribution_table_valid_count(
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_list);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_broadcast_distribution_table_valid_clear(
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_list);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_broadcast_distribution_table_entry_different(
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *dst,
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *src);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_broadcast_distribution_table_entry_copy(
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *dst,
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *src);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_broadcast_distribution_mask_different(
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_MASK *dst,
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_MASK *src);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_broadcast_distribution_mask_copy(
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_MASK *dst,
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_MASK *src);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_broadcast_distribution_table_entry_append(
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_list,
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_entry);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_broadcast_distribution_table_entry_set(
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_entry,
|
||||
BACNET_IP_ADDRESS *addr,
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_MASK *mask);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_broadcast_distribution_table_entry_forward_address(
|
||||
BACNET_IP_ADDRESS *addr,
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_entry);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_address_mask(
|
||||
BACNET_IP_ADDRESS *dst, const BACNET_IP_ADDRESS *src,
|
||||
const BACNET_IP_BROADCAST_DISTRIBUTION_MASK *mask);
|
||||
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_broadcast_distribution_mask_from_host(
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_MASK *mask, uint32_t broadcast_mask);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_broadcast_distribution_mask_to_host(
|
||||
uint32_t *broadcast_mask, BACNET_IP_BROADCAST_DISTRIBUTION_MASK *mask);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_broadcast_distribution_mask_set(
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_MASK *mask,
|
||||
uint8_t addr0,
|
||||
uint8_t addr1,
|
||||
uint8_t addr2,
|
||||
uint8_t addr3);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_broadcast_distribution_mask_get(
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_MASK *mask,
|
||||
uint8_t *addr0,
|
||||
uint8_t *addr1,
|
||||
uint8_t *addr2,
|
||||
uint8_t *addr3);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_write_broadcast_distribution_table(uint8_t *pdu,
|
||||
uint16_t pdu_size,
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_list);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_decode_write_broadcast_distribution_table(uint8_t *pdu,
|
||||
uint16_t pdu_len,
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_list);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_read_broadcast_distribution_table(
|
||||
uint8_t *pdu, uint16_t pdu_size);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_read_broadcast_distribution_table_ack(uint8_t *pdu,
|
||||
uint16_t pdu_size,
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_list);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_decode_read_broadcast_distribution_table_ack(uint8_t *pdu,
|
||||
uint16_t pdu_len,
|
||||
BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_list);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_header(
|
||||
uint8_t *pdu, uint16_t pdu_size, uint8_t message_type, uint16_t length);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_decode_header(
|
||||
uint8_t *pdu, uint16_t pdu_len, uint8_t *message_type, uint16_t *length);
|
||||
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_foreign_device_table_maintenance_timer(
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_list, uint16_t seconds);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint16_t bvlc_foreign_device_table_valid_count(
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_list);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint16_t bvlc_foreign_device_table_count(
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_list);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_foreign_device_table_link_array(
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_list, const size_t array_size);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_foreign_device_table_entry_different(
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *dst,
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *src);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_foreign_device_table_entry_copy(
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *dst,
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *src);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_foreign_device_table_entry_delete(
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_list,
|
||||
BACNET_IP_ADDRESS *ip_address);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_foreign_device_table_entry_add(
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_list,
|
||||
BACNET_IP_ADDRESS *ip_address,
|
||||
uint16_t ttl_seconds);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_foreign_device_table_entry(uint8_t *pdu,
|
||||
uint16_t pdu_size,
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_entry);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_decode_foreign_device_table_entry(uint8_t *pdu,
|
||||
uint16_t pdu_len,
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_entry);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_read_foreign_device_table(uint8_t *pdu, uint16_t pdu_size);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_read_foreign_device_table_ack(uint8_t *pdu,
|
||||
uint16_t pdu_size,
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_list);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_decode_read_foreign_device_table_ack(uint8_t *pdu,
|
||||
uint16_t pdu_len,
|
||||
BACNET_IP_FOREIGN_DEVICE_TABLE_ENTRY *fdt_list);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_result(uint8_t *pdu, uint16_t pdu_size, uint16_t result_code);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_decode_result(uint8_t *pdu, uint16_t pdu_len, uint16_t *result_code);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_original_unicast(
|
||||
uint8_t *pdu, uint16_t pdu_size, uint8_t *npdu, uint16_t npdu_len);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_decode_original_unicast(uint8_t *pdu,
|
||||
uint16_t pdu_len,
|
||||
uint8_t *npdu,
|
||||
uint16_t npdu_size,
|
||||
uint16_t *npdu_len);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_original_broadcast(
|
||||
uint8_t *pdu, uint16_t pdu_size, uint8_t *npdu, uint16_t npdu_len);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_decode_original_broadcast(uint8_t *pdu,
|
||||
uint16_t pdu_len,
|
||||
uint8_t *npdu,
|
||||
uint16_t npdu_size,
|
||||
uint16_t *npdu_len);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_forwarded_npdu(uint8_t *pdu,
|
||||
uint16_t pdu_size,
|
||||
BACNET_IP_ADDRESS *address,
|
||||
uint8_t *npdu,
|
||||
uint16_t npdu_len);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_decode_forwarded_npdu(uint8_t *pdu,
|
||||
uint16_t pdu_len,
|
||||
BACNET_IP_ADDRESS *address,
|
||||
uint8_t *npdu,
|
||||
uint16_t npdu_size,
|
||||
uint16_t *npdu_len);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_register_foreign_device(
|
||||
uint8_t *pdu, uint16_t pdu_size, uint16_t ttl_seconds);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_decode_register_foreign_device(
|
||||
uint8_t *pdu, uint16_t pdu_len, uint16_t *ttl_seconds);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_delete_foreign_device(
|
||||
uint8_t *pdu, uint16_t pdu_size, BACNET_IP_ADDRESS *ip_address);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_decode_delete_foreign_device(
|
||||
uint8_t *pdu, uint16_t pdu_len, BACNET_IP_ADDRESS *ip_address);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_secure_bvll(
|
||||
uint8_t *pdu, uint16_t pdu_size, uint8_t *sbuf, uint16_t sbuf_len);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_decode_secure_bvll(uint8_t *pdu,
|
||||
uint16_t pdu_len,
|
||||
uint8_t *sbuf,
|
||||
uint16_t sbuf_size,
|
||||
uint16_t *sbuf_len);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_distribute_broadcast_to_network(
|
||||
uint8_t *pdu, uint16_t pdu_size, uint8_t *npdu, uint16_t npdu_len);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_decode_distribute_broadcast_to_network(uint8_t *pdu,
|
||||
uint16_t pdu_len,
|
||||
uint8_t *npdu,
|
||||
uint16_t npdu_size,
|
||||
uint16_t *npdu_len);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
BACNET_STACK_EXPORT
|
||||
void test_BVLC(Test *pTest);
|
||||
#endif
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_read_bdt(
|
||||
uint8_t * pdu);
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_bbmd_read_bdt(
|
||||
uint32_t bbmd_address,
|
||||
uint16_t bbmd_port);
|
||||
|
||||
/* registers with a bbmd as a foreign device */
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_register_with_bbmd(
|
||||
uint32_t bbmd_address, /* in network byte order */
|
||||
uint16_t bbmd_port, /* in network byte order */
|
||||
uint16_t time_to_live_seconds);
|
||||
|
||||
/* Note any BVLC_RESULT code, or NAK the BVLL message in the unsupported cases. */
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_for_non_bbmd(
|
||||
struct sockaddr_in *sout,
|
||||
uint8_t * npdu,
|
||||
uint16_t received_bytes);
|
||||
|
||||
/* Returns the last BVLL Result we received, either as the result of a BBMD
|
||||
* request we sent, or (if not a BBMD or Client), from trying to register
|
||||
* as a foreign device. */
|
||||
BACNET_STACK_EXPORT
|
||||
BACNET_BVLC_RESULT bvlc_get_last_result(
|
||||
void);
|
||||
|
||||
/* Returns the current BVLL Function Code we are processing.
|
||||
* We have to store this higher layer code for when the lower layers
|
||||
* need to know what it is, especially to differentiate between
|
||||
* BVLC_ORIGINAL_UNICAST_NPDU and BVLC_ORIGINAL_BROADCAST_NPDU. */
|
||||
BACNET_STACK_EXPORT
|
||||
BACNET_BVLC_FUNCTION bvlc_get_function_code(
|
||||
void);
|
||||
|
||||
|
||||
/* Local interface to manage BBMD.
|
||||
* The interface user needs to handle mutual exclusion if needed i.e.
|
||||
* BACnet packet is not being handled when the BBMD table is modified.
|
||||
*/
|
||||
|
||||
/* Get handle to broadcast distribution table. Returns the number of
|
||||
* valid entries in the table. */
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_get_bdt_local(
|
||||
const BBMD_TABLE_ENTRY** table);
|
||||
|
||||
/* Invalidate all entries in the broadcast distribution table */
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_clear_bdt_local(void);
|
||||
|
||||
/* Add new entry to broadcast distribution table. Returns true if the new
|
||||
* entry was added successfully */
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_add_bdt_entry_local(
|
||||
BBMD_TABLE_ENTRY* entry);
|
||||
|
||||
/* Backup broadcast distribution table to a file.
|
||||
* Filename is the BBMD_BACKUP_FILE constant
|
||||
*/
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_bdt_backup_local(
|
||||
void);
|
||||
|
||||
/* Restore broadcast distribution from a file.
|
||||
* Filename is the BBMD_BACKUP_FILE constant
|
||||
*/
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_bdt_restore_local(
|
||||
void);
|
||||
|
||||
/* NAT handling
|
||||
* If the communication between BBMDs goes through a NAT enabled internet
|
||||
* router, special considerations are needed as stated in Annex J.7.8.
|
||||
*
|
||||
* In short, the local IP address of the BBMD is different than the global
|
||||
* address which is visible to the other BBMDs or foreign devices. This is
|
||||
* why the source address in forwarded messages needs to be changed to the
|
||||
* global IP address.
|
||||
*
|
||||
* For other considerations/limitations see Annex J.7.8.
|
||||
*/
|
||||
|
||||
/* Set global IP address of a NAT enabled router which is used in forwarded
|
||||
* messages. Enables NAT handling.
|
||||
*/
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_set_global_address_for_nat(const struct in_addr* addr);
|
||||
|
||||
/* Disable NAT handling of BBMD.
|
||||
*/
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_disable_nat(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
+16
-15
@@ -47,12 +47,12 @@
|
||||
* BVLC Result Code
|
||||
* @{
|
||||
*/
|
||||
#define BVLC6_RESULT_SUCCESSFUL_COMPLETION 0x0000
|
||||
#define BVLC6_RESULT_ADDRESS_RESOLUTION_NAK 0x0030
|
||||
#define BVLC6_RESULT_VIRTUAL_ADDRESS_RESOLUTION_NAK 0x0060
|
||||
#define BVLC6_RESULT_REGISTER_FOREIGN_DEVICE_NAK 0x0090
|
||||
#define BVLC6_RESULT_DELETE_FOREIGN_DEVICE_NAK 0x00A0
|
||||
#define BVLC6_RESULT_DISTRIBUTE_BROADCAST_TO_NETWORK_NAK 0x00C0
|
||||
#define BVLC6_RESULT_SUCCESSFUL_COMPLETION 0x0000U
|
||||
#define BVLC6_RESULT_ADDRESS_RESOLUTION_NAK 0x0030U
|
||||
#define BVLC6_RESULT_VIRTUAL_ADDRESS_RESOLUTION_NAK 0x0060U
|
||||
#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
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
@@ -71,21 +71,21 @@
|
||||
* defined for B/IPv6.
|
||||
* @{
|
||||
*/
|
||||
#define BIP6_MULTICAST_GROUP_ID 0xBAC0
|
||||
#define BIP6_MULTICAST_GROUP_ID 0xBAC0U
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* IANA prefixes
|
||||
* @{
|
||||
*/
|
||||
#define BIP6_MULTICAST_reserved_0 0xFF00
|
||||
#define BIP6_MULTICAST_NODE_LOCAL 0xFF01
|
||||
#define BIP6_MULTICAST_LINK_LOCAL 0xFF02
|
||||
#define BIP6_MULTICAST_reserved_3 0xFF03
|
||||
#define BIP6_MULTICAST_ADMIN_LOCAL 0xFF04
|
||||
#define BIP6_MULTICAST_SITE_LOCAL 0xFF05
|
||||
#define BIP6_MULTICAST_ORG_LOCAL 0xFF08
|
||||
#define BIP6_MULTICAST_GLOBAL 0xFF0E
|
||||
#define BIP6_MULTICAST_reserved_0 0xFF00U
|
||||
#define BIP6_MULTICAST_NODE_LOCAL 0xFF01U
|
||||
#define BIP6_MULTICAST_LINK_LOCAL 0xFF02U
|
||||
#define BIP6_MULTICAST_reserved_3 0xFF03U
|
||||
#define BIP6_MULTICAST_ADMIN_LOCAL 0xFF04U
|
||||
#define BIP6_MULTICAST_SITE_LOCAL 0xFF05U
|
||||
#define BIP6_MULTICAST_ORG_LOCAL 0xFF08U
|
||||
#define BIP6_MULTICAST_GLOBAL 0xFF0EU
|
||||
/** @} */
|
||||
|
||||
/* number of bytes in the IPv6 address */
|
||||
@@ -379,6 +379,7 @@ extern "C" {
|
||||
uint16_t pdu_size,
|
||||
uint32_t vmac_src,
|
||||
BACNET_IP6_ADDRESS *bip6_address);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc6_decode_delete_foreign_device(
|
||||
uint8_t * pdu,
|
||||
|
||||
@@ -173,4 +173,9 @@ void datalink_set_interface(char *ifname)
|
||||
void datalink_set(char *datalink_string)
|
||||
{
|
||||
}
|
||||
|
||||
void datalink_maintenance_timer(uint16_t seconds)
|
||||
{
|
||||
(void)seconds;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#define datalink_cleanup ethernet_cleanup
|
||||
#define datalink_get_broadcast_address ethernet_get_broadcast_address
|
||||
#define datalink_get_my_address ethernet_get_my_address
|
||||
#define datalink_maintenance_timer(s)
|
||||
|
||||
#elif defined(BACDL_ARCNET)
|
||||
#include "bacnet/datalink/arcnet.h"
|
||||
@@ -47,6 +48,7 @@
|
||||
#define datalink_cleanup arcnet_cleanup
|
||||
#define datalink_get_broadcast_address arcnet_get_broadcast_address
|
||||
#define datalink_get_my_address arcnet_get_my_address
|
||||
#define datalink_maintenance_timer(s)
|
||||
|
||||
#elif defined(BACDL_MSTP)
|
||||
#include "bacnet/datalink/dlmstp.h"
|
||||
@@ -57,19 +59,16 @@
|
||||
#define datalink_cleanup dlmstp_cleanup
|
||||
#define datalink_get_broadcast_address dlmstp_get_broadcast_address
|
||||
#define datalink_get_my_address dlmstp_get_my_address
|
||||
#define datalink_maintenance_timer(s)
|
||||
|
||||
#elif defined(BACDL_BIP)
|
||||
#include "bacnet/datalink/bip.h"
|
||||
#include "bacnet/datalink/bvlc.h"
|
||||
#include "bacnet/basic/bbmd/h_bbmd.h"
|
||||
|
||||
#define datalink_init bip_init
|
||||
#if defined(BBMD_ENABLED) && BBMD_ENABLED
|
||||
#define datalink_send_pdu bvlc_send_pdu
|
||||
#define datalink_receive bvlc_receive
|
||||
#else
|
||||
#define datalink_send_pdu bip_send_pdu
|
||||
#define datalink_receive bip_receive
|
||||
#endif
|
||||
#define datalink_cleanup bip_cleanup
|
||||
#define datalink_get_broadcast_address bip_get_broadcast_address
|
||||
#ifdef BAC_ROUTING
|
||||
@@ -80,6 +79,7 @@ void routed_get_my_address(
|
||||
#else
|
||||
#define datalink_get_my_address bip_get_my_address
|
||||
#endif
|
||||
#define datalink_maintenance_timer(s) bvlc_maintenance_timer(s)
|
||||
|
||||
#elif defined(BACDL_BIP6)
|
||||
#include "bacnet/datalink/bip6.h"
|
||||
@@ -90,6 +90,7 @@ void routed_get_my_address(
|
||||
#define datalink_cleanup bip6_cleanup
|
||||
#define datalink_get_broadcast_address bip6_get_broadcast_address
|
||||
#define datalink_get_my_address bip6_get_my_address
|
||||
#define datalink_maintenance_timer(s) bvlc6_maintenance_timer(s)
|
||||
|
||||
#elif defined(BACDL_ALL) || defined(BACDL_NONE)
|
||||
#include "bacnet/npdu.h"
|
||||
@@ -107,28 +108,37 @@ extern "C" {
|
||||
BACNET_NPDU_DATA * npdu_data,
|
||||
uint8_t * pdu,
|
||||
unsigned pdu_len);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint16_t datalink_receive(
|
||||
BACNET_ADDRESS * src,
|
||||
uint8_t * pdu,
|
||||
uint16_t max_pdu,
|
||||
unsigned timeout);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void datalink_cleanup(
|
||||
void);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void datalink_get_broadcast_address(
|
||||
BACNET_ADDRESS * dest);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void datalink_get_my_address(
|
||||
BACNET_ADDRESS * my_address);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void datalink_set_interface(
|
||||
char *ifname);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void datalink_set(
|
||||
char *datalink_string);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void datalink_maintenance_timer(uint16_t seconds);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
@@ -149,9 +159,11 @@ extern "C" {
|
||||
* - BACDL_ETHERNET -- for Clause 7 ISO 8802-3 ("Ethernet") LAN
|
||||
* - BACDL_ARCNET -- for Clause 8 ARCNET LAN
|
||||
* - BACDL_MSTP -- for Clause 9 MASTER-SLAVE/TOKEN PASSING (MS/TP) LAN
|
||||
* - BACDL_BIP -- for ANNEX J - BACnet/IP
|
||||
* - BACDL_BIP -- for ANNEX J - BACnet/IPv4
|
||||
* - BACDL_BIP6 -- for ANNEX U - BACnet/IPv6
|
||||
* - BACDL_ALL -- Unspecified for the build, so the transport can be
|
||||
* chosen at runtime from among these choices.
|
||||
* - BACDL_NONE -- Unspecified for the build for unit testing
|
||||
* - Clause 10 POINT-TO-POINT (PTP) and Clause 11 EIA/CEA-709.1 ("LonTalk") LAN
|
||||
* are not currently supported by this project.
|
||||
*//** @defgroup DLTemplates DataLink Template Functions
|
||||
|
||||
+114
-101
@@ -39,53 +39,44 @@
|
||||
#include "bacnet/basic/object/netport.h"
|
||||
#endif
|
||||
|
||||
#if defined(BACDL_BIP6)
|
||||
#include "bacnet/datalink/bvlc6.h"
|
||||
#include "bacnet/datalink/bip6.h"
|
||||
#endif
|
||||
|
||||
/** @file dlenv.c Initialize the DataLink configuration. */
|
||||
|
||||
#if defined(BACDL_BIP)
|
||||
/* timer used to renew Foreign Device Registration */
|
||||
static uint16_t BBMD_Timer_Seconds;
|
||||
/* BBMD variables */
|
||||
static long bbmd_timetolive_seconds = 60000;
|
||||
static long bbmd_port = 0xBAC0;
|
||||
static long bbmd_address = 0;
|
||||
static long bbmd_mask = 0xFFFFFFFF;
|
||||
static int bbmd_result = 0;
|
||||
static BBMD_TABLE_ENTRY BBMD_Table_Entry;
|
||||
static uint16_t BBMD_TTL_Seconds = 60000;
|
||||
static BACNET_IP_ADDRESS BBMD_Address;
|
||||
static bool BBMD_Address_Valid;
|
||||
static uint16_t BBMD_Result = 0;
|
||||
static BACNET_IP_BROADCAST_DISTRIBUTION_TABLE_ENTRY BBMD_Table_Entry;
|
||||
/* enable debugging */
|
||||
static bool BIP_DL_Debug = false;
|
||||
|
||||
/* Simple setters for BBMD registration variables. */
|
||||
|
||||
/** Sets the IPv4 address for BBMD registration.
|
||||
/**
|
||||
* @brief Sets the IPv4 address for BBMD registration.
|
||||
*
|
||||
* If not set here or provided by Environment variables,
|
||||
* no BBMD registration will occur.
|
||||
* @param address - IPv4 address (long) of BBMD to register with,
|
||||
*
|
||||
* @param address - IPv4 address (uint32_t) of BBMD to register with,
|
||||
* in network byte order.
|
||||
*/
|
||||
void dlenv_bbmd_address_set(long address)
|
||||
void dlenv_bbmd_address_set(
|
||||
BACNET_IP_ADDRESS *address)
|
||||
{
|
||||
bbmd_address = address;
|
||||
}
|
||||
|
||||
/** Set the port for BBMD registration.
|
||||
* Default if not set is 0xBAC0.
|
||||
* @param port - The port number (provided in network byte order).
|
||||
*/
|
||||
void dlenv_bbmd_port_set(int port)
|
||||
{
|
||||
bbmd_port = port;
|
||||
bvlc_address_copy(&BBMD_Address, address);
|
||||
BBMD_Address_Valid = true;
|
||||
}
|
||||
|
||||
/** Set the Lease Time (Time-to-Live) for BBMD registration.
|
||||
* Default if not set is 60000 (1000 minutes).
|
||||
* @param ttl_secs - The Lease Time, in seconds.
|
||||
*/
|
||||
void dlenv_bbmd_ttl_set(int ttl_secs)
|
||||
void dlenv_bbmd_ttl_set(uint16_t ttl_secs)
|
||||
{
|
||||
bbmd_timetolive_seconds = ttl_secs;
|
||||
BBMD_TTL_Seconds = ttl_secs;
|
||||
}
|
||||
|
||||
/** Get the result of the last attempt to register with the indicated BBMD.
|
||||
@@ -98,12 +89,12 @@ void dlenv_bbmd_ttl_set(int ttl_secs)
|
||||
*/
|
||||
int dlenv_bbmd_result(void)
|
||||
{
|
||||
if ((bbmd_result > 0) &&
|
||||
if ((BBMD_Result > 0) &&
|
||||
(bvlc_get_last_result() == BVLC_RESULT_REGISTER_FOREIGN_DEVICE_NAK)) {
|
||||
return -1;
|
||||
}
|
||||
/* Else, show our send: */
|
||||
return bbmd_result;
|
||||
return BBMD_Result;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -125,86 +116,124 @@ int dlenv_register_as_foreign_device(void)
|
||||
{
|
||||
int retval = 0;
|
||||
#if defined(BACDL_BIP)
|
||||
bool bdt_entry_valid = false;
|
||||
uint16_t bdt_entry_port = 0;
|
||||
char *pEnv = NULL;
|
||||
unsigned a[4] = { 0 };
|
||||
char bbmd_env[32] = "";
|
||||
unsigned entry_number = 0;
|
||||
unsigned entry_number = 0;\
|
||||
long long_value = 0;
|
||||
int c;
|
||||
|
||||
pEnv = getenv("BACNET_BBMD_PORT");
|
||||
if (pEnv) {
|
||||
bbmd_port = strtol(pEnv, NULL, 0);
|
||||
if (bbmd_port > 0xFFFF) {
|
||||
bbmd_port = 0xBAC0;
|
||||
long_value = strtol(pEnv, NULL, 0);
|
||||
if (long_value <= 0xFFFF) {
|
||||
BBMD_Address.port = (uint16_t)long_value;
|
||||
} else {
|
||||
BBMD_Address.port = 0xBAC0;
|
||||
}
|
||||
}
|
||||
pEnv = getenv("BACNET_BBMD_TIMETOLIVE");
|
||||
if (pEnv) {
|
||||
bbmd_timetolive_seconds = strtol(pEnv, NULL, 0);
|
||||
if (bbmd_timetolive_seconds > 0xFFFF) {
|
||||
bbmd_timetolive_seconds = 0xFFFF;
|
||||
long_value = strtol(pEnv, NULL, 0);
|
||||
if (long_value <= 0xFFFF) {
|
||||
BBMD_TTL_Seconds = (uint16_t)long_value;
|
||||
} else {
|
||||
BBMD_TTL_Seconds = 0xFFFF;
|
||||
}
|
||||
}
|
||||
pEnv = getenv("BACNET_BBMD_ADDRESS");
|
||||
if (pEnv) {
|
||||
bbmd_address = bip_getaddrbyname(pEnv);
|
||||
BBMD_Address_Valid = bip_get_addr_by_name(pEnv, &BBMD_Address);
|
||||
}
|
||||
if (bbmd_address) {
|
||||
struct in_addr addr;
|
||||
addr.s_addr = bbmd_address;
|
||||
fprintf(stderr, "Registering with BBMD at %s:%ld for %ld seconds\n",
|
||||
inet_ntoa(addr), bbmd_port, bbmd_timetolive_seconds);
|
||||
retval = bvlc_register_with_bbmd(bbmd_address,
|
||||
htons((uint16_t)bbmd_port), (uint16_t)bbmd_timetolive_seconds);
|
||||
if (BBMD_Address_Valid) {
|
||||
if (BIP_DL_Debug) {
|
||||
fprintf(stderr,
|
||||
"Registering with BBMD at %u.%u.%u.%u:%u for %u seconds\n",
|
||||
(unsigned)BBMD_Address.address[0],
|
||||
(unsigned)BBMD_Address.address[1],
|
||||
(unsigned)BBMD_Address.address[2],
|
||||
(unsigned)BBMD_Address.address[3],
|
||||
(unsigned)BBMD_Address.port,
|
||||
(unsigned)BBMD_TTL_Seconds);
|
||||
}
|
||||
retval = bvlc_register_with_bbmd(&BBMD_Address,
|
||||
BBMD_TTL_Seconds);
|
||||
if (retval < 0) {
|
||||
fprintf(stderr, "FAILED to Register with BBMD at %s \n",
|
||||
inet_ntoa(addr));
|
||||
fprintf(stderr,
|
||||
"FAILED to Register with BBMD at %u.%u.%u.%u:%u\n",
|
||||
(unsigned)BBMD_Address.address[0],
|
||||
(unsigned)BBMD_Address.address[1],
|
||||
(unsigned)BBMD_Address.address[2],
|
||||
(unsigned)BBMD_Address.address[3],
|
||||
(unsigned)BBMD_Address.port);
|
||||
}
|
||||
BBMD_Timer_Seconds = (uint16_t)bbmd_timetolive_seconds;
|
||||
BBMD_Timer_Seconds = (uint16_t)BBMD_TTL_Seconds;
|
||||
} else {
|
||||
for (entry_number = 1; entry_number <= 128; entry_number++) {
|
||||
bdt_entry_valid = false;
|
||||
sprintf(bbmd_env, "BACNET_BDT_ADDR_%u", entry_number);
|
||||
pEnv = getenv(bbmd_env);
|
||||
if (pEnv) {
|
||||
bbmd_address = bip_getaddrbyname(pEnv);
|
||||
bdt_entry_valid = bip_get_addr_by_name(pEnv,
|
||||
&BBMD_Table_Entry.dest_address);
|
||||
if (entry_number == 1) {
|
||||
if (BIP_DL_Debug) {
|
||||
fprintf(stderr, "BBMD 1 is %s=%s!\n", bbmd_env, pEnv);
|
||||
}
|
||||
}
|
||||
} else if (entry_number == 1) {
|
||||
/* BDT 1 is self (note: can be overridden) */
|
||||
bbmd_address = bip_get_addr();
|
||||
bdt_entry_valid = bip_get_addr(&BBMD_Table_Entry.dest_address);
|
||||
}
|
||||
if (bbmd_address) {
|
||||
bbmd_port = 0xBAC0;
|
||||
if (bdt_entry_valid) {
|
||||
if (entry_number != 1) {
|
||||
bdt_entry_port = 0xBAC0;
|
||||
sprintf(bbmd_env, "BACNET_BDT_PORT_%u", entry_number);
|
||||
pEnv = getenv(bbmd_env);
|
||||
if (pEnv) {
|
||||
bbmd_port = strtol(pEnv, NULL, 0);
|
||||
if (bbmd_port > 0xFFFF) {
|
||||
bbmd_port = 0xBAC0;
|
||||
bdt_entry_port = strtol(pEnv, NULL, 0);
|
||||
if (bdt_entry_port > 0xFFFF) {
|
||||
bdt_entry_port = 0xBAC0;
|
||||
}
|
||||
} else if (entry_number == 1) {
|
||||
/* BDT 1 is self (note: can be overridden) */
|
||||
bbmd_port = bip_get_port();
|
||||
}
|
||||
bbmd_mask = 0xFFFFFFFF;
|
||||
BBMD_Table_Entry.dest_address.port = bdt_entry_port;
|
||||
}
|
||||
/* broadcast mask */
|
||||
bvlc_broadcast_distribution_mask_from_host(
|
||||
&BBMD_Table_Entry.broadcast_mask, 0xFFFFFFFF);
|
||||
sprintf(bbmd_env, "BACNET_BDT_MASK_%u", entry_number);
|
||||
pEnv = getenv(bbmd_env);
|
||||
if (pEnv) {
|
||||
c = sscanf(
|
||||
pEnv, "%3u.%3u.%3u.%3u", &a[0], &a[1], &a[2], &a[3]);
|
||||
if (c == 4) {
|
||||
bbmd_mask = ((a[0] & 0xFF) << 24) |
|
||||
((a[1] & 0xFF) << 16) | ((a[2] & 0xFF) << 8) |
|
||||
(a[3] & 0xFF);
|
||||
bvlc_broadcast_distribution_mask_set(
|
||||
&BBMD_Table_Entry.broadcast_mask,
|
||||
a[0], a[1], a[2], a[3]);
|
||||
}
|
||||
}
|
||||
BBMD_Table_Entry.valid = true;
|
||||
BBMD_Table_Entry.dest_address.s_addr = bbmd_address;
|
||||
BBMD_Table_Entry.dest_port = bbmd_port;
|
||||
BBMD_Table_Entry.broadcast_mask.s_addr = bbmd_mask;
|
||||
bvlc_add_bdt_entry_local(&BBMD_Table_Entry);
|
||||
bvlc_broadcast_distribution_table_entry_append(
|
||||
bvlc_bdt_list(), &BBMD_Table_Entry);
|
||||
if (BIP_DL_Debug) {
|
||||
fprintf(stderr,
|
||||
"BBMD %4u: %u.%u.%u.%u:%u %u.%u.%u.%u\n", entry_number,
|
||||
(unsigned)BBMD_Table_Entry.dest_address.address[0],
|
||||
(unsigned)BBMD_Table_Entry.dest_address.address[1],
|
||||
(unsigned)BBMD_Table_Entry.dest_address.address[2],
|
||||
(unsigned)BBMD_Table_Entry.dest_address.address[3],
|
||||
(unsigned)BBMD_Table_Entry.dest_address.port,
|
||||
(unsigned)BBMD_Table_Entry.broadcast_mask.address[0],
|
||||
(unsigned)BBMD_Table_Entry.broadcast_mask.address[1],
|
||||
(unsigned)BBMD_Table_Entry.broadcast_mask.address[2],
|
||||
(unsigned)BBMD_Table_Entry.broadcast_mask.address[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
bbmd_result = retval;
|
||||
}
|
||||
BBMD_Result = retval;
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
@@ -216,34 +245,16 @@ int dlenv_register_as_foreign_device(void)
|
||||
*/
|
||||
static void dlenv_network_port_init(void)
|
||||
{
|
||||
uint32_t instance = 1;
|
||||
uint32_t address = 0;
|
||||
uint32_t broadcast = 0;
|
||||
uint32_t test_broadcast = 0;
|
||||
uint32_t mask = 0xFFFFFFFE;
|
||||
uint16_t port = 0;
|
||||
uint8_t mac[4 + 2] = { 0 };
|
||||
uint8_t prefix = 0;
|
||||
const uint32_t instance = 1;
|
||||
BACNET_IP_ADDRESS addr = { 0 };
|
||||
|
||||
Network_Port_Object_Instance_Number_Set(0, instance);
|
||||
Network_Port_Name_Set(instance, "BACnet/IP Port");
|
||||
Network_Port_Type_Set(instance, PORT_TYPE_BIP);
|
||||
port = bip_get_port();
|
||||
Network_Port_BIP_Port_Set(instance, port);
|
||||
address = bip_get_addr();
|
||||
memcpy(&mac[0], &address, 4);
|
||||
memcpy(&mac[4], &port, 2);
|
||||
Network_Port_MAC_Address_Set(instance, &mac[0], 6);
|
||||
broadcast = bip_get_broadcast_addr();
|
||||
/* calculate the subnet prefix from the broadcast address */
|
||||
for (prefix = 1; prefix <= 32; prefix++) {
|
||||
test_broadcast = (address & mask) | (~mask);
|
||||
if (test_broadcast == broadcast) {
|
||||
break;
|
||||
}
|
||||
mask = mask<<1;
|
||||
}
|
||||
Network_Port_IP_Subnet_Prefix_Set(instance, prefix);
|
||||
bip_get_addr(&addr);
|
||||
Network_Port_BIP_Port_Set(instance, addr.port);
|
||||
Network_Port_MAC_Address_Set(instance, &addr.address[0], 6);
|
||||
Network_Port_IP_Subnet_Prefix_Set(instance, bip_get_subnet_prefix());
|
||||
Network_Port_Link_Speed_Set(instance, 0.0);
|
||||
/* common NP data */
|
||||
Network_Port_Reliability_Set(instance, RELIABILITY_NO_FAULT_DETECTED);
|
||||
@@ -346,7 +357,7 @@ void dlenv_maintenance_timer(uint16_t elapsed_seconds)
|
||||
/* If that failed (negative), maybe just a network issue.
|
||||
* If nothing happened (0), may be un/misconfigured.
|
||||
* Set up to try again later in all cases. */
|
||||
BBMD_Timer_Seconds = (uint16_t)bbmd_timetolive_seconds;
|
||||
BBMD_Timer_Seconds = (uint16_t)BBMD_TTL_Seconds;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -434,12 +445,15 @@ void dlenv_init(void)
|
||||
}
|
||||
#endif
|
||||
#if defined(BACDL_BIP)
|
||||
#if defined(BIP_DEBUG)
|
||||
BIP_Debug = true;
|
||||
#endif
|
||||
pEnv = getenv("BACNET_IP_DEBUG");
|
||||
if (pEnv) {
|
||||
bip_debug_enable();
|
||||
bvlc_debug_enable();
|
||||
BIP_DL_Debug = true;
|
||||
}
|
||||
pEnv = getenv("BACNET_IP_PORT");
|
||||
if (pEnv) {
|
||||
bip_set_port(htons((uint16_t)strtol(pEnv, NULL, 0)));
|
||||
bip_set_port((uint16_t)strtol(pEnv, NULL, 0));
|
||||
} else {
|
||||
/* BIP_Port is statically initialized to 0xBAC0,
|
||||
* so if it is different, then it was programmatically altered,
|
||||
@@ -447,16 +461,15 @@ void dlenv_init(void)
|
||||
* Unless it is set below 1024, since:
|
||||
* "The range for well-known ports managed by the IANA is 0-1023."
|
||||
*/
|
||||
if (ntohs(bip_get_port()) < 1024) {
|
||||
bip_set_port(htons(0xBAC0));
|
||||
if (bip_get_port() < 1024) {
|
||||
bip_set_port(0xBAC0);
|
||||
}
|
||||
}
|
||||
pEnv = getenv("BACNET_IP_NAT_ADDR");
|
||||
if (pEnv) {
|
||||
struct in_addr nat_addr;
|
||||
nat_addr.s_addr = bip_getaddrbyname(pEnv);
|
||||
if (nat_addr.s_addr) {
|
||||
bvlc_set_global_address_for_nat(&nat_addr);
|
||||
BACNET_IP_ADDRESS addr;
|
||||
if (bip_get_addr_by_name(pEnv, &addr)) {
|
||||
bvlc_set_global_address_for_nat(&addr);
|
||||
}
|
||||
}
|
||||
#elif defined(BACDL_MSTP)
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
*********************************************************************/
|
||||
#ifndef DLENV_H
|
||||
#define DLENV_H
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdint.h>
|
||||
#include "bacnet/datalink/bvlc.h"
|
||||
|
||||
#include "bacnet/bacnet_stack_exports.h"
|
||||
|
||||
@@ -34,23 +38,23 @@ extern "C" {
|
||||
BACNET_STACK_EXPORT
|
||||
void dlenv_init(
|
||||
void);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int dlenv_register_as_foreign_device(
|
||||
void);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void dlenv_maintenance_timer(
|
||||
uint16_t elapsed_seconds);
|
||||
|
||||
/* Simple setters and getter. */
|
||||
BACNET_STACK_EXPORT
|
||||
void dlenv_bbmd_address_set(
|
||||
long address);
|
||||
BACNET_STACK_EXPORT
|
||||
void dlenv_bbmd_port_set(
|
||||
int port);
|
||||
BACNET_IP_ADDRESS *address);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void dlenv_bbmd_ttl_set(
|
||||
int ttl_secs);
|
||||
uint16_t ttl_secs);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int dlenv_bbmd_result(
|
||||
void);
|
||||
|
||||
@@ -65,6 +65,11 @@ bacstr: logfile bacstr.mak
|
||||
( ./bacstr >> ${LOGFILE} )
|
||||
$(MAKE) -s -f bacstr.mak clean
|
||||
|
||||
bvlc: logfile bvlc.mak
|
||||
$(MAKE) -s -f bvlc.mak clean all
|
||||
( ./bvlc >> ${LOGFILE} )
|
||||
$(MAKE) -s -f bvlc.mak clean
|
||||
|
||||
bvlc6: logfile bvlc6.mak
|
||||
$(MAKE) -s -f bvlc6.mak clean all
|
||||
( ./bvlc6 >> ${LOGFILE} )
|
||||
|
||||
+5
-2
@@ -1,7 +1,7 @@
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../src
|
||||
INCLUDES = -I$(SRC_DIR) -I. -I../ports/linux
|
||||
INCLUDES = -I$(SRC_DIR) -I.
|
||||
DEFINES = -DBACDL_BIP -DBIG_ENDIAN=0 -DTEST -DTEST_BVLC
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
@@ -10,7 +10,7 @@ SRCS = $(SRC_DIR)/bacnet/bacdcode.c \
|
||||
$(SRC_DIR)/bacnet/bacint.c \
|
||||
$(SRC_DIR)/bacnet/bacstr.c \
|
||||
$(SRC_DIR)/bacnet/bacreal.c \
|
||||
$(SRC_DIR)/bacnet/bvlc.c \
|
||||
$(SRC_DIR)/bacnet/datalink/bvlc.c \
|
||||
ctest.c
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
@@ -38,4 +38,7 @@ depend:
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS) *.bak *.1 *.ini
|
||||
|
||||
test: ${TARGET}
|
||||
./${TARGET}
|
||||
|
||||
include: .depend
|
||||
|
||||
Reference in New Issue
Block a user