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:
+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
|
||||
}
|
||||
|
||||
+2995
-1633
File diff suppressed because it is too large
Load Diff
+481
-183
@@ -1,204 +1,502 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
/* 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 */
|
||||
BACNET_IP_ADDRESS dest_address;
|
||||
/* Broadcast Distribution Mask */
|
||||
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 */
|
||||
|
||||
#if defined(BBMD_ENABLED) && BBMD_ENABLED
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_maintenance_timer(
|
||||
time_t seconds);
|
||||
#else
|
||||
#define bvlc_maintenance_timer(x)
|
||||
int bvlc_encode_address(
|
||||
uint8_t *pdu, uint16_t pdu_size, const BACNET_IP_ADDRESS *ip_address);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_decode_address(
|
||||
uint8_t *pdu, uint16_t pdu_len, BACNET_IP_ADDRESS *ip_address);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_address_copy(BACNET_IP_ADDRESS *dst, const BACNET_IP_ADDRESS *src);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_address_different(
|
||||
const BACNET_IP_ADDRESS *dst, const BACNET_IP_ADDRESS *src);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_address_from_ascii(BACNET_IP_ADDRESS *dst, const char *addrstr);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bvlc_address_port_from_ascii(
|
||||
BACNET_IP_ADDRESS *dst, const char *addrstr, const char *portstr);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void bvlc_address_from_network(BACNET_IP_ADDRESS *dst, uint32_t addr);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
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
|
||||
|
||||
typedef struct {
|
||||
/* 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 */
|
||||
/* Broadcast Distribution Mask */
|
||||
struct in_addr broadcast_mask; /* in tework format */
|
||||
} BBMD_TABLE_ENTRY;
|
||||
|
||||
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 */
|
||||
|
||||
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);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_send_mpdu(
|
||||
struct sockaddr_in *dest,
|
||||
uint8_t * mtu,
|
||||
uint16_t mtu_len);
|
||||
|
||||
#if defined(BBMD_CLIENT_ENABLED) && BBMD_CLIENT_ENABLED
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_write_bdt_init(
|
||||
uint8_t * pdu,
|
||||
unsigned entries);
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_read_fdt(
|
||||
uint8_t * pdu);
|
||||
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 */
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_original_unicast_npdu(
|
||||
uint8_t * pdu,
|
||||
uint8_t * npdu,
|
||||
unsigned npdu_length);
|
||||
BACNET_STACK_EXPORT
|
||||
int bvlc_encode_original_broadcast_npdu(
|
||||
uint8_t * pdu,
|
||||
uint8_t * npdu,
|
||||
unsigned npdu_length);
|
||||
#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
|
||||
}
|
||||
#endif /* __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
|
||||
|
||||
+122
-109
@@ -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.
|
||||
* If not set here or provided by Environment variables,
|
||||
* no BBMD registration will occur.
|
||||
* @param address - IPv4 address (long) of BBMD to register with,
|
||||
* in network byte order.
|
||||
/**
|
||||
* @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 (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 (retval < 0) {
|
||||
fprintf(stderr, "FAILED to Register with BBMD at %s \n",
|
||||
inet_ntoa(addr));
|
||||
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);
|
||||
}
|
||||
BBMD_Timer_Seconds = (uint16_t)bbmd_timetolive_seconds;
|
||||
retval = bvlc_register_with_bbmd(&BBMD_Address,
|
||||
BBMD_TTL_Seconds);
|
||||
if (retval < 0) {
|
||||
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_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;
|
||||
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;
|
||||
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) {
|
||||
bdt_entry_port = strtol(pEnv, NULL, 0);
|
||||
if (bdt_entry_port > 0xFFFF) {
|
||||
bdt_entry_port = 0xBAC0;
|
||||
}
|
||||
/* BDT 1 is self (note: can be overridden) */
|
||||
}
|
||||
} else if (entry_number == 1) {
|
||||
/* BDT 1 is self (note: can be overridden) */
|
||||
bbmd_port = bip_get_port();
|
||||
BBMD_Table_Entry.dest_address.port = bdt_entry_port;
|
||||
}
|
||||
bbmd_mask = 0xFFFFFFFF;
|
||||
/* 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);
|
||||
|
||||
Reference in New Issue
Block a user