Changed BACnet/IP to use only one socket to make the src port of sent messages have the 0xBAC0 port number instead of some random port number. The src port on I-Am messages is used to store the MAC address.
This commit is contained in:
@@ -38,7 +38,7 @@
|
|||||||
#include "bip.h"
|
#include "bip.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
|
|
||||||
static int BIP_Receive_Socket = -1;
|
static int BIP_Socket = -1;
|
||||||
/* port to use - stored in network byte order */
|
/* port to use - stored in network byte order */
|
||||||
static uint16_t BIP_Port = 0;
|
static uint16_t BIP_Port = 0;
|
||||||
/* IP Address - stored in network byte order */
|
/* IP Address - stored in network byte order */
|
||||||
@@ -48,14 +48,14 @@ static struct in_addr BIP_Broadcast_Address;
|
|||||||
|
|
||||||
bool bip_valid(void)
|
bool bip_valid(void)
|
||||||
{
|
{
|
||||||
return (BIP_Receive_Socket != -1);
|
return (BIP_Socket != -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bip_cleanup(void)
|
void bip_cleanup(void)
|
||||||
{
|
{
|
||||||
if (bip_valid())
|
if (bip_valid())
|
||||||
close(BIP_Receive_Socket);
|
close(BIP_Socket);
|
||||||
BIP_Receive_Socket = -1;
|
BIP_Socket = -1;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -101,28 +101,47 @@ void bip_set_port(uint16_t port)
|
|||||||
|
|
||||||
bool bip_init(void)
|
bool bip_init(void)
|
||||||
{
|
{
|
||||||
int rv = 0; // return from socket lib calls
|
int status = 0; // return from socket lib calls
|
||||||
struct sockaddr_in sin;
|
struct sockaddr_in sin;
|
||||||
|
int sockopt = 0;
|
||||||
|
|
||||||
/* configure standard BACnet/IP receive port */
|
/* configure standard BACnet/IP receive port */
|
||||||
bip_set_port(0xBAC0);
|
bip_set_port(0xBAC0);
|
||||||
|
|
||||||
// assumes that the driver has already been initialized
|
// assumes that the driver has already been initialized
|
||||||
BIP_Receive_Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
BIP_Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
if (BIP_Receive_Socket < 0)
|
if (BIP_Socket < 0)
|
||||||
return false;
|
return false;
|
||||||
|
// Allow us to use the same socket for sending and receiving
|
||||||
|
// This makes sure that the src port is correct when sending
|
||||||
|
sockopt = 1;
|
||||||
|
status = setsockopt(BIP_Socket, SOL_SOCKET, SO_REUSEADDR,
|
||||||
|
&sockopt, sizeof(sockopt));
|
||||||
|
if (status < 0)
|
||||||
|
{
|
||||||
|
close(BIP_Socket);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
// allow us to send a broadcast
|
||||||
|
status = setsockopt(BIP_Socket, SOL_SOCKET, SO_BROADCAST,
|
||||||
|
&sockopt, sizeof(sockopt));
|
||||||
|
if (status < 0)
|
||||||
|
{
|
||||||
|
close(BIP_Socket);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
// bind the socket to the local port number and IP address
|
// bind the socket to the local port number and IP address
|
||||||
sin.sin_family = AF_INET;
|
sin.sin_family = AF_INET;
|
||||||
sin.sin_addr.s_addr = htonl(INADDR_ANY);
|
sin.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
sin.sin_port = BIP_Port;
|
sin.sin_port = BIP_Port;
|
||||||
memset(&(sin.sin_zero), '\0', 8);
|
memset(&(sin.sin_zero), '\0', 8);
|
||||||
rv = bind(BIP_Receive_Socket,
|
status = bind(BIP_Socket,
|
||||||
(const struct sockaddr*)&sin, sizeof(struct sockaddr));
|
(const struct sockaddr*)&sin, sizeof(struct sockaddr));
|
||||||
if (rv < 0)
|
if (status < 0)
|
||||||
{
|
{
|
||||||
close(BIP_Receive_Socket);
|
close(BIP_Socket);
|
||||||
BIP_Receive_Socket = -1;
|
BIP_Socket = -1;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,26 +155,13 @@ static int bip_send(
|
|||||||
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) // number of bytes of data
|
unsigned pdu_len) // number of bytes of data
|
||||||
{
|
{
|
||||||
int bip_send_socket = -1;
|
|
||||||
uint8_t mtu[MAX_MPDU] = { 0 };
|
uint8_t mtu[MAX_MPDU] = { 0 };
|
||||||
int mtu_len = 0;
|
int mtu_len = 0;
|
||||||
int bytes_sent = 0;
|
int bytes_sent = 0;
|
||||||
int status = 0;
|
|
||||||
int sockopt = 0;
|
|
||||||
|
|
||||||
// assumes that the driver has already been initialized
|
// assumes that the driver has already been initialized
|
||||||
bip_send_socket = socket(AF_INET, SOCK_DGRAM, 0);
|
if (BIP_Socket < 0)
|
||||||
if (bip_send_socket < 0)
|
return BIP_Socket;
|
||||||
return bip_send_socket;
|
|
||||||
// allow us to do a broadcast if necessary
|
|
||||||
sockopt = 1;
|
|
||||||
status = setsockopt(bip_send_socket, SOL_SOCKET, SO_BROADCAST,
|
|
||||||
&sockopt, sizeof(sockopt));
|
|
||||||
if (status < 0)
|
|
||||||
{
|
|
||||||
close(bip_send_socket);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
mtu[0] = 0x81; /* BVLL for BACnet/IP */
|
mtu[0] = 0x81; /* BVLL for BACnet/IP */
|
||||||
if (bip_dest->sin_addr.s_addr == BIP_Broadcast_Address.s_addr)
|
if (bip_dest->sin_addr.s_addr == BIP_Broadcast_Address.s_addr)
|
||||||
@@ -168,12 +174,10 @@ static int bip_send(
|
|||||||
mtu_len += pdu_len;
|
mtu_len += pdu_len;
|
||||||
|
|
||||||
/* Send the packet */
|
/* Send the packet */
|
||||||
bytes_sent = sendto(bip_send_socket, (char *)mtu, mtu_len, 0,
|
bytes_sent = sendto(BIP_Socket, (char *)mtu, mtu_len, 0,
|
||||||
(struct sockaddr *)bip_dest,
|
(struct sockaddr *)bip_dest,
|
||||||
sizeof(struct sockaddr));
|
sizeof(struct sockaddr));
|
||||||
|
|
||||||
close(bip_send_socket);
|
|
||||||
|
|
||||||
return bytes_sent;
|
return bytes_sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +233,7 @@ uint16_t bip_receive(
|
|||||||
int sin_len = sizeof(sin);
|
int sin_len = sizeof(sin);
|
||||||
|
|
||||||
/* Make sure the socket is open */
|
/* Make sure the socket is open */
|
||||||
if (BIP_Receive_Socket < 0)
|
if (BIP_Socket < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* we could just use a non-blocking socket, but that consumes all
|
/* we could just use a non-blocking socket, but that consumes all
|
||||||
@@ -247,11 +251,11 @@ uint16_t bip_receive(
|
|||||||
select_timeout.tv_usec = 1000 * timeout;
|
select_timeout.tv_usec = 1000 * timeout;
|
||||||
}
|
}
|
||||||
FD_ZERO(&read_fds);
|
FD_ZERO(&read_fds);
|
||||||
FD_SET(BIP_Receive_Socket, &read_fds);
|
FD_SET(BIP_Socket, &read_fds);
|
||||||
max = BIP_Receive_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(BIP_Receive_Socket,
|
received_bytes = recvfrom(BIP_Socket,
|
||||||
(char *)&buf[0], MAX_MPDU, 0,
|
(char *)&buf[0], MAX_MPDU, 0,
|
||||||
(struct sockaddr *)&sin, &sin_len);
|
(struct sockaddr *)&sin, &sin_len);
|
||||||
else
|
else
|
||||||
|
|||||||
Reference in New Issue
Block a user