update LwIP BACnet/IP abstraction (#246)
* update LwIP BACnet/IP abstraction. Integrate LwIP build with continuous integration. Co-authored-by: Steve Karg <skarg@users.sourceforge.net>
This commit is contained in:
@@ -168,6 +168,19 @@ jobs:
|
|||||||
make atmega168
|
make atmega168
|
||||||
make bdk-atxx4-mstp
|
make bdk-atxx4-mstp
|
||||||
|
|
||||||
|
ports-lwip:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Create Build Environment
|
||||||
|
run: |
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -qq build-essential
|
||||||
|
sudo apt-get install -qq liblwip-dev
|
||||||
|
- name: ports-lwip
|
||||||
|
run: |
|
||||||
|
make lwip
|
||||||
|
|
||||||
mingw:
|
mingw:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -191,6 +191,10 @@ stm32f4xx-clean: ports/stm32f4xx/Makefile
|
|||||||
mstpsnap: ports/linux/mstpsnap.mak
|
mstpsnap: ports/linux/mstpsnap.mak
|
||||||
$(MAKE) -s -C ports/linux -f mstpsnap.mak clean all
|
$(MAKE) -s -C ports/linux -f mstpsnap.mak clean all
|
||||||
|
|
||||||
|
.PHONY: lwip
|
||||||
|
lwip: ports/lwip/Makefile
|
||||||
|
$(MAKE) -s -C ports/lwip clean all
|
||||||
|
|
||||||
.PHONY: pretty
|
.PHONY: pretty
|
||||||
pretty:
|
pretty:
|
||||||
find ./src -iname *.h -o -iname *.c -exec \
|
find ./src -iname *.h -o -iname *.c -exec \
|
||||||
@@ -252,6 +256,7 @@ clean: ports-clean
|
|||||||
$(MAKE) -s -C apps/router-ipv6 clean
|
$(MAKE) -s -C apps/router-ipv6 clean
|
||||||
$(MAKE) -s -C apps/router-mstp clean
|
$(MAKE) -s -C apps/router-mstp clean
|
||||||
$(MAKE) -s -C apps/gateway clean
|
$(MAKE) -s -C apps/gateway clean
|
||||||
|
$(MAKE) -s -C ports/lwip clean
|
||||||
$(MAKE) -s -C test clean
|
$(MAKE) -s -C test clean
|
||||||
rm -rf ./build
|
rm -rf ./build
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# Makefile to build BACnet/IP LwIP library
|
||||||
|
|
||||||
|
# Executable file name
|
||||||
|
TARGET = bip-lwip
|
||||||
|
|
||||||
|
SRC = bip.c
|
||||||
|
|
||||||
|
BACNET_DIR = ../../src
|
||||||
|
LWIP_DIR = /usr/include/lwip
|
||||||
|
|
||||||
|
CFLAGS += -I$(LWIP_DIR) -I$(BACNET_DIR)
|
||||||
|
|
||||||
|
OBJS += ${SRC:.c=.o}
|
||||||
|
|
||||||
|
all: Makefile $(TARGET)
|
||||||
|
|
||||||
|
lib: $(TARGET)
|
||||||
|
|
||||||
|
$(TARGET): $(OBJS) Makefile
|
||||||
|
${AR} rcs $@ $(OBJS)
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
${CC} -c ${CFLAGS} $*.c -o $@
|
||||||
|
|
||||||
|
.PHONY: depend
|
||||||
|
depend:
|
||||||
|
rm -f .depend
|
||||||
|
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
-rm -f core ${TARGET} ${OBJS} $(TARGET).map
|
||||||
|
|
||||||
|
.PHONY: include
|
||||||
|
include: .depend
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 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 BACPORT_H
|
||||||
|
#define BACPORT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "lwip/def.h"
|
||||||
|
#include "lwip/udp.h"
|
||||||
|
#include "lwip/memp.h"
|
||||||
|
#include "netif/etharp.h"
|
||||||
|
#include "lwip/dhcp.h"
|
||||||
|
#include "lwip/inet.h"
|
||||||
|
|
||||||
|
#endif
|
||||||
+154
-212
@@ -39,17 +39,17 @@
|
|||||||
#include "bacnet/datalink/bip.h"
|
#include "bacnet/datalink/bip.h"
|
||||||
#include "bacnet/datalink/bvlc.h"
|
#include "bacnet/datalink/bvlc.h"
|
||||||
#include "bacnet/basic/services.h"
|
#include "bacnet/basic/services.h"
|
||||||
|
#include "bacnet/basic/bbmd/h_bbmd.h"
|
||||||
#include "bacport.h" /* custom per port */
|
#include "bacport.h" /* custom per port */
|
||||||
|
|
||||||
/** @file bip.c Configuration and Operations for BACnet/IP */
|
/** @file bip.c Configuration and Operations for BACnet/IP */
|
||||||
|
|
||||||
/* port to use - stored in network byte order */
|
/* port to use - stored in network byte order */
|
||||||
static uint16_t BIP_Port = 0xBAC0U;
|
|
||||||
static bool BIP_Port_Changed;
|
static bool BIP_Port_Changed;
|
||||||
/* IP Address - stored in network byte order */
|
/* IP Address */
|
||||||
static struct in_addr BIP_Address;
|
static BACNET_IP_ADDRESS BIP_Address;
|
||||||
/* Broadcast Address - stored in network byte order */
|
/* Broadcast Address */
|
||||||
static struct in_addr BIP_Broadcast_Address;
|
static BACNET_IP_ADDRESS BIP_Broadcast_Address;
|
||||||
/* lwIP socket, of sorts */
|
/* lwIP socket, of sorts */
|
||||||
static struct udp_pcb *Server_upcb;
|
static struct udp_pcb *Server_upcb;
|
||||||
/* track packets for diagnostics */
|
/* track packets for diagnostics */
|
||||||
@@ -61,41 +61,71 @@ struct bacnet_stats {
|
|||||||
struct bacnet_stats BIP_Stats;
|
struct bacnet_stats BIP_Stats;
|
||||||
#define BIP_STATS_INC(x) ++BIP_Stats.x
|
#define BIP_STATS_INC(x) ++BIP_Stats.x
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the BACnet/IP transmit stats
|
||||||
|
* @return number of BACnet/IP transmitted packets
|
||||||
|
*/
|
||||||
uint32_t bip_stats_xmit(void)
|
uint32_t bip_stats_xmit(void)
|
||||||
{
|
{
|
||||||
return BIP_Stats.xmit;
|
return BIP_Stats.xmit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the BACnet/IP received stats
|
||||||
|
* @return number of BACnet/IP received packets
|
||||||
|
*/
|
||||||
uint32_t bip_stats_recv(void)
|
uint32_t bip_stats_recv(void)
|
||||||
{
|
{
|
||||||
return BIP_Stats.recv;
|
return BIP_Stats.recv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the BACnet/IP drop stats
|
||||||
|
* @return number of BACnet/IP drops
|
||||||
|
*/
|
||||||
uint32_t bip_stats_drop(void)
|
uint32_t bip_stats_drop(void)
|
||||||
{
|
{
|
||||||
return BIP_Stats.drop;
|
return BIP_Stats.drop;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bip_set_addr(uint32_t net_address)
|
/**
|
||||||
{ /* in network byte order */
|
* @brief Set the BACnet/IP address
|
||||||
BIP_Address.s_addr = net_address;
|
* @param addr - network IPv4 address
|
||||||
}
|
* @return true if the address is set
|
||||||
|
*/
|
||||||
/* returns network byte order */
|
bool bip_set_addr(BACNET_IP_ADDRESS *addr)
|
||||||
uint32_t bip_get_addr(void)
|
|
||||||
{
|
{
|
||||||
return BIP_Address.s_addr;
|
return bvlc_address_copy(&BIP_Address, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bip_set_broadcast_addr(uint32_t net_address)
|
/**
|
||||||
{ /* in network byte order */
|
* @brief Get the BACnet/IP address
|
||||||
BIP_Broadcast_Address.s_addr = net_address;
|
* @param network IPv4 address
|
||||||
}
|
* @return true if the address is set
|
||||||
|
*/
|
||||||
/* returns network byte order */
|
bool bip_get_addr(BACNET_IP_ADDRESS *addr)
|
||||||
uint32_t bip_get_broadcast_addr(void)
|
|
||||||
{
|
{
|
||||||
return BIP_Broadcast_Address.s_addr;
|
return bvlc_address_copy(addr, &BIP_Address);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the BACnet/IP broadcast address
|
||||||
|
* @param network IPv4 broadcast address
|
||||||
|
* @return true if the broadcast address is retrieved
|
||||||
|
*/
|
||||||
|
bool bip_set_broadcast_addr(BACNET_IP_ADDRESS *addr)
|
||||||
|
{
|
||||||
|
return bvlc_address_copy(&BIP_Broadcast_Address, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the BACnet/IP broadcast address
|
||||||
|
* @param network IPv4 broadcast address
|
||||||
|
* @return true if the broadcast address is set
|
||||||
|
*/
|
||||||
|
bool bip_get_broadcast_addr(BACNET_IP_ADDRESS *addr)
|
||||||
|
{
|
||||||
|
return bvlc_address_copy(addr, &BIP_Broadcast_Address);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -104,24 +134,36 @@ uint32_t bip_get_broadcast_addr(void)
|
|||||||
*/
|
*/
|
||||||
void bip_set_port(uint16_t port)
|
void bip_set_port(uint16_t port)
|
||||||
{
|
{
|
||||||
if (BIP_Port != htons(port)) {
|
if (BIP_Address.port != htons(port)) {
|
||||||
BIP_Port_Changed = true;
|
BIP_Port_Changed = true;
|
||||||
BIP_Port = htons(port);
|
BIP_Address.port = htons(port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Determine if the BACnet IPv4 UDP port number changed
|
||||||
|
* @return true of the BACnet IPv4 UDP port number changed
|
||||||
|
*/
|
||||||
bool bip_port_changed(void)
|
bool bip_port_changed(void)
|
||||||
{
|
{
|
||||||
return BIP_Port_Changed;
|
return BIP_Port_Changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns host byte order */
|
/**
|
||||||
|
* @brief Get the BACnet IPv4 UDP port number
|
||||||
|
* @return IPv4 UDP port number - in host byte order
|
||||||
|
*/
|
||||||
uint16_t bip_get_port(void)
|
uint16_t bip_get_port(void)
|
||||||
{
|
{
|
||||||
return ntohs(BIP_Port);
|
return ntohs(BIP_Address.port);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bip_mac_to_addr(struct ip_addr *address, uint8_t *mac)
|
/**
|
||||||
|
* @brief Convert the BACnet IPv4 address
|
||||||
|
* @param address - IPv4 address from LwIP
|
||||||
|
* @param mac - IP address from BACnet/IP
|
||||||
|
*/
|
||||||
|
static void bip_mac_to_addr(ip4_addr_t *address, uint8_t *mac)
|
||||||
{
|
{
|
||||||
if (mac && address) {
|
if (mac && address) {
|
||||||
address->addr = ((u32_t)((((uint32_t)mac[0]) << 24) & 0xff000000));
|
address->addr = ((u32_t)((((uint32_t)mac[0]) << 24) & 0xff000000));
|
||||||
@@ -131,7 +173,34 @@ static void bip_mac_to_addr(struct ip_addr *address, uint8_t *mac)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bip_addr_to_mac(uint8_t *mac, struct ip_addr *address)
|
/**
|
||||||
|
* @brief Convert from a BACnet/IP address
|
||||||
|
* @param baddr - BACnet/IP address
|
||||||
|
* @param address - IPv4 address from LwIP
|
||||||
|
* @param port - IPv4 UDP port number
|
||||||
|
*/
|
||||||
|
static int bip_decode_bip_address(BACNET_IP_ADDRESS *baddr,
|
||||||
|
ip_addr_t *address,
|
||||||
|
uint16_t *port)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
if (baddr && address && port) {
|
||||||
|
address->type = IPADDR_TYPE_V4;
|
||||||
|
bip_mac_to_addr(&address->u_addr.ip4, &baddr->address[0]);
|
||||||
|
*port = baddr->port;
|
||||||
|
len = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert the BACnet IPv4 address
|
||||||
|
* @param mac - IP address from BACnet/IP
|
||||||
|
* @param address - IPv4 address from LwIP
|
||||||
|
*/
|
||||||
|
static void bip_addr_to_mac(uint8_t *mac, const ip4_addr_t *address)
|
||||||
{
|
{
|
||||||
if (mac && address) {
|
if (mac && address) {
|
||||||
mac[0] = (uint8_t)(address->addr >> 24);
|
mac[0] = (uint8_t)(address->addr >> 24);
|
||||||
@@ -141,16 +210,24 @@ static void bip_addr_to_mac(uint8_t *mac, struct ip_addr *address)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bip_decode_bip_address(BACNET_ADDRESS *bac_addr,
|
/**
|
||||||
struct ip_addr *address, /* in network format */
|
* @brief Convert to a BACnet/IP address
|
||||||
uint16_t *port)
|
* @param baddr - BACnet/IP address
|
||||||
{ /* in network format */
|
* @param address - IPv4 address from LwIP
|
||||||
|
* @param port - IPv4 UDP port number
|
||||||
|
*/
|
||||||
|
static int bip_encode_bip_address(BACNET_IP_ADDRESS *baddr,
|
||||||
|
const ip_addr_t *address,
|
||||||
|
uint16_t port)
|
||||||
|
{
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
|
||||||
if (bac_addr) {
|
if (baddr && address) {
|
||||||
bip_mac_to_addr(address, &bac_addr->mac[0]);
|
if (address->type == IPADDR_TYPE_V4) {
|
||||||
memcpy(port, &bac_addr->mac[4], 2);
|
bip_addr_to_mac(&baddr->address[0], &address->u_addr.ip4);
|
||||||
len = 6;
|
baddr->port = port;
|
||||||
|
len = 6;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
@@ -159,26 +236,35 @@ static int bip_decode_bip_address(BACNET_ADDRESS *bac_addr,
|
|||||||
/** Function to send a packet out the BACnet/IP socket (Annex J).
|
/** Function to send a packet out the BACnet/IP socket (Annex J).
|
||||||
* @ingroup DLBIP
|
* @ingroup DLBIP
|
||||||
*
|
*
|
||||||
* @param dst_ip [in] Destination address
|
* @param dest [in] Destination address
|
||||||
* @param port [in] UDP port number
|
* @param port [in] UDP port number
|
||||||
* @param pkt [in] PBUF packet
|
* @param mtu_len [in] PBUF packet
|
||||||
*
|
* @return number of bytes sent, or 0 on failure.
|
||||||
* @return true if the packet was sent
|
|
||||||
*/
|
*/
|
||||||
static bool bip_send_mpdu(
|
int bip_send_mpdu(
|
||||||
struct ip_addr *dst_ip, uint16_t port, struct pbuf *pkt)
|
BACNET_IP_ADDRESS *dest, uint8_t *mtu, uint16_t mtu_len)
|
||||||
{
|
{
|
||||||
|
struct pbuf *pkt = NULL;
|
||||||
|
/* addr and port in host format */
|
||||||
|
ip_addr_t dst_ip;
|
||||||
|
uint16_t port = 0;
|
||||||
err_t status = ERR_OK;
|
err_t status = ERR_OK;
|
||||||
|
|
||||||
/* Send the packet */
|
pkt = pbuf_alloc(PBUF_TRANSPORT, mtu_len, PBUF_POOL);
|
||||||
status = udp_sendto(Server_upcb, pkt, dst_ip, port);
|
if (pkt == NULL) {
|
||||||
/* free the buffer pbuf */
|
return 0;
|
||||||
pbuf_free(pkt);
|
}
|
||||||
|
bip_decode_bip_address(dest, &dst_ip, &port);
|
||||||
|
pbuf_take(pkt, mtu, mtu_len);
|
||||||
|
status = udp_sendto(Server_upcb, pkt, &dst_ip, port);
|
||||||
if (status == ERR_OK) {
|
if (status == ERR_OK) {
|
||||||
BIP_STATS_INC(xmit);
|
BIP_STATS_INC(xmit);
|
||||||
|
} else {
|
||||||
|
mtu_len = 0;
|
||||||
}
|
}
|
||||||
|
pbuf_free(pkt);
|
||||||
|
|
||||||
return (status == ERR_OK);
|
return mtu_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Send the Original Broadcast or Unicast messages
|
/** Send the Original Broadcast or Unicast messages
|
||||||
@@ -195,77 +281,7 @@ int bip_send_pdu(BACNET_ADDRESS *dest, /* destination address */
|
|||||||
uint8_t *pdu, /* any data to be sent - may be null */
|
uint8_t *pdu, /* any data to be sent - may be null */
|
||||||
unsigned pdu_len)
|
unsigned pdu_len)
|
||||||
{
|
{
|
||||||
struct pbuf *pkt = NULL, *pkt0 = NULL;
|
return bvlc_send_pdu(dest, npdu_data, pdu, pdu_len);
|
||||||
uint8_t mtu[4] = { 0 };
|
|
||||||
int mtu_len = 0;
|
|
||||||
/* addr and port in host format */
|
|
||||||
struct ip_addr dst_ip;
|
|
||||||
uint16_t port = 0;
|
|
||||||
err_t status = ERR_OK;
|
|
||||||
|
|
||||||
pkt0 = pbuf_alloc(PBUF_TRANSPORT, 4, PBUF_POOL);
|
|
||||||
if (pkt0 == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
pkt = pbuf_alloc(PBUF_TRANSPORT, pdu_len, PBUF_POOL);
|
|
||||||
if (pkt == NULL) {
|
|
||||||
pbuf_free(pkt0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
mtu[0] = BVLL_TYPE_BACNET_IP;
|
|
||||||
if (dest->net == BACNET_BROADCAST_NETWORK) {
|
|
||||||
/* broadcast */
|
|
||||||
dst_ip.addr = BIP_Broadcast_Address.s_addr;
|
|
||||||
port = BIP_Port;
|
|
||||||
mtu[1] = BVLC_ORIGINAL_BROADCAST_NPDU;
|
|
||||||
} else if (dest->mac_len == 6) {
|
|
||||||
/* unicast */
|
|
||||||
bip_decode_bip_address(dest, &dst_ip, &port);
|
|
||||||
mtu[1] = BVLC_ORIGINAL_UNICAST_NPDU;
|
|
||||||
} else {
|
|
||||||
/* invalid address */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
mtu_len = pdu_len + 4 /*inclusive */;
|
|
||||||
encode_unsigned16(&mtu[2], mtu_len);
|
|
||||||
pbuf_take(pkt0, mtu, 4);
|
|
||||||
pbuf_take(pkt, pdu, pdu_len);
|
|
||||||
pbuf_cat(pkt0, pkt);
|
|
||||||
status = bip_send_mpdu(&dst_ip, port, pkt0);
|
|
||||||
if (!status) {
|
|
||||||
mtu_len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mtu_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Send the BVLC Result message
|
|
||||||
*
|
|
||||||
* @param addr [in] Destination address
|
|
||||||
* @param result_code - BVLC result code
|
|
||||||
*
|
|
||||||
* @return number of bytes encoded
|
|
||||||
*/
|
|
||||||
static bool bvlc_send_result(struct ip_addr *addr, uint16_t result_code)
|
|
||||||
{
|
|
||||||
struct pbuf *pkt = NULL;
|
|
||||||
uint8_t mtu[6] = { 0 };
|
|
||||||
uint16_t mtu_len = 6;
|
|
||||||
|
|
||||||
pkt = pbuf_alloc(PBUF_TRANSPORT, mtu_len, PBUF_POOL);
|
|
||||||
if (pkt == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
mtu[0] = BVLL_TYPE_BACNET_IP;
|
|
||||||
mtu[1] = BVLC_RESULT;
|
|
||||||
/* The 2-octet BVLC Length field is the length, in octets,
|
|
||||||
of the entire BVLL message, including the two octets of the
|
|
||||||
length field itself, most significant octet first. */
|
|
||||||
encode_unsigned16(&mtu[2], 6);
|
|
||||||
encode_unsigned16(&mtu[4], result_code);
|
|
||||||
pbuf_take(pkt, mtu, mtu_len);
|
|
||||||
|
|
||||||
return bip_send_mpdu(addr, BIP_Port, pkt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** LwIP BACnet service callback
|
/** LwIP BACnet service callback
|
||||||
@@ -279,99 +295,24 @@ static bool bvlc_send_result(struct ip_addr *addr, uint16_t result_code)
|
|||||||
void bip_server_callback(void *arg,
|
void bip_server_callback(void *arg,
|
||||||
struct udp_pcb *upcb,
|
struct udp_pcb *upcb,
|
||||||
struct pbuf *pkt,
|
struct pbuf *pkt,
|
||||||
struct ip_addr *addr,
|
const ip_addr_t *addr,
|
||||||
u16_t port)
|
u16_t port)
|
||||||
{
|
{
|
||||||
uint8_t function = 0;
|
uint8_t function = 0;
|
||||||
uint16_t pdu_len = 0;
|
uint16_t npdu_offset = 0;
|
||||||
uint16_t pdu_offset = 0;
|
|
||||||
BACNET_ADDRESS src = { 0 }; /* address where message came from */
|
BACNET_ADDRESS src = { 0 }; /* address where message came from */
|
||||||
struct ip_addr sin_addr;
|
BACNET_IP_ADDRESS saddr;
|
||||||
uint16_t sin_port = 0;
|
uint8_t *npdu = (uint8_t *) pkt->payload;
|
||||||
uint8_t *pdu = (uint8_t *)pkt->payload;
|
uint16_t npdu_len = pkt->tot_len;
|
||||||
|
|
||||||
/* the signature of a BACnet/IP packet */
|
bip_encode_bip_address(&saddr, addr, port);
|
||||||
if ((pkt->tot_len >= 2) &&
|
npdu_offset = bvlc_handler(&saddr, &src, npdu, npdu_len);
|
||||||
(pdu[0] == BVLL_TYPE_BACNET_IP)) {
|
if (npdu_offset > 0) {
|
||||||
function = pdu[1];
|
BIP_STATS_INC(recv);
|
||||||
if ((function == BVLC_ORIGINAL_UNICAST_NPDU) ||
|
npdu_len -= npdu_offset;
|
||||||
(function == BVLC_ORIGINAL_BROADCAST_NPDU)) {
|
npdu_handler(&src, &npdu[npdu_offset], npdu_len);
|
||||||
/* ignore messages from me */
|
} else {
|
||||||
if ((addr->addr == BIP_Address.s_addr) && (port == BIP_Port)) {
|
BIP_STATS_INC(drop);
|
||||||
pdu_len = 0;
|
|
||||||
} else if (pkt->tot_len >= 4) {
|
|
||||||
/* data in src->mac[] is in network format */
|
|
||||||
src.mac_len = 6;
|
|
||||||
bip_addr_to_mac(&src.mac[0], addr);
|
|
||||||
memcpy(&src.mac[4], &port, 2);
|
|
||||||
/* decode the length of the PDU
|
|
||||||
length is inclusive of BVLC */
|
|
||||||
(void)decode_unsigned16(&pdu[2], &pdu_len);
|
|
||||||
if (pdu_len > pkt->tot_len) {
|
|
||||||
/* BVLC length is too long - someone is lying */
|
|
||||||
pdu_len = 0;
|
|
||||||
} else {
|
|
||||||
/* subtract off the BVLC header */
|
|
||||||
pdu_len -= 4;
|
|
||||||
pdu_offset = 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (function == BVLC_FORWARDED_NPDU) {
|
|
||||||
if (pkt->tot_len >= 10) {
|
|
||||||
IP4_ADDR(&sin_addr, pdu[4], pdu[5], pdu[6], pdu[7]);
|
|
||||||
decode_unsigned16(&pdu[8], &sin_port);
|
|
||||||
if ((sin_addr.addr == BIP_Address.s_addr) &&
|
|
||||||
(sin_port == BIP_Port)) {
|
|
||||||
/* ignore forwarded messages from me */
|
|
||||||
pdu_len = 0;
|
|
||||||
} else {
|
|
||||||
/* data in src->mac[] is in network format */
|
|
||||||
src.mac_len = 6;
|
|
||||||
bip_addr_to_mac(&src.mac[0], &sin_addr);
|
|
||||||
memcpy(&src.mac[4], &sin_port, 2);
|
|
||||||
/* decode the length of the PDU
|
|
||||||
length is inclusive of BVLC */
|
|
||||||
(void)decode_unsigned16(&pdu[2], &pdu_len);
|
|
||||||
if (pdu_len > pkt->tot_len) {
|
|
||||||
/* BVLC length is too long - someone is lying */
|
|
||||||
pdu_len = 0;
|
|
||||||
} else {
|
|
||||||
/* subtract off the BVLC header */
|
|
||||||
pdu_len -= 10;
|
|
||||||
pdu_offset = 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (function == BVLC_WRITE_BROADCAST_DISTRIBUTION_TABLE) {
|
|
||||||
bvlc_send_result(
|
|
||||||
addr, BVLC_RESULT_WRITE_BROADCAST_DISTRIBUTION_TABLE_NAK);
|
|
||||||
} else if (function == BVLC_READ_BROADCAST_DIST_TABLE) {
|
|
||||||
bvlc_send_result(
|
|
||||||
addr, BVLC_RESULT_READ_BROADCAST_DISTRIBUTION_TABLE_NAK);
|
|
||||||
} else if (function == BVLC_REGISTER_FOREIGN_DEVICE) {
|
|
||||||
bvlc_send_result(addr, BVLC_RESULT_REGISTER_FOREIGN_DEVICE_NAK);
|
|
||||||
} else if (function == BVLC_READ_FOREIGN_DEVICE_TABLE) {
|
|
||||||
bvlc_send_result(addr, BVLC_RESULT_READ_FOREIGN_DEVICE_TABLE_NAK);
|
|
||||||
} else if (function == BVLC_DELETE_FOREIGN_DEVICE_TABLE_ENTRY) {
|
|
||||||
bvlc_send_result(
|
|
||||||
addr, BVLC_RESULT_DELETE_FOREIGN_DEVICE_TABLE_ENTRY_NAK);
|
|
||||||
} else if (function == BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK) {
|
|
||||||
bvlc_send_result(addr, BVLC_RESULT_DISTRIBUTE_BROADCAST_TO_NETWORK_NAK);
|
|
||||||
}
|
|
||||||
if (pdu_len) {
|
|
||||||
BIP_STATS_INC(recv);
|
|
||||||
if ((function == BVLC_ORIGINAL_BROADCAST_NPDU) &&
|
|
||||||
(npdu_confirmed_service(&pdu[pdu_offset], pdu_len))) {
|
|
||||||
/* BTL test: verifies that the IUT will quietly discard any
|
|
||||||
Confirmed-Request-PDU, whose destination address is a
|
|
||||||
multicast or broadcast address, received from the
|
|
||||||
network layer. */
|
|
||||||
} else {
|
|
||||||
npdu_handler(&src, &pdu[pdu_offset], pdu_len);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
BIP_STATS_INC(rxdrop);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/* free our packet */
|
/* free our packet */
|
||||||
pbuf_free(pkt);
|
pbuf_free(pkt);
|
||||||
@@ -383,8 +324,8 @@ void bip_get_my_address(BACNET_ADDRESS *my_address)
|
|||||||
|
|
||||||
if (my_address) {
|
if (my_address) {
|
||||||
my_address->mac_len = 6;
|
my_address->mac_len = 6;
|
||||||
memcpy(&my_address->mac[0], &BIP_Address.s_addr, 4);
|
memcpy(&my_address->mac[0], &BIP_Address.address, 4);
|
||||||
memcpy(&my_address->mac[4], &BIP_Port, 2);
|
memcpy(&my_address->mac[4], &BIP_Address.port, 2);
|
||||||
my_address->net = 0; /* local only, no routing */
|
my_address->net = 0; /* local only, no routing */
|
||||||
my_address->len = 0; /* no SLEN */
|
my_address->len = 0; /* no SLEN */
|
||||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||||
@@ -402,8 +343,8 @@ void bip_get_broadcast_address(BACNET_ADDRESS *dest)
|
|||||||
|
|
||||||
if (dest) {
|
if (dest) {
|
||||||
dest->mac_len = 6;
|
dest->mac_len = 6;
|
||||||
memcpy(&dest->mac[0], &BIP_Broadcast_Address.s_addr, 4);
|
memcpy(&dest->mac[0], &BIP_Broadcast_Address.address, 4);
|
||||||
memcpy(&dest->mac[4], &BIP_Port, 2);
|
memcpy(&dest->mac[4], &BIP_Address.port, 2);
|
||||||
dest->net = BACNET_BROADCAST_NETWORK;
|
dest->net = BACNET_BROADCAST_NETWORK;
|
||||||
dest->len = 0; /* no SLEN */
|
dest->len = 0; /* no SLEN */
|
||||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||||
@@ -438,12 +379,13 @@ bool bip_init(char *ifname)
|
|||||||
/* Create a new UDP control block */
|
/* Create a new UDP control block */
|
||||||
Server_upcb = udp_new();
|
Server_upcb = udp_new();
|
||||||
if (Server_upcb == NULL) {
|
if (Server_upcb == NULL) {
|
||||||
/* increase MEMP_NUM_UDP_PCB in lwipopts.h */
|
while (1) {
|
||||||
while (1) { };
|
/* fixme: increase MEMP_NUM_UDP_PCB in lwipopts.h */
|
||||||
|
};
|
||||||
}
|
}
|
||||||
/* Bind the upcb to the UDP_PORT port */
|
/* Bind the upcb to the UDP_PORT port */
|
||||||
/* Using IP_ADDR_ANY allow the upcb to be used by any local interface */
|
/* Using IP_ADDR_ANY allow the upcb to be used by any local interface */
|
||||||
udp_bind(Server_upcb, IP_ADDR_ANY, BIP_Port);
|
udp_bind(Server_upcb, IP_ADDR_ANY, BIP_Address.port);
|
||||||
/* Set a receive callback for the upcb */
|
/* Set a receive callback for the upcb */
|
||||||
udp_recv(Server_upcb, bip_server_callback, NULL);
|
udp_recv(Server_upcb, bip_server_callback, NULL);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user