Added ARCNET raw packet handling for Linux.

This commit is contained in:
skarg
2005-09-06 20:28:52 +00:00
parent 62d3c2e45a
commit 211e0fdb34
7 changed files with 368 additions and 7 deletions
+4 -2
View File
@@ -6,12 +6,14 @@ BASEDIR = .
#CFLAGS = -Wall -I. -O2 -g
# Note: you can strip out symbols using the strip command
# to get an idea of how big the compile really is.
#CFLAGS = -Wall -I. -Iports/linux -g -DBACDL_MSTP=1
#CFLAGS = -Wall -I. -Iports/linux -g -DBACDL_ETHERNET=1
CFLAGS = -Wall -I. -Iports/linux -g -DBACDL_BIP=1
CFLAGS = -Wall -I. -Iports/linux -g -DBACDL_ARCNET=1
#CFLAGS = -Wall -I. -Iports/linux -g -DBACDL_MSTP=1
#CFLAGS = -Wall -I. -Iports/linux -g -DBACDL_BIP=1
SRCS = ports/linux/main.c \
ports/linux/ethernet.c \
ports/linux/arcnet.c \
ports/linux/bip-init.c \
bip.c \
dlmstp.c \
+16 -3
View File
@@ -34,15 +34,21 @@
#ifndef ARCNET_H
#define ARCNET_H
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include "bacdef.h"
// specific defines for ARCNET
#define MAX_HEADER (1+1+2+2+1+1+1+1)
#define MAX_MPDU (MAX_HEADER+MAX_PDU)
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
bool arcnet_valid(void);
bool arcnet_cleanup(void);
void arcnet_cleanup(void);
bool arcnet_init(char *interface_name);
/* function to send a packet out the 802.2 socket */
@@ -60,13 +66,20 @@ int arcnet_send_pdu(
uint8_t *pdu, // any data to be sent - may be null
unsigned pdu_len); // number of bytes of data
// receives an 802.2 framed packet
// receives an framed packet
// returns the number of octets in the PDU, or zero on failure
uint16_t arcnet_receive(
BACNET_ADDRESS *src, // source address
uint8_t *pdu, // PDU data
uint16_t max_pdu); // amount of space available in the PDU
uint16_t max_pdu, // amount of space available in the PDU
unsigned timeout); // milliseconds to wait for a packet
void arcnet_get_my_address(BACNET_ADDRESS *my_address);
void arcnet_get_broadcast_address(
BACNET_ADDRESS *dest); // destination address
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+19
View File
@@ -46,6 +46,12 @@ int datalink_send_pdu(
uint8_t *pdu, // any data to be sent - may be null
unsigned pdu_len) // number of bytes of data
{
#ifdef BACDL_ARCNET
return arcnet_send_pdu(
dest,
pdu,
pdu_len);
#endif
#ifdef BACDL_MSTP
return dlmstp_send_pdu(
dest,
@@ -73,6 +79,13 @@ uint16_t datalink_receive(
uint16_t max_pdu, // amount of space available in the PDU
unsigned timeout) // number of milliseconds to wait for a packet
{
#ifdef BACDL_ARCNET
return arcnet_receive(
src,
pdu,
max_pdu,
timeout);
#endif
#ifdef BACDL_MSTP
return dlmstp_receive(
src,
@@ -99,6 +112,9 @@ uint16_t datalink_receive(
void datalink_get_broadcast_address(
BACNET_ADDRESS *dest) // destination address
{
#ifdef BACDL_ARCNET
arcnet_get_broadcast_address(dest);
#endif
#ifdef BACDL_MSTP
dlmstp_get_broadcast_address(dest);
#endif
@@ -113,6 +129,9 @@ void datalink_get_broadcast_address(
void datalink_get_my_address(
BACNET_ADDRESS *my_address)
{
#ifdef BACDL_ARCNET
arcnet_get_my_address(my_address);
#endif
#ifdef BACDL_MSTP
dlmstp_get_my_address(my_address);
#endif
+4
View File
@@ -43,6 +43,10 @@
#include "ethernet.h"
#endif
#ifdef BACDL_ARCNET
#include "arcnet.h"
#endif
#ifdef BACDL_MSTP
#include "dlmstp.h"
#endif
+321
View File
@@ -0,0 +1,321 @@
#include <stdint.h>
#include "bacdef.h"
#include "arcnet.h"
#include "net.h"
// my local device data - MAC address
uint8_t ARCNET_MAC_Address = 0;
// ARCNET file handle
static int ARCNET_Sock_FD = -1;
// ARCNET socket address (has the interface name)
static struct sockaddr ARCNET_Socket_Address;
// Broadcast address
#define ARCNET_BROADCAST 0
bool arcnet_valid(void)
{
return (ARCNET_Sock_FD >= 0);
}
void arcnet_cleanup(void)
{
if (arcnet_valid())
close(ARCNET_Sock_FD);
ARCNET_Sock_FD = -1;
return;
}
static int arcnet_bind(char *interface_name)
{
int sock_fd = -1; // return value
struct ifreq ifr;
int rv; // return value - error value from df or ioctl call
fprintf(stderr,"arcnet: opening \"%s\"\n",interface_name);
// note: on some systems you may have to add or enable in
// modules.conf (or in modutils/alias on Debian with update-modules)
// alias net-pf-17 af_packet
// Then follow it by: # modprobe af_packet
if ((sock_fd = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ALL))) < 0)
{
/* Error occured */
fprintf(stderr,
"arcnet: Error opening socket: %s\n",
strerror(errno));
fprintf(stderr,
"You might need to add the following to modules.conf\n"
"(or in /etc/modutils/alias on Debian with update-modules):\n"
"alias net-pf-17 af_packet\n"
"Also, add af_packet to /etc/modules.\n"
"Then follow it by:\n"
"# modprobe af_packet\n");
exit(-1);
}
if (ARCNET_Sock_FD >= 0)
{
/* Bind the socket to an interface name so we only get packets from it */
ARCNET_Socket_Address.sa_family = ARPHRD_ARCNET;
//ARCNET_Socket_Address.sa_family = PF_INET;
/* Clear the memory before copying */
memset(ARCNET_Socket_Address.sa_data, '\0',
sizeof(ARCNET_Socket_Address.sa_data));
/* Strcpy the interface name into the address */
strncpy(ARCNET_Socket_Address.sa_data, interface_name,
sizeof(ARCNET_Socket_Address.sa_data)-1);
fprintf(stderr,"arcnet: binding \"%s\"\n",ARCNET_Socket_Address.sa_data);
if (bind(sock_fd, &ARCNET_Socket_Address,
sizeof(ARCNET_Socket_Address)) != 0)
{
/* Bind problem, close socket and return */
fprintf(stderr,
"arcnet: Unable to bind socket : %s\n",
strerror(errno));
fprintf(stderr,
"You might need to add the following to modules.conf\n"
"(or in /etc/modutils/alias on Debian with update-modules):\n"
"alias net-pf-17 af_packet\n"
"Also, add af_packet to /etc/modules.\n"
"Then follow it by:\n"
"# modprobe af_packet\n");
/* Close the socket */
close(sock_fd);
exit(-1);
}
}
strncpy(ifr.ifr_name, interface_name, sizeof(ifr.ifr_name));
rv = ioctl(sock_fd, SIOCGIFHWADDR, &ifr);
if (rv != -1) /* worked okay */
ARCNET_MAC_Address = ifr.ifr_hwaddr.sa_data[0];
fprintf(stderr,"arcnet: MAC=%02Xh\n",ARCNET_MAC_Address);
atexit(arcnet_cleanup);
return sock_fd;
}
bool arcnet_init(char *interface_name)
{
ARCNET_Sock_FD = arcnet_bind(interface_name);
return arcnet_valid();
}
/* function to send a packet out the socket */
/* returns number of bytes sent on success, negative on failure */
int arcnet_send(
BACNET_ADDRESS *dest, // destination address
BACNET_ADDRESS *src, // source address
uint8_t *pdu, // any data to be sent - may be null
unsigned pdu_len) // number of bytes of data
{
int bytes = 0;
uint8_t mtu[512] = { 0 };
int mtu_len = 0;
struct archdr *pkt = (struct archdr *)mtu;
// don't waste time if the socket is not valid
if (ARCNET_Sock_FD < 0)
{
fprintf(stderr, "arcnet: socket is invalid!\n");
return -1;
}
/* load destination MAC address */
if (dest->mac_len == 1)
pkt->hard.dest = dest->mac[0];
else
{
fprintf(stderr, "arcnet: invalid destination MAC address!\n");
return -2;
}
if (src->mac_len == 1)
pkt->hard.source = src->mac[0];
else
{
fprintf(stderr, "arcnet: invalid source MAC address!\n");
return -3;
}
if ((ARC_HDR_SIZE + pdu_len) > 512)
{
fprintf(stderr, "arcnet: PDU is too big to send!\n");
return -4;
}
/* Logical PDU portion */
pkt->soft.raw[0] = 0xCD; /* SC for BACnet */
pkt->soft.raw[1] = 0x82; /* DSAP for BACnet */
pkt->soft.raw[2] = 0x82; /* SSAP for BACnet */
pkt->soft.raw[3] = 0x03; /* Control byte in header */
memcpy(&pkt->soft.raw[4], pdu, pdu_len);
/* packet length */
mtu_len = ARC_HDR_SIZE + 4 /*SC,DSAP,SSAP,LLC*/ + pdu_len;
/* Send the packet */
bytes =
sendto(ARCNET_Sock_FD, &mtu, mtu_len, 0,
(struct sockaddr *) &ARCNET_Socket_Address,
sizeof(ARCNET_Socket_Address));
/* did it get sent? */
if (bytes < 0)
fprintf(stderr,"arcnet: Error sending packet: %s\n",
strerror(errno));
return bytes;
}
/* function to send a PDU out the socket */
/* returns number of bytes sent on success, negative on failure */
int arcnet_send_pdu(
BACNET_ADDRESS *dest, // destination address
uint8_t *pdu, // any data to be sent - may be null
unsigned pdu_len) // number of bytes of data
{
BACNET_ADDRESS src = {0}; // source address
src.mac[0] = ARCNET_MAC_Address;
src.mac_len = 1;
return arcnet_send(dest, // destination address
&src, // source address
pdu, // any data to be sent - may be null
pdu_len); // number of bytes of data
}
// receives an framed packet
// returns the number of octets in the PDU, or zero on failure
uint16_t arcnet_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
{
int received_bytes;
uint8_t buf[512] = {0}; // data
uint16_t pdu_len = 0; // return value
fd_set read_fds;
int max;
struct timeval select_timeout;
struct archdr *pkt = (struct archdr *)buf;
/* Make sure the socket is open */
if (ARCNET_Sock_FD <= 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(ARCNET_Sock_FD, &read_fds);
max = ARCNET_Sock_FD;
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0)
received_bytes = read(ARCNET_Sock_FD, &buf[0], sizeof(buf));
else
return 0;
/* See if there is a problem */
if (received_bytes < 0) {
// EAGAIN Non-blocking I/O has been selected
// using O_NONBLOCK and no data
// was immediately available for reading.
if (errno != EAGAIN)
fprintf(stderr,"ethernet: Read error in receiving packet: %s\n",
strerror(errno));
return 0;
}
if (received_bytes == 0)
return 0;
printf("arcnet: received %u bytes from %02Xh (proto==%02Xh)\n",
received_bytes, pkt->hard.source, pkt->soft.raw[0]);
if (pkt->hard.source == ARCNET_MAC_Address) {
fprintf(stderr,"arcnet: self sent packet?\n");
return 0;
}
if (pkt->soft.raw[0] != 0xCD) {
fprintf(stderr,"arcnet: Non-BACnet packet.\n");
return 0;
}
if ((pkt->hard.dest != ARCNET_MAC_Address) &&
(pkt->hard.dest != ARCNET_BROADCAST))
{
fprintf(stderr,"arcnet: This packet is not for us.\n");
return 0;
}
if ((pkt->soft.raw[1] != 0x82) || /* DSAP */
(pkt->soft.raw[2] != 0x82) || /* LSAP */
(pkt->soft.raw[3] != 0x03)) /* LLC Control */
{
fprintf(stderr,"arcnet: BACnet packet has invalid LLC.\n");
return 0;
}
/* It must be addressed to us or be a Broadcast */
if ((pkt->hard.dest != ARCNET_MAC_Address) &&
(pkt->hard.dest != ARCNET_BROADCAST))
{
fprintf(stderr,"arcnet: This packet is not for us.\n");
return 0;
}
/* copy the source address */
src->mac_len = 1;
src->mac[0] = pkt->hard.source;
/* compute the PDU length */
pdu_len = received_bytes - ARC_HDR_SIZE;
pdu_len -= 4 /* SC, DSAP, SSAP, LLC Control */ ;
// copy the buffer into the PDU
if (pdu_len < max_pdu)
memmove(&pdu[0],&pkt->soft.raw[4],pdu_len);
// silently ignore packets that are too large
else
pdu_len = 0;
return pdu_len;
}
void arcnet_get_my_address(BACNET_ADDRESS *my_address)
{
int i = 0;
my_address->mac_len = 1;
my_address->mac[0] = ARCNET_MAC_Address;
my_address->net = 0; // local only, no routing
my_address->len = 0;
for (i = 0; i < MAX_MAC_LEN; i++)
{
my_address->adr[i] = 0;
}
return;
}
void arcnet_get_broadcast_address(
BACNET_ADDRESS *dest) // destination address
{
int i = 0; // counter
if (dest)
{
dest->mac[0] = ARCNET_BROADCAST;
dest->mac_len = 1;
dest->net = BACNET_BROADCAST_NETWORK;
dest->len = 0; // len=0 denotes broadcast address
for (i = 0; i < MAX_MAC_LEN; i++)
{
dest->adr[i] = 0;
}
}
return;
}
+1 -1
View File
@@ -316,7 +316,7 @@ uint16_t ethernet_receive(
max = eth802_sockfd;
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0)
received_bytes = read(eth802_sockfd, &buf[0], MAX_MPDU);
received_bytes = read(eth802_sockfd, &buf[0], sizeof(buf));
else
return 0;
+3 -1
View File
@@ -79,6 +79,7 @@
#include <sys/socket.h>
#include <net/route.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <features.h> /* for the glibc version number */
#if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1
#include <netpacket/packet.h>
@@ -86,7 +87,8 @@
#else
#include <asm/types.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h> /* The L2 protocols */
#include <linux/if_arcnet.h>
#include <linux/if_ether.h>
#endif
#include <netinet/in.h>
#include <arpa/inet.h>