win32: fix ethernet and bip6 (#774)

Switch from WinPcap ton npcap.
Include npcap sdk in cmake
add libs for ipv6 in cmake
fix ethernet uninitialized var
This commit is contained in:
Patrick Grimm
2024-10-04 20:46:34 +02:00
committed by GitHub
parent 442f0bdf1c
commit 90dcd9dca1
3 changed files with 202 additions and 53 deletions
+3 -3
View File
@@ -393,9 +393,9 @@ int bip6_send_mpdu(
* Otherwise, -1 shall be returned and errno set to indicate the error.
*/
int bip6_send_pdu(
const BACNET_ADDRESS *dest,
const BACNET_NPDU_DATA *npdu_data,
const uint8_t *pdu,
BACNET_ADDRESS *dest,
BACNET_NPDU_DATA *npdu_data,
uint8_t *pdu,
unsigned pdu_len)
{
return bvlc6_send_pdu(dest, npdu_data, pdu, pdu_len);
+168 -47
View File
@@ -15,21 +15,20 @@
#include "bacnet/datalink/ethernet.h"
#include "bacnet/bacdcode.h"
/* Uses WinPCap to access raw ethernet */
/* Uses Npcap to access raw ethernet */
/* Notes: */
/* To make ethernet.c work under win32, you have to: */
/* 1. install winpcap 3.1 development pack; */
/* 2. install Microsoft Platform SDK Feb 2003. */
/* 1. install Npcap 1.80 installer for Windows; */
/* 2. install msys2 x86_64 */
/* 3. remove or modify functions used for log such as */
/* "LogError()", "LogInfo()", which were implemented */
/* as a wrapper of Log4cpp. */
/* -- Kevin Liao */
/* -- Patrick Grimm */
/* includes for accessing ethernet by using winpcap */
#include "pcap.h"
#include "packet32.h"
#include "ntddndis.h"
#include "remote-ext.h"
/* commonly used comparison address for ethernet */
uint8_t Ethernet_Broadcast[MAX_MAC_LEN] = {
@@ -46,14 +45,105 @@ static char pcap_errbuf[PCAP_ERRBUF_SIZE + 1];
static pcap_t *pcap_eth802_fp = NULL; /* 802.2 file handle, from winpcap */
static unsigned eth_timeout = 100;
/* #######Begin Packet32.h copy########*/
/*!
\brief Structure containing an OID request.
It is used by the PacketRequest() function to send an OID to the interface
card driver. It can be used, for example, to retrieve the status of the error
counters on the adapter, its MAC address, the list of the multicast groups
defined on it, and so on.
*/
struct _PACKET_OID_DATA {
ULONG Oid; /* ///< OID code. See the Microsoft DDK
documentation or the file ntddndis.h
///< for a complete list of valid codes. */
ULONG Length; /* ///< Length of the data field
_Field_size_full_(Length)*/
UCHAR Data[1]; /* ///< variable-lenght field that contains the
information passed to or received
///< from the adapter.*/
};
typedef struct _PACKET_OID_DATA PACKET_OID_DATA, *PPACKET_OID_DATA;
#define MAX_LINK_NAME_LENGTH \
64 /* //< Maximum length of the devices symbolic links*/
#define ADAPTER_NAME_LENGTH \
256 + 12 /*///< Maximum length for the name of an adapter. The value is \
the same used by the IP Helper API.*/
typedef struct WAN_ADAPTER_INT
WAN_ADAPTER; /*///< Describes an opened wan (dialup, VPN...) network adapter
using the NetMon API*/
typedef WAN_ADAPTER
*PWAN_ADAPTER; /*///< Describes an opened wan (dialup, VPN...) network
adapter using the NetMon API*/
/*!
\brief Describes an opened network adapter.
This structure is the most important for the functioning of packet.dll, but
the great part of its fields should be ignored by the user, since the library
offers functions that avoid to cope with low-level parameters
*/
typedef struct _ADAPTER {
HANDLE hFile; /* ///< \internal Handle to an open instance of the
NPF driver.*/
CHAR
SymbolicLink[MAX_LINK_NAME_LENGTH]; /*///< \internal A string containing
the name of the network adapter
currently opened.*/
int NumWrites; /* ///< \internal Number of times a packets written
on this adapter will be repeated
///< on the wire.*/
HANDLE
ReadEvent; /* ///< A notification event associated with the read
calls on the adapter.
///< It can be passed to standard Win32 functions (like WaitForSingleObject
///< or WaitForMultipleObjects) to wait until the driver's buffer contains some
///< data. It is particularly useful in GUI applications that need to wait
///< concurrently on several events. The PacketSetMinToCopy()
///< function can be used to define the minimum amount of data in the kernel
buffer
///< that will cause the event to be signalled. */
UINT ReadTimeOut; /*///< \internal The amount of time PacketReceivePacket
will wait for the ReadEvent to be signalled before
issuing a ReadFile.*/
CHAR Name[ADAPTER_NAME_LENGTH];
PWAN_ADAPTER pWanAdapter;
UINT Flags; /* ///< Adapter's flags. Tell if this adapter must be
treated in a different way.*/
#ifdef HAVE_AIRPCAP_API
PAirpcapHandle AirpcapAd;
#endif /*// HAVE_AIRPCAP_API*/
} ADAPTER, *LPADAPTER;
_Ret_maybenull_ LPADAPTER PacketOpenAdapter(_In_ PCCH AdapterName);
_Success_(return) BOOLEAN PacketRequest(
_In_ LPADAPTER AdapterObject,
_In_ BOOLEAN Set,
_Inout_ PPACKET_OID_DATA OidData);
VOID PacketCloseAdapter(_In_ _Post_invalid_ LPADAPTER lpAdapter);
/* #######End Packet32.h copy##########*/
/* couple of external func for runtime error logging, you can simply */
/* replace them with standard "printf(...)" */
/* Logging extern functions: Info level */
extern void LogInfo(const char *msg);
/* Logging extern functions: Error level*/
extern void LogError(const char *msg);
/* Logging extern functions: Debug level*/
extern void LogDebug(const char *msg);
/* Logging functions: Info level */
void LogInfo(const char *msg)
{
fprintf(stdout, "info ethernet: %s", msg);
}
/* Logging functions: Error level*/
void LogError(const char *msg)
{
fprintf(stderr, "error ethernet: %s", msg);
}
/* Logging functions: Debug level*/
void LogDebug(const char *msg)
{
fprintf(stdout, "debug ethernet: %s", msg);
}
bool ethernet_valid(void)
{
@@ -66,7 +156,7 @@ void ethernet_cleanup(void)
pcap_close(pcap_eth802_fp);
pcap_eth802_fp = NULL;
}
LogInfo("ethernet.c: ethernet_cleanup() ok.\n");
LogInfo("ethernet_cleanup() ok.\n");
}
void ethernet_set_timeout(unsigned timeout)
@@ -108,7 +198,9 @@ bool ethernet_init(char *if_name)
BOOLEAN result;
CHAR str[sizeof(PACKET_OID_DATA) + 128];
int i;
char msg[200];
char msg[400];
int devnum;
char *device = NULL;
if (ethernet_valid()) {
ethernet_cleanup();
@@ -118,24 +210,42 @@ bool ethernet_init(char *if_name)
* Find the interface user specified
*/
/* Retrieve the device list */
if (pcap_findalldevs(&pcap_all_if, pcap_errbuf) == -1) {
snprintf(
msg, sizeof(msg), "ethernet.c: error in pcap_findalldevs: %s\n",
pcap_errbuf);
if (pcap_findalldevs(&pcap_all_if, pcap_errbuf) == PCAP_ERROR) {
snprintf(msg, sizeof(msg), "pcap_findalldevs: %s\n", pcap_errbuf);
LogError(msg);
return false;
}
/* Scan the list printing every entry */
devnum = atoi(if_name);
i = 0;
for (dev = pcap_all_if; dev; dev = dev->next) {
if (strcmp(if_name, dev->name) == 0) {
break;
/* struct pcap_addr *dev_addr;*/
i++;
if (devnum == i) {
device = dev->name;
snprintf(msg, sizeof(msg), "interface select index: %i\n", i);
LogInfo(msg);
}
if ((dev->flags & PCAP_IF_UP) && !(dev->flags & PCAP_IF_LOOPBACK) &&
(dev->flags & PCAP_IF_RUNNING) &&
(dev->flags & PCAP_IF_CONNECTION_STATUS_CONNECTED)) {
snprintf(msg, sizeof(msg), "interface index: %i\n", i);
LogInfo(msg);
snprintf(msg, sizeof(msg), " name: %s\n", dev->name);
LogInfo(msg);
snprintf(msg, sizeof(msg), " description: %s\n", dev->description);
LogInfo(msg);
}
}
pcap_freealldevs(pcap_all_if); /* we don't need it anymore */
if (dev == NULL) {
if (if_name == NULL) {
snprintf(msg, sizeof(msg), "interface index not set\n");
LogError(msg);
return false;
}
if (device == NULL) {
snprintf(
msg, sizeof(msg), "ethernet.c: specified interface not found: %s\n",
if_name);
msg, sizeof(msg), "specified interface not found: %s\n", if_name);
LogError(msg);
return false;
}
@@ -144,12 +254,11 @@ bool ethernet_init(char *if_name)
* Get local MAC address
*/
ZeroMemory(str, sizeof(PACKET_OID_DATA) + 128);
lpAdapter = PacketOpenAdapter(if_name);
lpAdapter = PacketOpenAdapter(device);
if (lpAdapter == NULL) {
ethernet_cleanup();
snprintf(
msg, sizeof(msg),
"ethernet.c: error in PacketOpenAdapter(\"%s\")\n", if_name);
msg, sizeof(msg), "local mac PacketOpenAdapter(\"%s\")\n", device);
LogError(msg);
return false;
}
@@ -160,7 +269,7 @@ bool ethernet_init(char *if_name)
if (!result) {
PacketCloseAdapter(lpAdapter);
ethernet_cleanup();
LogError("ethernet.c: error in PacketRequest()\n");
LogError("local mac PacketRequest()\n");
return false;
}
for (i = 0; i < 6; ++i) {
@@ -168,16 +277,23 @@ bool ethernet_init(char *if_name)
}
PacketCloseAdapter(lpAdapter);
snprintf(
msg, sizeof(msg), "local mac %02x:%02x:%02x:%02x:%02x:%02x \n",
Ethernet_MAC_Address[0], Ethernet_MAC_Address[1],
Ethernet_MAC_Address[2], Ethernet_MAC_Address[3],
Ethernet_MAC_Address[4], Ethernet_MAC_Address[5]);
LogInfo(msg);
/**
* Open interface for subsequent sending and receiving
*/
/* Open the output device */
pcap_eth802_fp = pcap_open(
if_name, /* name of the device */
pcap_eth802_fp = pcap_open_live(
device, /* name of the device */
ETHERNET_MPDU_MAX, /* portion of the packet to capture */
PCAP_OPENFLAG_PROMISCUOUS, /* promiscuous mode */
eth_timeout, /* read timeout */
NULL, /* authentication on the remote machine */
/* NULL, */ /* authentication on the remote machine */
pcap_errbuf /* error buffer */
);
if (pcap_eth802_fp == NULL) {
@@ -185,14 +301,14 @@ bool ethernet_init(char *if_name)
ethernet_cleanup();
snprintf(
msg, sizeof(msg),
"ethernet.c: unable to open the adapter. %s is not supported by "
"WinPcap\n",
if_name);
"unable to open the adapter. %s is not supported by "
"Npcap\n",
device);
LogError(msg);
return false;
}
LogInfo("ethernet.c: ethernet_init() ok.\n");
LogInfo("ethernet_init() ok.\n");
atexit(ethernet_cleanup);
@@ -201,21 +317,21 @@ bool ethernet_init(char *if_name)
/* function to send a packet out the 802.2 socket */
/* returns bytes sent success, negative on failure */
int ethernet_send(
int ethernet_send_dst(
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;
/* int bytes = 0; */
uint8_t mtu[ETHERNET_MPDU_MAX] = { 0 };
int mtu_len = 0;
int i = 0;
/* don't waste time if the socket is not valid */
if (!ethernet_valid()) {
LogError("ethernet.c: invalid 802.2 ethernet interface descriptor!\n");
LogError("invalid 802.2 ethernet interface descriptor!\n");
return -1;
}
/* load destination ethernet MAC address */
@@ -225,7 +341,7 @@ int ethernet_send(
mtu_len++;
}
} else {
LogError("ethernet.c: invalid destination MAC address!\n");
LogError("invalid destination MAC address!\n");
return -2;
}
@@ -236,11 +352,11 @@ int ethernet_send(
mtu_len++;
}
} else {
LogError("ethernet.c: invalid source MAC address!\n");
LogError("invalid source MAC address!\n");
return -3;
}
if ((14 + 3 + pdu_len) > ETHERNET_MPDU_MAX) {
LogError("ethernet.c: PDU is too big to send!\n");
LogError("PDU is too big to send!\n");
return -4;
}
/* packet length */
@@ -257,7 +373,7 @@ int ethernet_send(
/* did it get sent? */
char msg[200];
snprintf(
msg, sizeof(msg), "ethernet.c: error sending packet: %s\n",
msg, sizeof(msg), "error sending packet: %s\n",
pcap_geterr(pcap_eth802_fp));
LogError(msg);
return -5;
@@ -270,12 +386,14 @@ int ethernet_send(
/* returns number of bytes sent on success, negative on failure */
int ethernet_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 */
)
{
int i = 0; /* counter */
BACNET_ADDRESS src = { 0 }; /* source address */
(void)npdu_data;
for (i = 0; i < 6; i++) {
src.mac[i] = Ethernet_MAC_Address[i];
@@ -283,7 +401,7 @@ int ethernet_send_pdu(
}
/* function to send a packet out the 802.2 socket */
/* returns 1 on success, 0 on failure */
return ethernet_send(
return ethernet_send_dst(
dest, /* destination address */
&src, /* source address */
pdu, /* any data to be sent - may be null */
@@ -303,12 +421,14 @@ uint16_t ethernet_receive(
{
struct pcap_pkthdr *header;
int res;
u_char *pkt_data;
const u_char *pkt_data;
uint16_t pdu_len = 0; /* return value */
/* unused ? */
(void)timeout;
/* Make sure the socket is open */
if (!ethernet_valid()) {
LogError("ethernet.c: invalid 802.2 ethernet interface descriptor!\n");
LogError("invalid 802.2 ethernet interface descriptor!\n");
return 0;
}
@@ -317,8 +437,9 @@ uint16_t ethernet_receive(
if (res < 0) {
char msg[200];
snprintf(
msg, sizeof(), "ethernet.c: error in receiving packet: %s\n",
msg, sizeof(msg), "error in receiving packet: %s\n",
pcap_geterr(pcap_eth802_fp));
LogError(msg);
return 0;
} else if (res == 0) {
return 0;
@@ -330,7 +451,7 @@ uint16_t ethernet_receive(
/* the signature of an 802.2 BACnet packet */
if ((pkt_data[14] != 0x82) && (pkt_data[15] != 0x82)) {
/*eth_log_error("ethernet.c: Non-BACnet packet\n"); */
/*LogError("ethernet.c: Non-BACnet packet\n"); */
return 0;
}
/* copy the source address */
@@ -341,7 +462,7 @@ uint16_t ethernet_receive(
/* the Ethernet card is in promiscious mode */
if ((memcmp(&pkt_data[0], Ethernet_MAC_Address, 6) != 0) &&
(memcmp(&pkt_data[0], Ethernet_Broadcast, 6) != 0)) {
/*eth_log_error( "ethernet.c: This packet isn't for us\n"); */
/*LogError( "ethernet.c: This packet isn't for us\n"); */
return 0;
}