Added more handling to BVLC. Still more to do.

This commit is contained in:
skarg
2007-08-11 17:18:11 +00:00
parent 75ae61d9ce
commit 89d5edba62
3 changed files with 156 additions and 40 deletions
+131 -32
View File
@@ -37,15 +37,15 @@
#include <time.h> /* for the standard bool type. */
#include "bacdcode.h"
#include "bacint.h"
#include "bvlc.h"
#include "bip.h"
#include "net.h" /* custom per port */
/* Handle the BACnet Virtual Link Control (BVLC), which includes:
BACnet Broadcast Management Device,
Broadcast Distribution Table, and
Foreign Device Registration */
typedef struct
typedef struct
{
/* true if valid entry - false if not */
bool valid;
@@ -111,11 +111,11 @@ int bvlc_encode_bip_address(
uint16_t port)
{
int len = 0;
if (pdu) {
len = encode_unsigned32(&pdu[0], address->s_addr);
len += encode_unsigned16(&pdu[len], port);
}
}
return len;
}
@@ -485,10 +485,20 @@ void bvlc_bdt_forward_npdu(
htonl(((~BBMD_Table[i].broadcast_mask.s_addr) |
BBMD_Table[i].dest_address.s_addr));
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 */
bytes_sent =
sendto(bip_socket(), (char *) mtu, mtu_len, 0,
(struct sockaddr *) &bip_dest,
(struct sockaddr *) &bip_dest,
sizeof(struct sockaddr));
}
}
@@ -501,28 +511,62 @@ void bvlc_fdt_forward_npdu(
uint8_t * npdu, /* returns 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 */
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 */
{
uint8_t buf[MAX_MPDU] = {0}; /* data */
{
uint16_t pdu_len = 0; /* return value */
fd_set read_fds;
int max;
int max = 0;
struct timeval select_timeout;
struct sockaddr_in sin = { -1 };
socklen_t sin_len = sizeof(sin);
int function_type = 0;
int received_bytes;
int received_bytes = 0;
unsigned i =0;
/* Make sure the socket is open */
if (BIP_Socket < 0) {
if (bip_socket() < 0) {
return 0;
}
@@ -538,14 +582,14 @@ uint16_t bvlc_handler(
select_timeout.tv_usec = 1000 * timeout;
}
FD_ZERO(&read_fds);
FD_SET((unsigned int) BIP_Socket, &read_fds);
max = BIP_Socket;
FD_SET((unsigned int) 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 *) &buf[0],
MAX_MPDU, 0,
bip_socket(),
(char *) &npdu[0],
max_npdu, 0,
(struct sockaddr *) &sin, &sin_len);
} else {
return 0;
@@ -562,9 +606,9 @@ uint16_t bvlc_handler(
if (buf[0] != BVLL_TYPE_BACNET_IP) {
return 0;
}
function_type = buf[1];
function_type = npdu[1];
/* 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 */
npdu_len -= 4;
switch (function_type) {
@@ -603,8 +647,8 @@ uint16_t bvlc_handler(
BACnet devices may omit the broadcast using the B/IP
broadcast address. The method by which a BBMD determines whether
or not other BACnet devices are present is a local matter. */
bvlc_broadcast_npdu(&sin, &buf[4], npdu_len);
bvlc_fdt_forward_npdu(&sin, &buf[4], npdu_len);
bvlc_broadcast_npdu(&sin, &npdu[4], npdu_len);
bvlc_fdt_forward_npdu(&sin, &npdu[4], npdu_len);
break;
case BVLC_REGISTER_FOREIGN_DEVICE:
break;
@@ -615,18 +659,20 @@ uint16_t bvlc_handler(
case BVLC_DELETE_FOREIGN_DEVICE_TABLE_ENTRY:
break;
case BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK:
bvlc_broadcast_forward_npdu(&sin, &buf[4], npdu_len);
bvlc_fdt_forward_npdu(&sin, &buf[4], npdu_len);
bvlc_broadcast_forward_npdu(&sin, &npdu[4], npdu_len);
bvlc_fdt_forward_npdu(&sin, &npdu[4], npdu_len);
break;
case BVLC_ORIGINAL_UNICAST_NPDU:
/* 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;
} else {
bvlc_internet_to_bacnet_address(src, &sin);
if (npdu_len < max_npdu) {
/* copy the buffer into the PDU */
memmove(&npdu[0], &buf[4], npdu_len);
/* shift the buffer to return a valid PDU */
for (i = 0; i < npdu_len; i++) {
npdu[i] = npdu[i+4];
}
} else {
/* ignore packets that are too large */
/* 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. */
bvlc_internet_to_bacnet_address(src, &sin);
if (npdu_len < max_npdu) {
/* copy the buffer into the PDU */
memmove(&npdu[0], &buf[4], npdu_len);
/* shift the buffer to return a valid PDU */
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 {
/* ignore packets that are too large */
/* clients should check my max-apdu first */
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;
default:
break;
@@ -668,6 +715,58 @@ uint16_t bvlc_handler(
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
#include <assert.h>
#include <string.h>
+15 -6
View File
@@ -1,6 +1,6 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2006 Steve Karg
Copyright (C) 2007 Steve Karg
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@@ -34,17 +34,26 @@
#ifndef BVLC_H
#define BVLC_H
#include <stdint.h> /* for standard integer types uint8_t etc. */
#include <stdbool.h> /* for the standard bool type. */
#include "bip.h"
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include "bacdef.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* called from BACnet/IP handler */
void bvlc_handler(uint8_t * buf, int len, struct sockaddr_in *sin);
uint16_t bvlc_receive(
BACNET_ADDRESS * src, /* returns the source address */
uint8_t * npdu, /* returns the NPDU */
uint16_t max_npdu, /* amount of space available in the NPDU */
unsigned timeout); /* number of milliseconds to wait for a packet */
int bvlc_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
}
+10 -2
View File
@@ -66,10 +66,18 @@
#elif defined(BACDL_BIP)
#include "bip.h"
#ifdef BBMD_ENABLED
#include "bvlc.h"
#endif
#define datalink_init bip_init
#define datalink_send_pdu bip_send_pdu
#define datalink_receive bip_receive
#ifdef 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
#define datalink_get_my_address bip_get_my_address