You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
515 lines
12 KiB
C
515 lines
12 KiB
C
/*
|
|
* ethernet_win32.c
|
|
*
|
|
* Copyright 2013 Michael Zillgith
|
|
*
|
|
* This file is part of libIEC61850.
|
|
*
|
|
* libIEC61850 is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* libIEC61850 is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with libIEC61850. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* See COPYING file for the complete license text.
|
|
*/
|
|
|
|
#include "stack_config.h"
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include "hal_ethernet.h"
|
|
#include "lib_memory.h"
|
|
|
|
#ifndef DEBUG_HAL_ETHERNET
|
|
#define DEBUG_HAL_ETHERNET 1
|
|
#endif
|
|
|
|
// Set to 1 to workaround WaitForMutlipleObjects problem (returns timeout even when packets are received)
|
|
#define ETHERNET_WIN32_DISABLE_ETHERNET_HANDLESET 1
|
|
|
|
#if (CONFIG_INCLUDE_ETHERNET_WINDOWS == 1)
|
|
|
|
|
|
#include <malloc.h>
|
|
|
|
#include <winsock2.h>
|
|
#include <iphlpapi.h>
|
|
|
|
#ifndef __GNUC__
|
|
#pragma comment (lib, "IPHLPAPI.lib")
|
|
#endif
|
|
|
|
#define HAVE_REMOTE
|
|
|
|
// Enable WinPcap specific extension: pcap_getevent()
|
|
#define WPCAP
|
|
#include "pcap.h"
|
|
|
|
struct sEthernetSocket {
|
|
pcap_t* rawSocket;
|
|
struct bpf_program etherTypeFilter;
|
|
};
|
|
|
|
struct sEthernetHandleSet {
|
|
HANDLE *handles;
|
|
int nhandles;
|
|
};
|
|
|
|
#ifdef __GNUC__ /* detect MINGW */
|
|
|
|
#ifndef __MINGW64_VERSION_MAJOR
|
|
|
|
#define MAX_ADAPTER_ADDRESS_LENGTH 8
|
|
|
|
typedef struct _IP_ADAPTER_ADDRESSES {
|
|
union {
|
|
ULONGLONG Alignment;
|
|
struct {
|
|
ULONG Length;
|
|
DWORD IfIndex;
|
|
};
|
|
};
|
|
struct _IP_ADAPTER_ADDRESSES *Next;
|
|
PCHAR AdapterName;
|
|
void* FirstUnicastAddress;
|
|
void* FirstAnycastAddress;
|
|
void* FirstMulticastAddress;
|
|
void* FirstDnsServerAddress;
|
|
PWCHAR DnsSuffix;
|
|
PWCHAR Description;
|
|
PWCHAR FriendlyName;
|
|
BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH];
|
|
DWORD PhysicalAddressLength;
|
|
DWORD Flags;
|
|
DWORD Mtu;
|
|
DWORD IfType;
|
|
} IP_ADAPTER_ADDRESSES, *PIP_ADAPTER_ADDRESSES;
|
|
|
|
|
|
typedef ULONG (WINAPI* pgetadaptersaddresses)(ULONG family, ULONG flags, PVOID reserved, PIP_ADAPTER_ADDRESSES AdapterAddresses,
|
|
PULONG SizePointer);
|
|
|
|
static pgetadaptersaddresses GetAdaptersAddresses;
|
|
|
|
static bool dllLoaded = false;
|
|
|
|
static void
|
|
loadDLLs(void)
|
|
{
|
|
HINSTANCE hDll = LoadLibrary("iphlpapi.dll");
|
|
|
|
if (hDll == NULL) {
|
|
if (DEBUG_HAL_ETHERNET)
|
|
printf("Error loading iphlpapi.dll!\n");
|
|
return;
|
|
}
|
|
|
|
GetAdaptersAddresses = (pgetadaptersaddresses) GetProcAddress(hDll,
|
|
"GetAdaptersAddresses");
|
|
|
|
if (GetAdaptersAddresses == NULL)
|
|
printf("Error loading GetAdaptersAddresses from iphlpapi.dll (%d)\n", (int) GetLastError());
|
|
}
|
|
|
|
#endif /* __MINGW64_VERSION_MAJOR */
|
|
|
|
#endif /* __GNUC__ */
|
|
|
|
EthernetHandleSet
|
|
EthernetHandleSet_new(void)
|
|
{
|
|
EthernetHandleSet result = (EthernetHandleSet) GLOBAL_MALLOC(sizeof(struct sEthernetHandleSet));
|
|
|
|
if (result != NULL) {
|
|
result->handles = NULL;
|
|
result->nhandles = 0;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void
|
|
EthernetHandleSet_addSocket(EthernetHandleSet self, const EthernetSocket sock)
|
|
{
|
|
#if ETHERNET_WIN32_DISABLE_ETHERNET_HANDLESET == 1
|
|
#else
|
|
if (self != NULL && sock != NULL) {
|
|
|
|
int i = self->nhandles++;
|
|
|
|
self->handles = (HANDLE *) realloc(self->handles, self->nhandles * sizeof(HANDLE));
|
|
|
|
self->handles[i] = pcap_getevent(sock->rawSocket);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void
|
|
EthernetHandleSet_removeSocket(EthernetHandleSet self, const EthernetSocket sock)
|
|
{
|
|
#if ETHERNET_WIN32_DISABLE_ETHERNET_HANDLESET == 1
|
|
#else
|
|
if ((self != NULL) && (sock != NULL)) {
|
|
HANDLE h = pcap_getevent(sock->rawSocket);
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < self->nhandles; i++) {
|
|
if (self->handles[i] == h) {
|
|
memmove(&self->handles[i], &self->handles[i+1], sizeof(HANDLE) * (self->nhandles - i - 1));
|
|
self->nhandles--;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
int
|
|
EthernetHandleSet_waitReady(EthernetHandleSet self, unsigned int timeoutMs)
|
|
{
|
|
#if ETHERNET_WIN32_DISABLE_ETHERNET_HANDLESET == 1
|
|
return 1;
|
|
#else
|
|
int result;
|
|
|
|
if ((self != NULL) && (self->nhandles > 0)) {
|
|
DWORD ret = WaitForMultipleObjects(self->nhandles, self->handles, 0, timeoutMs);
|
|
|
|
if (ret == WAIT_TIMEOUT)
|
|
result = 0;
|
|
else if (ret == WAIT_FAILED)
|
|
result = -1;
|
|
else
|
|
result = (int)ret;
|
|
}
|
|
else {
|
|
result = -1;
|
|
}
|
|
|
|
return result;
|
|
#endif
|
|
}
|
|
|
|
void
|
|
EthernetHandleSet_destroy(EthernetHandleSet self)
|
|
{
|
|
if (self->handles)
|
|
free(self->handles);
|
|
|
|
GLOBAL_FREEMEM(self);
|
|
}
|
|
|
|
static char*
|
|
getInterfaceName(int interfaceIndex)
|
|
{
|
|
char errbuf[PCAP_ERRBUF_SIZE];
|
|
char* interfaceName = NULL;
|
|
|
|
pcap_if_t *devices;
|
|
pcap_if_t *device;
|
|
|
|
/* Get the ethernet device list */
|
|
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &devices, errbuf) == -1)
|
|
{
|
|
printf("pcap_findalldevs_ex: %s\n", errbuf);
|
|
return NULL;
|
|
}
|
|
|
|
bool ifaceFound = false;
|
|
|
|
/* Search device list for requested interface) */
|
|
int i = 0;
|
|
for(device = devices; device != NULL; device= device->next)
|
|
{
|
|
if (i == interfaceIndex) {
|
|
interfaceName = (char*) malloc(strlen(device->name) + 1);
|
|
strcpy(interfaceName, device->name);
|
|
if (DEBUG_HAL_ETHERNET)
|
|
printf("Use interface (%s)\n", interfaceName);
|
|
ifaceFound = true;
|
|
break;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
if (!ifaceFound)
|
|
{
|
|
if (DEBUG_HAL_ETHERNET)
|
|
printf("No ethernet interfaces found! Make sure WinPcap is installed.\n");
|
|
return NULL;
|
|
}
|
|
|
|
pcap_freealldevs(devices);
|
|
|
|
return interfaceName;
|
|
}
|
|
|
|
static void
|
|
getAdapterMacAddress(char* pcapAdapterName, uint8_t* macAddress)
|
|
{
|
|
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
|
|
ULONG outBufLen = 0;
|
|
|
|
pAddresses = (IP_ADAPTER_ADDRESSES*) malloc(65000);
|
|
|
|
if (GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW) {
|
|
free(pAddresses);
|
|
pAddresses = (IP_ADAPTER_ADDRESSES*) malloc(outBufLen);
|
|
}
|
|
|
|
if (GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses, &outBufLen) == NO_ERROR) {
|
|
PIP_ADAPTER_ADDRESSES pAddress = pAddresses;
|
|
|
|
while (pAddress != NULL) {
|
|
|
|
DWORD addressLength = pAddress->PhysicalAddressLength;
|
|
|
|
if (addressLength == 6) {
|
|
|
|
int i;
|
|
|
|
if (DEBUG_HAL_ETHERNET) {
|
|
printf("Adapter %s: ", pAddress->AdapterName);
|
|
|
|
for (i = 0; i < (int) addressLength; i++) {
|
|
printf("%02x ", pAddress->PhysicalAddress[i]);
|
|
}
|
|
}
|
|
|
|
if (strstr(pcapAdapterName, pAddress->AdapterName) != 0) {
|
|
if (DEBUG_HAL_ETHERNET)
|
|
printf(" requested found!");
|
|
|
|
for (i = 0; i < (int) addressLength; i++) {
|
|
macAddress[i] = pAddress->PhysicalAddress[i];
|
|
}
|
|
}
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
pAddress = pAddress->Next;
|
|
}
|
|
|
|
free(pAddresses);
|
|
}
|
|
else {
|
|
printf("Error getting device addresses!\n");
|
|
}
|
|
}
|
|
|
|
void
|
|
Ethernet_getInterfaceMACAddress(const char* interfaceId, uint8_t* addr)
|
|
{
|
|
#ifdef __GNUC__
|
|
#ifndef __MINGW64_VERSION_MAJOR
|
|
if (!dllLoaded) {
|
|
loadDLLs();
|
|
dllLoaded = true;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
char* endPtr;
|
|
|
|
long interfaceIndex = strtol(interfaceId, &endPtr, 10);
|
|
|
|
if ((*interfaceId != '\0') && (*endPtr != '\0')) {
|
|
printf("Ethernet_getInterfaceMACAddress: invalid interface number %s\n", interfaceId);
|
|
return;
|
|
}
|
|
|
|
char* interfaceName = getInterfaceName((int) interfaceIndex);
|
|
|
|
getAdapterMacAddress(interfaceName, addr);
|
|
|
|
free(interfaceName);
|
|
}
|
|
|
|
|
|
EthernetSocket
|
|
Ethernet_createSocket(const char* interfaceId, uint8_t* destAddress)
|
|
{
|
|
pcap_t *pcapSocket;
|
|
char errbuf[PCAP_ERRBUF_SIZE];
|
|
|
|
int interfaceIndex = atoi(interfaceId);
|
|
|
|
char* interfaceName = getInterfaceName(interfaceIndex);
|
|
|
|
if ((pcapSocket = pcap_open_live(interfaceName, 65536, PCAP_OPENFLAG_PROMISCUOUS, 1, errbuf)) == NULL)
|
|
{
|
|
printf("Open ethernet socket failed for device %s\n", interfaceName);
|
|
free(interfaceName);
|
|
return NULL;
|
|
}
|
|
|
|
free(interfaceName);
|
|
|
|
EthernetSocket ethernetSocket = (EthernetSocket) calloc(1, sizeof(struct sEthernetSocket));
|
|
|
|
ethernetSocket->rawSocket = pcapSocket;
|
|
|
|
return ethernetSocket;
|
|
}
|
|
|
|
void
|
|
Ethernet_destroySocket(EthernetSocket ethSocket)
|
|
{
|
|
pcap_close(ethSocket->rawSocket);
|
|
free(ethSocket);
|
|
}
|
|
|
|
void
|
|
Ethernet_sendPacket(EthernetSocket ethSocket, uint8_t* buffer, int packetSize)
|
|
{
|
|
if (pcap_sendpacket(ethSocket->rawSocket, buffer, packetSize) != 0)
|
|
printf("Error sending the packet: %s\n", pcap_geterr(ethSocket->rawSocket));
|
|
}
|
|
|
|
void
|
|
Ethernet_setMode(EthernetSocket ethSocket, EthernetSocketMode mode)
|
|
{
|
|
/* not implemented */
|
|
}
|
|
|
|
void
|
|
Ethernet_addMulticastAddress(EthernetSocket ethSocket, const uint8_t* multicastAddress)
|
|
{
|
|
/* not implemented */
|
|
}
|
|
|
|
void
|
|
Ethernet_setProtocolFilter(EthernetSocket ethSocket, uint16_t etherType)
|
|
{
|
|
char filterString[100];
|
|
|
|
sprintf(filterString, "(ether proto 0x%04x) or (vlan and ether proto 0x%04x)", etherType, etherType);
|
|
|
|
if (pcap_compile(ethSocket->rawSocket, &(ethSocket->etherTypeFilter), filterString, 1, 0) < 0) {
|
|
printf("Compiling packet filter failed!\n");
|
|
return;
|
|
}
|
|
|
|
if (pcap_setfilter(ethSocket->rawSocket, &(ethSocket->etherTypeFilter)) < 0) {
|
|
printf("Setting packet filter failed!\n");
|
|
}
|
|
}
|
|
|
|
int
|
|
Ethernet_receivePacket(EthernetSocket self, uint8_t* buffer, int bufferSize)
|
|
{
|
|
struct pcap_pkthdr* header;
|
|
uint8_t* packetData;
|
|
|
|
int pcapCode = pcap_next_ex(self->rawSocket, &header, (const unsigned char**) &packetData);
|
|
|
|
if (pcapCode > 0) {
|
|
int packetSize = header->caplen;
|
|
|
|
if (packetSize > bufferSize)
|
|
packetSize = bufferSize;
|
|
|
|
memcpy(buffer, packetData, packetSize);
|
|
|
|
return packetSize;
|
|
}
|
|
else {
|
|
if (pcapCode < 0)
|
|
printf("winpcap error\n");
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
bool
|
|
Ethernet_isSupported()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
#else
|
|
|
|
bool
|
|
Ethernet_isSupported()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
EthernetHandleSet
|
|
EthernetHandleSet_new(void)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
EthernetHandleSet_addSocket(EthernetHandleSet self, const EthernetSocket sock)
|
|
{
|
|
}
|
|
|
|
int
|
|
EthernetHandleSet_waitReady(EthernetHandleSet self, unsigned int timeoutMs)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
EthernetHandleSet_destroy(EthernetHandleSet self)
|
|
{
|
|
}
|
|
|
|
void
|
|
Ethernet_getInterfaceMACAddress(const char* interfaceId, uint8_t* addr)
|
|
{
|
|
}
|
|
|
|
EthernetSocket
|
|
Ethernet_createSocket(const char* interfaceId, uint8_t* destAddress)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
Ethernet_destroySocket(EthernetSocket ethSocket)
|
|
{
|
|
}
|
|
|
|
void
|
|
Ethernet_sendPacket(EthernetSocket ethSocket, uint8_t* buffer, int packetSize)
|
|
{
|
|
}
|
|
|
|
void
|
|
Ethernet_setMode(EthernetSocket ethSocket, EthernetSocketMode mode)
|
|
{
|
|
}
|
|
|
|
void
|
|
Ethernet_addMulticastAddress(EthernetSocket ethSocket, uint8_t* multicastAddress)
|
|
{
|
|
}
|
|
|
|
void
|
|
Ethernet_setProtocolFilter(EthernetSocket ethSocket, uint16_t etherType)
|
|
{
|
|
}
|
|
|
|
int
|
|
Ethernet_receivePacket(EthernetSocket self, uint8_t* buffer, int bufferSize)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#endif /* (CONFIG_INCLUDE_ETHERNET_WINDOWS == 1) */
|