Added more handling to BVLC. Still more to do.
This commit is contained in:
+126
-27
@@ -37,8 +37,8 @@
|
|||||||
#include <time.h> /* for the standard bool type. */
|
#include <time.h> /* for the standard bool type. */
|
||||||
#include "bacdcode.h"
|
#include "bacdcode.h"
|
||||||
#include "bacint.h"
|
#include "bacint.h"
|
||||||
|
#include "bvlc.h"
|
||||||
#include "bip.h"
|
#include "bip.h"
|
||||||
#include "net.h" /* custom per port */
|
|
||||||
|
|
||||||
/* Handle the BACnet Virtual Link Control (BVLC), which includes:
|
/* Handle the BACnet Virtual Link Control (BVLC), which includes:
|
||||||
BACnet Broadcast Management Device,
|
BACnet Broadcast Management Device,
|
||||||
@@ -485,6 +485,16 @@ void bvlc_bdt_forward_npdu(
|
|||||||
htonl(((~BBMD_Table[i].broadcast_mask.s_addr) |
|
htonl(((~BBMD_Table[i].broadcast_mask.s_addr) |
|
||||||
BBMD_Table[i].dest_address.s_addr));
|
BBMD_Table[i].dest_address.s_addr));
|
||||||
bip_dest.sin_port = htons(BBMD_Table[i].dest_port);
|
bip_dest.sin_port = htons(BBMD_Table[i].dest_port);
|
||||||
|
/* don't send to my broadcast address and same port */
|
||||||
|
if ((bip_dest.sin_addr.s_addr == htonl(bip_get_broadcast_addr())) &&
|
||||||
|
(bip_dest.sin_port == htons(bip_get_port))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* don't send to my ip address and same port */
|
||||||
|
if ((bip_dest.sin_addr.s_addr == htonl(bip_get_addr())) &&
|
||||||
|
(bip_dest.sin_port == htons(bip_get_port))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
/* Send the packet */
|
/* Send the packet */
|
||||||
bytes_sent =
|
bytes_sent =
|
||||||
sendto(bip_socket(), (char *) mtu, mtu_len, 0,
|
sendto(bip_socket(), (char *) mtu, mtu_len, 0,
|
||||||
@@ -501,28 +511,62 @@ void bvlc_fdt_forward_npdu(
|
|||||||
uint8_t * npdu, /* returns the NPDU */
|
uint8_t * npdu, /* returns the NPDU */
|
||||||
uint16_t max_npdu) /* amount of space available in the NPDU */
|
uint16_t max_npdu) /* amount of space available in the NPDU */
|
||||||
{
|
{
|
||||||
|
uint8_t mtu[MAX_MPDU] = {0};
|
||||||
|
int mtu_len = 0;
|
||||||
|
int bytes_sent = 0;
|
||||||
|
unsigned i = 0; /* loop counter */
|
||||||
|
struct sockaddr_in bvlc_dest;
|
||||||
|
BACNET_ADDRESS src;
|
||||||
|
|
||||||
/* FIXME: add the code */
|
/* assumes that the driver has already been initialized */
|
||||||
|
if (bip_socket() < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bvlc_internet_to_bacnet_address(&src, sin);
|
||||||
|
mtu_len = bvlc_encode_forwarded_npdu(
|
||||||
|
&mtu[0],
|
||||||
|
&src,
|
||||||
|
npdu,
|
||||||
|
npdu_length);
|
||||||
|
/* load destination IP address */
|
||||||
|
bvlc_dest.sin_family = AF_INET;
|
||||||
|
/* loop through the FDT and send one to each entry */
|
||||||
|
for (i = 0; i < MAX_FD_ENTRIES; i++) {
|
||||||
|
if (FD_Table[i].valid && FD_Table[i].seconds_remaining) {
|
||||||
|
bvlc_dest.sin_addr.s_addr =
|
||||||
|
htonl(FD_Table[i].dest_address.s_addr);
|
||||||
|
bvlc_dest.sin_port = htons(FD_Table[i].dest_port);
|
||||||
|
/* Send the packet */
|
||||||
|
bytes_sent =
|
||||||
|
sendto(bip_socket(), (char *) mtu, mtu_len, 0,
|
||||||
|
(struct sockaddr *) &bvlc_dest,
|
||||||
|
sizeof(struct sockaddr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t bvlc_handler(
|
/* returns:
|
||||||
|
Number of bytes received, or 0 if none or timeout. */
|
||||||
|
uint16_t bvlc_receive(
|
||||||
BACNET_ADDRESS * src, /* returns the source address */
|
BACNET_ADDRESS * src, /* returns the source address */
|
||||||
uint8_t * npdu, /* returns the NPDU */
|
uint8_t * npdu, /* returns the NPDU */
|
||||||
uint16_t max_npdu, /* amount of space available in the NPDU */
|
uint16_t max_npdu, /* amount of space available in the NPDU */
|
||||||
unsigned timeout) /* number of milliseconds to wait for a packet */
|
unsigned timeout) /* number of milliseconds to wait for a packet */
|
||||||
{
|
{
|
||||||
uint8_t buf[MAX_MPDU] = {0}; /* data */
|
|
||||||
uint16_t pdu_len = 0; /* return value */
|
uint16_t pdu_len = 0; /* return value */
|
||||||
fd_set read_fds;
|
fd_set read_fds;
|
||||||
int max;
|
int max = 0;
|
||||||
struct timeval select_timeout;
|
struct timeval select_timeout;
|
||||||
struct sockaddr_in sin = { -1 };
|
struct sockaddr_in sin = { -1 };
|
||||||
socklen_t sin_len = sizeof(sin);
|
socklen_t sin_len = sizeof(sin);
|
||||||
int function_type = 0;
|
int function_type = 0;
|
||||||
int received_bytes;
|
int received_bytes = 0;
|
||||||
|
unsigned i =0;
|
||||||
|
|
||||||
/* Make sure the socket is open */
|
/* Make sure the socket is open */
|
||||||
if (BIP_Socket < 0) {
|
if (bip_socket() < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -538,14 +582,14 @@ uint16_t bvlc_handler(
|
|||||||
select_timeout.tv_usec = 1000 * timeout;
|
select_timeout.tv_usec = 1000 * timeout;
|
||||||
}
|
}
|
||||||
FD_ZERO(&read_fds);
|
FD_ZERO(&read_fds);
|
||||||
FD_SET((unsigned int) BIP_Socket, &read_fds);
|
FD_SET((unsigned int) bip_socket(), &read_fds);
|
||||||
max = BIP_Socket;
|
max = bip_socket();
|
||||||
/* see if there is a packet for us */
|
/* see if there is a packet for us */
|
||||||
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) {
|
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) {
|
||||||
received_bytes = recvfrom(
|
received_bytes = recvfrom(
|
||||||
BIP_Socket,
|
bip_socket(),
|
||||||
(char *) &buf[0],
|
(char *) &npdu[0],
|
||||||
MAX_MPDU, 0,
|
max_npdu, 0,
|
||||||
(struct sockaddr *) &sin, &sin_len);
|
(struct sockaddr *) &sin, &sin_len);
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -562,9 +606,9 @@ uint16_t bvlc_handler(
|
|||||||
if (buf[0] != BVLL_TYPE_BACNET_IP) {
|
if (buf[0] != BVLL_TYPE_BACNET_IP) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
function_type = buf[1];
|
function_type = npdu[1];
|
||||||
/* decode the length of the PDU - length is inclusive of BVLC */
|
/* decode the length of the PDU - length is inclusive of BVLC */
|
||||||
(void) decode_unsigned16(&buf[2], &npdu_len);
|
(void) decode_unsigned16(&npdu[2], &npdu_len);
|
||||||
/* subtract off the BVLC header */
|
/* subtract off the BVLC header */
|
||||||
npdu_len -= 4;
|
npdu_len -= 4;
|
||||||
switch (function_type) {
|
switch (function_type) {
|
||||||
@@ -603,8 +647,8 @@ uint16_t bvlc_handler(
|
|||||||
BACnet devices may omit the broadcast using the B/IP
|
BACnet devices may omit the broadcast using the B/IP
|
||||||
broadcast address. The method by which a BBMD determines whether
|
broadcast address. The method by which a BBMD determines whether
|
||||||
or not other BACnet devices are present is a local matter. */
|
or not other BACnet devices are present is a local matter. */
|
||||||
bvlc_broadcast_npdu(&sin, &buf[4], npdu_len);
|
bvlc_broadcast_npdu(&sin, &npdu[4], npdu_len);
|
||||||
bvlc_fdt_forward_npdu(&sin, &buf[4], npdu_len);
|
bvlc_fdt_forward_npdu(&sin, &npdu[4], npdu_len);
|
||||||
break;
|
break;
|
||||||
case BVLC_REGISTER_FOREIGN_DEVICE:
|
case BVLC_REGISTER_FOREIGN_DEVICE:
|
||||||
break;
|
break;
|
||||||
@@ -615,18 +659,20 @@ uint16_t bvlc_handler(
|
|||||||
case BVLC_DELETE_FOREIGN_DEVICE_TABLE_ENTRY:
|
case BVLC_DELETE_FOREIGN_DEVICE_TABLE_ENTRY:
|
||||||
break;
|
break;
|
||||||
case BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK:
|
case BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK:
|
||||||
bvlc_broadcast_forward_npdu(&sin, &buf[4], npdu_len);
|
bvlc_broadcast_forward_npdu(&sin, &npdu[4], npdu_len);
|
||||||
bvlc_fdt_forward_npdu(&sin, &buf[4], npdu_len);
|
bvlc_fdt_forward_npdu(&sin, &npdu[4], npdu_len);
|
||||||
break;
|
break;
|
||||||
case BVLC_ORIGINAL_UNICAST_NPDU:
|
case BVLC_ORIGINAL_UNICAST_NPDU:
|
||||||
/* ignore messages from me */
|
/* ignore messages from me */
|
||||||
if (sin.sin_addr.s_addr == BIP_Address.s_addr) {
|
if (sin.sin_addr.s_addr == htonl(bip_get_addr())) {
|
||||||
npdu_len = 0;
|
npdu_len = 0;
|
||||||
} else {
|
} else {
|
||||||
bvlc_internet_to_bacnet_address(src, &sin);
|
bvlc_internet_to_bacnet_address(src, &sin);
|
||||||
if (npdu_len < max_npdu) {
|
if (npdu_len < max_npdu) {
|
||||||
/* copy the buffer into the PDU */
|
/* shift the buffer to return a valid PDU */
|
||||||
memmove(&npdu[0], &buf[4], npdu_len);
|
for (i = 0; i < npdu_len; i++) {
|
||||||
|
npdu[i] = npdu[i+4];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* ignore packets that are too large */
|
/* ignore packets that are too large */
|
||||||
/* clients should check my max-apdu first */
|
/* clients should check my max-apdu first */
|
||||||
@@ -650,16 +696,17 @@ uint16_t bvlc_handler(
|
|||||||
the BBMD's FDT also using the BVLL Forwarded-NPDU message. */
|
the BBMD's FDT also using the BVLL Forwarded-NPDU message. */
|
||||||
bvlc_internet_to_bacnet_address(src, &sin);
|
bvlc_internet_to_bacnet_address(src, &sin);
|
||||||
if (npdu_len < max_npdu) {
|
if (npdu_len < max_npdu) {
|
||||||
/* copy the buffer into the PDU */
|
/* shift the buffer to return a valid PDU */
|
||||||
memmove(&npdu[0], &buf[4], npdu_len);
|
for (i = 0; i < npdu_len; i++) {
|
||||||
|
npdu[i] = npdu[i+4];
|
||||||
|
}
|
||||||
|
/* if BDT or FDT entries exist, Forward the NPDU */
|
||||||
|
bvlc_bdt_forward_npdu(&sin, &npdu[0], npdu_len);
|
||||||
|
bvlc_fdt_forward_npdu(&sin, &npdu[0], npdu_len);
|
||||||
} else {
|
} else {
|
||||||
/* ignore packets that are too large */
|
/* ignore packets that are too large */
|
||||||
/* clients should check my max-apdu first */
|
|
||||||
npdu_len = 0;
|
npdu_len = 0;
|
||||||
}
|
}
|
||||||
/* if BDT or FDT entries exist, Forward the NPDU */
|
|
||||||
bvlc_bdt_forward_npdu(&sin, &buf[4], npdu_len);
|
|
||||||
bvlc_fdt_forward_npdu(&sin, &buf[4], npdu_len);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -668,6 +715,58 @@ uint16_t bvlc_handler(
|
|||||||
return npdu_len;
|
return npdu_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* function to send a packet out the BACnet/IP socket (Annex J) */
|
||||||
|
/* returns number of bytes sent on success, negative number on failure */
|
||||||
|
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)
|
||||||
|
{ /* number of bytes of data */
|
||||||
|
struct sockaddr_in bvlc_dest;
|
||||||
|
uint8_t mtu[MAX_MPDU] = { 0 };
|
||||||
|
int mtu_len = 0;
|
||||||
|
int bytes_sent = 0;
|
||||||
|
|
||||||
|
/* bip datalink doesn't need to know the npdu data */
|
||||||
|
(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) {
|
||||||
|
/* broadcast */
|
||||||
|
bip_dest.sin_addr.s_addr = htonl(BIP_Broadcast_Address.s_addr);
|
||||||
|
bip_dest.sin_port = htons(BIP_Port);
|
||||||
|
memset(&(bip_dest.sin_zero), '\0', 8);
|
||||||
|
mtu[1] = BVLC_ORIGINAL_BROADCAST_NPDU;
|
||||||
|
} else if (dest->mac_len == 6) {
|
||||||
|
/* valid unicast */
|
||||||
|
(void) decode_unsigned32(&dest->mac[0],
|
||||||
|
&(bip_dest.sin_addr.s_addr));
|
||||||
|
(void) decode_unsigned16(&dest->mac[4], &(bip_dest.sin_port));
|
||||||
|
memset(&(bip_dest.sin_zero), '\0', 8);
|
||||||
|
mtu[1] = BVLC_ORIGINAL_UNICAST_NPDU;
|
||||||
|
} else {
|
||||||
|
/* invalid address */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef TEST
|
#ifdef TEST
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|||||||
+15
-6
@@ -1,6 +1,6 @@
|
|||||||
/*####COPYRIGHTBEGIN####
|
/*####COPYRIGHTBEGIN####
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
Copyright (C) 2006 Steve Karg
|
Copyright (C) 2007 Steve Karg
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
This program is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU General Public License
|
modify it under the terms of the GNU General Public License
|
||||||
@@ -34,17 +34,26 @@
|
|||||||
#ifndef BVLC_H
|
#ifndef BVLC_H
|
||||||
#define BVLC_H
|
#define BVLC_H
|
||||||
|
|
||||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
#include <stdbool.h>
|
||||||
#include <stdbool.h> /* for the standard bool type. */
|
#include <stdint.h>
|
||||||
#include "bip.h"
|
#include <stddef.h>
|
||||||
|
#include "bacdef.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
/* called from BACnet/IP handler */
|
uint16_t bvlc_receive(
|
||||||
void bvlc_handler(uint8_t * buf, int len, struct sockaddr_in *sin);
|
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_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);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-2
@@ -66,10 +66,18 @@
|
|||||||
|
|
||||||
#elif defined(BACDL_BIP)
|
#elif defined(BACDL_BIP)
|
||||||
#include "bip.h"
|
#include "bip.h"
|
||||||
|
#ifdef BBMD_ENABLED
|
||||||
|
#include "bvlc.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define datalink_init bip_init
|
#define datalink_init bip_init
|
||||||
#define datalink_send_pdu bip_send_pdu
|
#ifdef BBMD_ENABLED
|
||||||
#define datalink_receive bip_receive
|
#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_cleanup bip_cleanup
|
||||||
#define datalink_get_broadcast_address bip_get_broadcast_address
|
#define datalink_get_broadcast_address bip_get_broadcast_address
|
||||||
#define datalink_get_my_address bip_get_my_address
|
#define datalink_get_my_address bip_get_my_address
|
||||||
|
|||||||
Reference in New Issue
Block a user