Added support for VDE (Virtual Distributed Ethernet) network packet transport
Fixed filtering for non-pcap network packet transports (i.e. tun/tap, and vde) to properly filter the desired packets.
This commit is contained in:
parent
bfb6e54819
commit
fd5de0d005
4 changed files with 1282 additions and 1095 deletions
|
@ -133,12 +133,36 @@ OSX (Snow Leopard)
|
||||||
Invoke the package installer tuntap_20090913.pkg
|
Invoke the package installer tuntap_20090913.pkg
|
||||||
Click through the various prompts accepting things and eventually installing the package.
|
Click through the various prompts accepting things and eventually installing the package.
|
||||||
|
|
||||||
# Run simulator and:
|
# Build and Run simulator and:
|
||||||
sim> attach xq tap:tap0
|
sim> attach xq tap:tap0
|
||||||
sim> ! ifconfig tap0 192.168.6.1 netmask 255.255.255.0
|
sim> ! ifconfig tap0 192.168.6.1 netmask 255.255.255.0
|
||||||
|
|
||||||
Simulated system uses IP address 192.168.6.2 and host uses 192.167.6.1 and things work.
|
Simulated system uses IP address 192.168.6.2 and host uses 192.167.6.1
|
||||||
As far as I can tell you must run as root for this to work.
|
and things work.
|
||||||
|
You must run as root for this to work.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
An alternative to direct pcap and tun/tap networking on *nix environments is
|
||||||
|
VDE (Virtual Distributed Ethernet).
|
||||||
|
|
||||||
|
Note 1: Using vde based networking is likely more flexible, but it isn't
|
||||||
|
nearly as efficient. Host OS overhead will always be higher when
|
||||||
|
vde networking is used as compared to native pcap and/or tun/tap
|
||||||
|
networking.
|
||||||
|
Note 2: Root access will likely be needed to configure or start the vde
|
||||||
|
environment prior to starting a simulator which may use it.
|
||||||
|
Note 3: Simulators running using VDE networking can run without root
|
||||||
|
privilege.
|
||||||
|
|
||||||
|
Linux (Ubuntu 10.04):
|
||||||
|
apt-get install libvdeplug-dev
|
||||||
|
apt-get install vde2
|
||||||
|
|
||||||
|
vde_switch -s /tmp/switch1 -tap tap0 -m 666
|
||||||
|
ifconfig tap0 192.168.6.1 netmask 255.255.255.0 up
|
||||||
|
|
||||||
|
# Build and Run simulator and:
|
||||||
|
sim> attach xq vde:/tmp/switch1 #simulator uses IP address 192.168.6.2
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -354,6 +378,7 @@ Dave
|
||||||
Change Log
|
Change Log
|
||||||
===============================================================================
|
===============================================================================
|
||||||
|
|
||||||
|
30-Oct-11 MP Added support for vde (Virtual Distributed Ethernet) networking
|
||||||
29-Oct-11 MP Added support for integrated Tap networking interfaces on OSX
|
29-Oct-11 MP Added support for integrated Tap networking interfaces on OSX
|
||||||
17-Aug-11 RMS Fix from Sergey Oboguev relating to XU and XQ Auto Config and
|
17-Aug-11 RMS Fix from Sergey Oboguev relating to XU and XQ Auto Config and
|
||||||
vector assignments
|
vector assignments
|
||||||
|
|
13
makefile
13
makefile
|
@ -13,6 +13,7 @@
|
||||||
#
|
#
|
||||||
ifeq ($(WIN32),)
|
ifeq ($(WIN32),)
|
||||||
#*nix Environments (&& cygwin)
|
#*nix Environments (&& cygwin)
|
||||||
|
GCC = gcc
|
||||||
ifeq (SunOS,$(shell uname))
|
ifeq (SunOS,$(shell uname))
|
||||||
TEST = /bin/test
|
TEST = /bin/test
|
||||||
else
|
else
|
||||||
|
@ -62,13 +63,18 @@ ifeq ($(WIN32),)
|
||||||
NETWORK_CCDEFS = -DUSE_NETWORK
|
NETWORK_CCDEFS = -DUSE_NETWORK
|
||||||
NETWORK_LDFLAGS = -lpcap
|
NETWORK_LDFLAGS = -lpcap
|
||||||
endif
|
endif
|
||||||
|
ifeq (vde,$(shell if $(TEST) -e /usr/include/libvdeplug.h -a \( -e /usr/lib/libvdeplug.$(LIBEXT) -o -e /usr/lib64/libvdeplug.$(LIBEXT) \); then echo vde; fi))
|
||||||
|
# Provide support for vde networking
|
||||||
|
NETWORK_CCDEFS += -DUSE_VDE_NETWORK
|
||||||
|
NETWORK_LDFLAGS += -lvdeplug
|
||||||
|
endif
|
||||||
ifeq (tuntap,$(shell if $(TEST) -e /usr/include/linux/if_tun.h; then echo tuntap; fi))
|
ifeq (tuntap,$(shell if $(TEST) -e /usr/include/linux/if_tun.h; then echo tuntap; fi))
|
||||||
# Provide support for Tap networking on Linux
|
# Provide support for Tap networking on Linux
|
||||||
NETWORK_TAP_CCDEFS = -DUSE_TAP_NETWORK
|
NETWORK_CCDEFS += -DUSE_TAP_NETWORK
|
||||||
endif
|
endif
|
||||||
ifeq (bsdtuntap,$(shell if $(TEST) -e /usr/include/net/if_tun.h -o -e /Library/Extensions/tap.kext; then echo bsdtuntap; fi))
|
ifeq (bsdtuntap,$(shell if $(TEST) -e /usr/include/net/if_tun.h -o -e /Library/Extensions/tap.kext; then echo bsdtuntap; fi))
|
||||||
# Provide support for Tap networking
|
# Provide support for Tap networking
|
||||||
NETWORK_TAP_CCDEFS = -DUSE_TAP_NETWORK -DUSE_BSDTUNTAP
|
NETWORK_CCDEFS += -DUSE_TAP_NETWORK -DUSE_BSDTUNTAP
|
||||||
endif
|
endif
|
||||||
ifneq (binexists,$(shell if $(TEST) -e BIN; then echo binexists; fi))
|
ifneq (binexists,$(shell if $(TEST) -e BIN; then echo binexists; fi))
|
||||||
MKDIRBIN = if $(TEST) ! -e BIN; then mkdir BIN; fi
|
MKDIRBIN = if $(TEST) ! -e BIN; then mkdir BIN; fi
|
||||||
|
@ -79,6 +85,7 @@ ifeq ($(WIN32),)
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
#Win32 Environments (via MinGW32)
|
#Win32 Environments (via MinGW32)
|
||||||
|
GCC = gcc
|
||||||
GCC_Path := $(dir $(shell where gcc.exe))
|
GCC_Path := $(dir $(shell where gcc.exe))
|
||||||
ifeq ($(NOASYNCH),)
|
ifeq ($(NOASYNCH),)
|
||||||
ifeq (pthreads,$(shell if exist ..\pthreads\Pre-built.2\include\pthread.h echo pthreads))
|
ifeq (pthreads,$(shell if exist ..\pthreads\Pre-built.2\include\pthread.h echo pthreads))
|
||||||
|
@ -119,7 +126,7 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
CC = gcc -std=c99 -U__STRICT_ANSI__ -g -I . $(NETWORK_CCDEFS) $(NETWORK_TAP_CCDEFS) $(OS_CCDEFS) $(ROMS_OPT)
|
CC = $(GCC) -std=c99 -U__STRICT_ANSI__ -g -I . $(NETWORK_CCDEFS) $(OS_CCDEFS) $(ROMS_OPT)
|
||||||
LDFLAGS = $(OS_LDFLAGS) $(NETWORK_LDFLAGS)
|
LDFLAGS = $(OS_LDFLAGS) $(NETWORK_LDFLAGS)
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
337
sim_ether.c
337
sim_ether.c
|
@ -138,6 +138,15 @@
|
||||||
at open time. This functionality is only useful/needed
|
at open time. This functionality is only useful/needed
|
||||||
on *nix platforms since native sharing of Windows NIC
|
on *nix platforms since native sharing of Windows NIC
|
||||||
devices works with no external magic.
|
devices works with no external magic.
|
||||||
|
USE_VDE_NETWORK - Specifies that support for vde networking should be
|
||||||
|
included. This can be leveraged, along with OS bridging
|
||||||
|
capabilities to share a single LAN interface. It also
|
||||||
|
can allow a simulator to have useful networking
|
||||||
|
functionality when running without root access. This
|
||||||
|
allows device names of the form vde:/tmp/switch to be
|
||||||
|
specified at open time. This functionality is only
|
||||||
|
available on *nix platforms since the vde api isn't
|
||||||
|
available on Windows.
|
||||||
|
|
||||||
NEED_PCAP_SENDPACKET
|
NEED_PCAP_SENDPACKET
|
||||||
- Specifies that you are using an older version of libpcap
|
- Specifies that you are using an older version of libpcap
|
||||||
|
@ -151,6 +160,11 @@
|
||||||
|
|
||||||
Modification history:
|
Modification history:
|
||||||
|
|
||||||
|
30-Oct-11 MP Added support for vde (Virtual Distributed Ethernet) networking
|
||||||
|
29-Oct-11 MP Added support for integrated Tap networking interfaces on OSX
|
||||||
|
12-Aug-11 MP Cleaned up payload length determination
|
||||||
|
Fixed race condition detecting reflections when threaded
|
||||||
|
reading and writing is enabled
|
||||||
18-Apr-11 MP Fixed race condition with self loopback packets in
|
18-Apr-11 MP Fixed race condition with self loopback packets in
|
||||||
multithreaded environments
|
multithreaded environments
|
||||||
09-Jan-11 MP Fixed missing crc data when USE_READER_THREAD is defined and
|
09-Jan-11 MP Fixed missing crc data when USE_READER_THREAD is defined and
|
||||||
|
@ -793,6 +807,10 @@ void eth_show_dev (FILE* st, ETH_DEV* dev)
|
||||||
#endif
|
#endif
|
||||||
#endif /* USE_TAP_NETWORK */
|
#endif /* USE_TAP_NETWORK */
|
||||||
|
|
||||||
|
#ifdef USE_VDE_NETWORK
|
||||||
|
#include <libvdeplug.h>
|
||||||
|
#endif /* USE_VDE_NETWORK */
|
||||||
|
|
||||||
/* Allows windows to look up user-defined adapter names */
|
/* Allows windows to look up user-defined adapter names */
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#include <winreg.h>
|
#include <winreg.h>
|
||||||
|
@ -1092,10 +1110,12 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, char *devname)
|
||||||
if (!pcap_mac_if_win32(devname, (UCHAR *)&dev->host_nic_phy_hw_addr))
|
if (!pcap_mac_if_win32(devname, (UCHAR *)&dev->host_nic_phy_hw_addr))
|
||||||
dev->have_host_nic_phy_addr = 1;
|
dev->have_host_nic_phy_addr = 1;
|
||||||
#elif !defined (__VMS)
|
#elif !defined (__VMS)
|
||||||
{
|
if (1) {
|
||||||
char command[1024];
|
char command[1024];
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
|
||||||
|
if (0 == strncmp("vde:", devname, 4))
|
||||||
|
return;
|
||||||
memset(command, 0, sizeof(command));
|
memset(command, 0, sizeof(command));
|
||||||
snprintf(command, sizeof(command)-1, "ifconfig %s | grep [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F] >NIC.hwaddr", devname);
|
snprintf(command, sizeof(command)-1, "ifconfig %s | grep [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F] >NIC.hwaddr", devname);
|
||||||
system(command);
|
system(command);
|
||||||
|
@ -1148,16 +1168,24 @@ int sched_policy;
|
||||||
struct sched_param sched_priority;
|
struct sched_param sched_priority;
|
||||||
#if defined (_WIN32)
|
#if defined (_WIN32)
|
||||||
HANDLE hWait = pcap_getevent ((pcap_t*)dev->handle);
|
HANDLE hWait = pcap_getevent ((pcap_t*)dev->handle);
|
||||||
#endif
|
#else
|
||||||
#if defined (MUST_DO_SELECT)
|
|
||||||
struct timeval timeout;
|
|
||||||
int sel_ret;
|
int sel_ret;
|
||||||
int pcap_fd;
|
int do_select = 0;
|
||||||
|
int select_fd;
|
||||||
|
|
||||||
if (dev->pcap_mode)
|
switch (dev->eth_api) {
|
||||||
pcap_fd = pcap_get_selectable_fd((pcap_t *)dev->handle);
|
case ETH_API_PCAP:
|
||||||
else
|
#if defined (MUST_DO_SELECT)
|
||||||
pcap_fd = dev->fd_handle;
|
do_select = 1;
|
||||||
|
select_fd = pcap_get_selectable_fd((pcap_t *)dev->handle);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case ETH_API_TAP:
|
||||||
|
case ETH_API_VDE:
|
||||||
|
do_select = 1;
|
||||||
|
select_fd = dev->fd_handle;
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sim_debug(dev->dbit, dev->dptr, "Reader Thread Starting\n");
|
sim_debug(dev->dbit, dev->dptr, "Reader Thread Starting\n");
|
||||||
|
@ -1169,32 +1197,35 @@ else
|
||||||
++sched_priority.sched_priority;
|
++sched_priority.sched_priority;
|
||||||
pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
|
pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
|
||||||
|
|
||||||
while ((dev->pcap_mode && dev->handle) || dev->fd_handle) {
|
while (dev->handle) {
|
||||||
#if defined (MUST_DO_SELECT)
|
|
||||||
fd_set setl;
|
|
||||||
FD_ZERO(&setl);
|
|
||||||
FD_SET(pcap_fd, &setl);
|
|
||||||
timeout.tv_sec = 0;
|
|
||||||
timeout.tv_usec = 250*1000;
|
|
||||||
sel_ret = select(1+pcap_fd, &setl, NULL, NULL, &timeout);
|
|
||||||
if (sel_ret < 0 && errno != EINTR) break;
|
|
||||||
if (sel_ret > 0) {
|
|
||||||
#else /* !MUST_DO_SELECT */
|
|
||||||
#if defined (_WIN32)
|
#if defined (_WIN32)
|
||||||
if (WAIT_OBJECT_0 == WaitForSingleObject (hWait, 250)) {
|
if (WAIT_OBJECT_0 == WaitForSingleObject (hWait, 250)) {
|
||||||
#else
|
#else
|
||||||
if (1) {
|
fd_set setl;
|
||||||
#endif
|
struct timeval timeout;
|
||||||
#endif /* MUST_DO_SELECT */
|
|
||||||
if ((dev->pcap_mode) && (!dev->handle))
|
if (do_select) {
|
||||||
break;
|
FD_ZERO(&setl);
|
||||||
if ((!dev->pcap_mode) && (!dev->fd_handle))
|
FD_SET(select_fd, &setl);
|
||||||
|
timeout.tv_sec = 0;
|
||||||
|
timeout.tv_usec = 250*1000;
|
||||||
|
sel_ret = select(1+select_fd, &setl, NULL, NULL, &timeout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sel_ret = 1;
|
||||||
|
if (sel_ret < 0 && errno != EINTR) break;
|
||||||
|
if (sel_ret > 0) {
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
if (!dev->handle)
|
||||||
break;
|
break;
|
||||||
/* dispatch read request queue available packets */
|
/* dispatch read request queue available packets */
|
||||||
if (dev->pcap_mode)
|
switch (dev->eth_api) {
|
||||||
|
case ETH_API_PCAP:
|
||||||
status = pcap_dispatch ((pcap_t*)dev->handle, -1, &_eth_callback, (u_char*)dev);
|
status = pcap_dispatch ((pcap_t*)dev->handle, -1, &_eth_callback, (u_char*)dev);
|
||||||
|
break;
|
||||||
#ifdef USE_TAP_NETWORK
|
#ifdef USE_TAP_NETWORK
|
||||||
else {
|
case ETH_API_TAP:
|
||||||
|
if (1) {
|
||||||
struct pcap_pkthdr header;
|
struct pcap_pkthdr header;
|
||||||
int len;
|
int len;
|
||||||
u_char buf[ETH_MAX_JUMBO_FRAME];
|
u_char buf[ETH_MAX_JUMBO_FRAME];
|
||||||
|
@ -1205,14 +1236,35 @@ else
|
||||||
status = 1;
|
status = 1;
|
||||||
header.caplen = header.len = len;
|
header.caplen = header.len = len;
|
||||||
_eth_callback((u_char *)dev, &header, buf);
|
_eth_callback((u_char *)dev, &header, buf);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
status = 0;
|
status = 0;
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
#endif /* USE_TAP_NETWORK */
|
#endif /* USE_TAP_NETWORK */
|
||||||
|
#ifdef USE_VDE_NETWORK
|
||||||
|
case ETH_API_VDE:
|
||||||
|
if (1) {
|
||||||
|
struct pcap_pkthdr header;
|
||||||
|
int len;
|
||||||
|
u_char buf[ETH_MAX_JUMBO_FRAME];
|
||||||
|
|
||||||
|
memset(&header, 0, sizeof(header));
|
||||||
|
len = vde_recv((VDECONN *)dev->handle, buf, sizeof(buf), 0);
|
||||||
|
if (len > 0) {
|
||||||
|
status = 1;
|
||||||
|
header.caplen = header.len = len;
|
||||||
|
_eth_callback((u_char *)dev, &header, buf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
status = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif /* USE_VDE_NETWORK */
|
||||||
|
}
|
||||||
if ((status > 0) && (dev->asynch_io)) {
|
if ((status > 0) && (dev->asynch_io)) {
|
||||||
int wakeup_needed;
|
int wakeup_needed;
|
||||||
|
|
||||||
pthread_mutex_lock (&dev->lock);
|
pthread_mutex_lock (&dev->lock);
|
||||||
wakeup_needed = (dev->read_queue.count != 0);
|
wakeup_needed = (dev->read_queue.count != 0);
|
||||||
pthread_mutex_unlock (&dev->lock);
|
pthread_mutex_unlock (&dev->lock);
|
||||||
|
@ -1246,7 +1298,7 @@ struct sched_param sched_priority;
|
||||||
sim_debug(dev->dbit, dev->dptr, "Writer Thread Starting\n");
|
sim_debug(dev->dbit, dev->dptr, "Writer Thread Starting\n");
|
||||||
|
|
||||||
pthread_mutex_lock (&dev->writer_lock);
|
pthread_mutex_lock (&dev->writer_lock);
|
||||||
while ((dev->pcap_mode && dev->handle) || dev->fd_handle) {
|
while (dev->handle) {
|
||||||
pthread_cond_wait (&dev->writer_cond, &dev->writer_lock);
|
pthread_cond_wait (&dev->writer_cond, &dev->writer_lock);
|
||||||
while (request = dev->write_requests) {
|
while (request = dev->write_requests) {
|
||||||
/* Pull buffer off request list */
|
/* Pull buffer off request list */
|
||||||
|
@ -1330,7 +1382,8 @@ t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
|
||||||
savname = eth_getname(num, temp);
|
savname = eth_getname(num, temp);
|
||||||
if (savname == 0) /* didn't translate */
|
if (savname == 0) /* didn't translate */
|
||||||
return SCPE_OPENERR;
|
return SCPE_OPENERR;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
/* are they trying to use device description? */
|
/* are they trying to use device description? */
|
||||||
savname = eth_getname_bydesc(name, temp);
|
savname = eth_getname_bydesc(name, temp);
|
||||||
if (savname == 0) { /* didn't translate */
|
if (savname == 0) { /* didn't translate */
|
||||||
|
@ -1343,16 +1396,7 @@ t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
|
||||||
|
|
||||||
/* attempt to connect device */
|
/* attempt to connect device */
|
||||||
memset(errbuf, 0, sizeof(errbuf));
|
memset(errbuf, 0, sizeof(errbuf));
|
||||||
if (strncmp("tap:", savname, 4)) {
|
if (0 == strncmp("tap:", savname, 4)) {
|
||||||
dev->handle = (void*) pcap_open_live(savname, bufsz, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
|
|
||||||
if (!dev->handle) { /* can't open device */
|
|
||||||
msg = "Eth: pcap_open_live error - %s\r\n";
|
|
||||||
printf (msg, errbuf);
|
|
||||||
if (sim_log) fprintf (sim_log, msg, errbuf);
|
|
||||||
return SCPE_OPENERR;
|
|
||||||
}
|
|
||||||
dev->pcap_mode = 1;
|
|
||||||
} else {
|
|
||||||
int tun = -1; /* TUN/TAP Socket */
|
int tun = -1; /* TUN/TAP Socket */
|
||||||
int on = 1;
|
int on = 1;
|
||||||
char dev_name[64] = "";
|
char dev_name[64] = "";
|
||||||
|
@ -1374,18 +1418,21 @@ t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
|
||||||
strcpy(ifr.ifr_name, savname+4);
|
strcpy(ifr.ifr_name, savname+4);
|
||||||
ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
|
ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
|
||||||
|
|
||||||
// Send interface requests to TUN/TAP driver.
|
/* Send interface requests to TUN/TAP driver. */
|
||||||
if (ioctl(tun, TUNSETIFF, &ifr) >= 0) {
|
if (ioctl(tun, TUNSETIFF, &ifr) >= 0) {
|
||||||
if (ioctl(tun, FIONBIO, &on)) {
|
if (ioctl(tun, FIONBIO, &on)) {
|
||||||
strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
|
strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
|
||||||
close(tun);
|
close(tun);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
dev->fd_handle = tun;
|
dev->fd_handle = tun;
|
||||||
strcpy(savname, ifr.ifr_name);
|
strcpy(savname, ifr.ifr_name);
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
|
strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
|
strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
|
||||||
#elif defined(USE_BSDTUNTAP) && defined(USE_TAP_NETWORK)
|
#elif defined(USE_BSDTUNTAP) && defined(USE_TAP_NETWORK)
|
||||||
snprintf(dev_name, sizeof(dev_name)-1, "/dev/%s", savname+4);
|
snprintf(dev_name, sizeof(dev_name)-1, "/dev/%s", savname+4);
|
||||||
|
@ -1395,7 +1442,8 @@ t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
|
||||||
if (ioctl(tun, FIONBIO, &on)) {
|
if (ioctl(tun, FIONBIO, &on)) {
|
||||||
strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
|
strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
|
||||||
close(tun);
|
close(tun);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
dev->fd_handle = tun;
|
dev->fd_handle = tun;
|
||||||
strcpy(savname, savname+4);
|
strcpy(savname, savname+4);
|
||||||
}
|
}
|
||||||
|
@ -1416,12 +1464,48 @@ t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} else {
|
|
||||||
strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
|
||||||
#else
|
#else
|
||||||
strncpy(errbuf, "No support for tap: devices", sizeof(errbuf)-1);
|
strncpy(errbuf, "No support for tap: devices", sizeof(errbuf)-1);
|
||||||
#endif /* !defined(__linux) && !defined(USE_BSDTUNTAP) */
|
#endif /* !defined(__linux) && !defined(USE_BSDTUNTAP) */
|
||||||
|
if (0 == errbuf[0]) {
|
||||||
|
dev->eth_api = ETH_API_TAP;
|
||||||
|
dev->handle = (void *)1; /* Flag used to indicated open */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (0 == strncmp("vde:", savname, 4)) {
|
||||||
|
#if defined(USE_VDE_NETWORK)
|
||||||
|
struct vde_open_args voa;
|
||||||
|
|
||||||
|
memset(&voa, 0, sizeof(voa));
|
||||||
|
if (!strcmp(savname, "vde:vdedevice")) {
|
||||||
|
msg = "Eth: Must specify actual vde device name (i.e. vde:/tmp/switch)\r\n";
|
||||||
|
printf (msg, errbuf);
|
||||||
|
if (sim_log) fprintf (sim_log, msg, errbuf);
|
||||||
|
return SCPE_OPENERR;
|
||||||
|
}
|
||||||
|
if (!(dev->handle = (void*) vde_open(savname+4, "simh", &voa)))
|
||||||
|
strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
|
||||||
|
else {
|
||||||
|
dev->eth_api = ETH_API_VDE;
|
||||||
|
dev->fd_handle = vde_datafd((VDECONN*)dev->handle);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
strncpy(errbuf, "No support for vde: network devices", sizeof(errbuf)-1);
|
||||||
|
#endif /* !defined(__linux) && !defined(USE_BSDTUNTAP) */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dev->handle = (void*) pcap_open_live(savname, bufsz, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
|
||||||
|
if (!dev->handle) { /* can't open device */
|
||||||
|
msg = "Eth: pcap_open_live error - %s\r\n";
|
||||||
|
printf (msg, errbuf);
|
||||||
|
if (sim_log) fprintf (sim_log, msg, errbuf);
|
||||||
|
return SCPE_OPENERR;
|
||||||
|
}
|
||||||
|
dev->eth_api = ETH_API_PCAP;
|
||||||
}
|
}
|
||||||
if (errbuf[0]) {
|
if (errbuf[0]) {
|
||||||
msg = "Eth: open error - %s\r\n";
|
msg = "Eth: open error - %s\r\n";
|
||||||
|
@ -1447,14 +1531,14 @@ t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
|
||||||
#if !defined(HAS_PCAP_SENDPACKET) && defined (xBSD) && !defined (__APPLE__)
|
#if !defined(HAS_PCAP_SENDPACKET) && defined (xBSD) && !defined (__APPLE__)
|
||||||
/* Tell the kernel that the header is fully-formed when it gets it.
|
/* Tell the kernel that the header is fully-formed when it gets it.
|
||||||
This is required in order to fake the src address. */
|
This is required in order to fake the src address. */
|
||||||
if (dev->pcap_mode) {
|
if (dev->eth_api == ETH_API_PCAP) {
|
||||||
int one = 1;
|
int one = 1;
|
||||||
ioctl(pcap_fileno(dev->handle), BIOCSHDRCMPLT, &one);
|
ioctl(pcap_fileno(dev->handle), BIOCSHDRCMPLT, &one);
|
||||||
}
|
}
|
||||||
#endif /* xBSD */
|
#endif /* xBSD */
|
||||||
|
|
||||||
#if defined (USE_READER_THREAD)
|
#if defined (USE_READER_THREAD)
|
||||||
{
|
if (1) {
|
||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
@ -1474,7 +1558,7 @@ t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
|
||||||
#else /* !defined (USE_READER_THREAD */
|
#else /* !defined (USE_READER_THREAD */
|
||||||
#ifdef USE_SETNONBLOCK
|
#ifdef USE_SETNONBLOCK
|
||||||
/* set ethernet device non-blocking so pcap_dispatch() doesn't hang */
|
/* set ethernet device non-blocking so pcap_dispatch() doesn't hang */
|
||||||
if (dev->pcap_mode && (pcap_setnonblock (dev->handle, 1, errbuf) == -1)) {
|
if ((dev->eth_api == ETH_API_PCAP) && (pcap_setnonblock (dev->handle, 1, errbuf) == -1)) {
|
||||||
msg = "Eth: Failed to set non-blocking: %s\r\n";
|
msg = "Eth: Failed to set non-blocking: %s\r\n";
|
||||||
printf (msg, errbuf);
|
printf (msg, errbuf);
|
||||||
if (sim_log) fprintf (sim_log, msg, errbuf);
|
if (sim_log) fprintf (sim_log, msg, errbuf);
|
||||||
|
@ -1482,7 +1566,7 @@ t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
|
||||||
#endif
|
#endif
|
||||||
#endif /* !defined (USE_READER_THREAD */
|
#endif /* !defined (USE_READER_THREAD */
|
||||||
#if defined (__APPLE__)
|
#if defined (__APPLE__)
|
||||||
if (dev->pcap_mode) {
|
if (dev->eth_api == ETH_API_PCAP) {
|
||||||
/* Deliver packets immediately, needed for OS X 10.6.2 and later
|
/* Deliver packets immediately, needed for OS X 10.6.2 and later
|
||||||
* (Snow-Leopard).
|
* (Snow-Leopard).
|
||||||
* See this thread on libpcap and Mac Os X 10.6 Snow Leopard on
|
* See this thread on libpcap and Mac Os X 10.6 Snow Leopard on
|
||||||
|
@ -1520,7 +1604,6 @@ t_stat eth_close(ETH_DEV* dev)
|
||||||
pthread_cond_destroy (&dev->writer_cond);
|
pthread_cond_destroy (&dev->writer_cond);
|
||||||
if (1) {
|
if (1) {
|
||||||
struct write_request *buffer;
|
struct write_request *buffer;
|
||||||
|
|
||||||
while (buffer = dev->write_buffers) {
|
while (buffer = dev->write_buffers) {
|
||||||
dev->write_buffers = buffer->next;
|
dev->write_buffers = buffer->next;
|
||||||
free(buffer);
|
free(buffer);
|
||||||
|
@ -1533,12 +1616,21 @@ t_stat eth_close(ETH_DEV* dev)
|
||||||
ethq_destroy (&dev->read_queue); /* release FIFO queue */
|
ethq_destroy (&dev->read_queue); /* release FIFO queue */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (dev->pcap_mode)
|
switch (dev->eth_api) {
|
||||||
|
case ETH_API_PCAP:
|
||||||
pcap_close(pcap);
|
pcap_close(pcap);
|
||||||
|
break;
|
||||||
#ifdef USE_TAP_NETWORK
|
#ifdef USE_TAP_NETWORK
|
||||||
else
|
case ETH_API_TAP:
|
||||||
close(pcap_fd);
|
close(pcap_fd);
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_VDE_NETWORK
|
||||||
|
case ETH_API_VDE:
|
||||||
|
vde_close((VDECONN*)pcap);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
printf (msg, dev->name);
|
printf (msg, dev->name);
|
||||||
if (sim_log) fprintf (sim_log, msg, dev->name);
|
if (sim_log) fprintf (sim_log, msg, dev->name);
|
||||||
|
|
||||||
|
@ -1645,13 +1737,28 @@ t_stat _eth_write(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dispatch write request (synchronous; no need to save write info to dev) */
|
/* dispatch write request (synchronous; no need to save write info to dev) */
|
||||||
if (dev->pcap_mode)
|
switch (dev->eth_api) {
|
||||||
|
case ETH_API_PCAP:
|
||||||
status = pcap_sendpacket((pcap_t*)dev->handle, (u_char*)packet->msg, packet->len);
|
status = pcap_sendpacket((pcap_t*)dev->handle, (u_char*)packet->msg, packet->len);
|
||||||
|
break;
|
||||||
#ifdef USE_TAP_NETWORK
|
#ifdef USE_TAP_NETWORK
|
||||||
else
|
case ETH_API_TAP:
|
||||||
status = ((packet->len == write(dev->fd_handle, (void *)packet->msg, packet->len)) ? 0 : -1);
|
status = ((packet->len == write(dev->fd_handle, (void *)packet->msg, packet->len)) ? 0 : -1);
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_VDE_NETWORK
|
||||||
|
case ETH_API_VDE:
|
||||||
|
status = vde_send((VDECONN*)dev->handle, (void *)packet->msg, packet->len, 0);
|
||||||
|
if ((status == packet->len) || (status == 0))
|
||||||
|
status = 0;
|
||||||
|
else
|
||||||
|
if ((status == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
|
||||||
|
status = 0;
|
||||||
|
else
|
||||||
|
status = 1;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
/* On error, correct loopback bookkeeping */
|
/* On error, correct loopback bookkeeping */
|
||||||
if ((status != 0) && loopback_self_frame) {
|
if ((status != 0) && loopback_self_frame) {
|
||||||
#ifdef USE_READER_THREAD
|
#ifdef USE_READER_THREAD
|
||||||
|
@ -1710,7 +1817,8 @@ t_stat eth_write(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine)
|
||||||
++write_queue_size;
|
++write_queue_size;
|
||||||
}
|
}
|
||||||
last_request->next = request;
|
last_request->next = request;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
dev->write_requests = request;
|
dev->write_requests = request;
|
||||||
if (write_queue_size > dev->write_queue_peak)
|
if (write_queue_size > dev->write_queue_peak)
|
||||||
dev->write_queue_peak = write_queue_size;
|
dev->write_queue_peak = write_queue_size;
|
||||||
|
@ -1762,12 +1870,14 @@ _eth_hash_validate(ETH_MAC *MultiCastList, int count, ETH_MULTIHASH hash)
|
||||||
lhash[0], lhash[1], lhash[2], lhash[3],
|
lhash[0], lhash[1], lhash[2], lhash[3],
|
||||||
lhash[4], lhash[5], lhash[6], lhash[7]);
|
lhash[4], lhash[5], lhash[6], lhash[7]);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
printf("Should be: %02X %02X %02X %02X %02X %02X %02X %02X\n",
|
printf("Should be: %02X %02X %02X %02X %02X %02X %02X %02X\n",
|
||||||
hash[0], hash[1], hash[2], hash[3],
|
hash[0], hash[1], hash[2], hash[3],
|
||||||
hash[4], hash[5], hash[6], hash[7]);
|
hash[4], hash[5], hash[6], hash[7]);
|
||||||
printf("Was: %02X %02X %02X %02X %02X %02X %02X %02X\n",
|
printf("Was: %02X %02X %02X %02X %02X %02X %02X %02X\n",
|
||||||
lhash[0], lhash[1], lhash[2], lhash[3],
|
lhash[0], lhash[1], lhash[2], lhash[3],
|
||||||
lhash[4], lhash[5], lhash[6], lhash[7]);
|
lhash[4], lhash[5], lhash[6], lhash[7]);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2000,7 +2110,8 @@ _eth_fix_ip_jumbo_offload(ETH_DEV* dev, const u_char* msg, int len)
|
||||||
if (payload_len > mtu_payload) {
|
if (payload_len > mtu_payload) {
|
||||||
ip_flags |= IP_MF_FLAG;
|
ip_flags |= IP_MF_FLAG;
|
||||||
IP->total_len = htons(((mtu_payload>>3)<<3) + IP_HLEN(IP));
|
IP->total_len = htons(((mtu_payload>>3)<<3) + IP_HLEN(IP));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
IP->total_len = htons(payload_len + IP_HLEN(IP));
|
IP->total_len = htons(payload_len + IP_HLEN(IP));
|
||||||
}
|
}
|
||||||
IP->flags = htons(ip_flags);
|
IP->flags = htons(ip_flags);
|
||||||
|
@ -2009,7 +2120,8 @@ _eth_fix_ip_jumbo_offload(ETH_DEV* dev, const u_char* msg, int len)
|
||||||
header.caplen = header.len = 14 + ntohs(IP->total_len);
|
header.caplen = header.len = 14 + ntohs(IP->total_len);
|
||||||
eth_packet_trace (dev, ((u_char *)IP)-14, header.len, "reading Datagram fragment");
|
eth_packet_trace (dev, ((u_char *)IP)-14, header.len, "reading Datagram fragment");
|
||||||
#if ETH_MIN_JUMBO_FRAME < ETH_MAX_PACKET
|
#if ETH_MIN_JUMBO_FRAME < ETH_MAX_PACKET
|
||||||
{ /* Debugging is easier if we read packets directly with pcap
|
if (1) {
|
||||||
|
/* Debugging is easier if we read packets directly with pcap
|
||||||
(i.e. we can use Wireshark to verify packet contents)
|
(i.e. we can use Wireshark to verify packet contents)
|
||||||
we don't want to do this all the time for 2 reasons:
|
we don't want to do this all the time for 2 reasons:
|
||||||
1) sending through pcap involves kernel transitions and
|
1) sending through pcap involves kernel transitions and
|
||||||
|
@ -2050,7 +2162,8 @@ _eth_fix_ip_jumbo_offload(ETH_DEV* dev, const u_char* msg, int len)
|
||||||
if (payload_len > mtu_payload) {
|
if (payload_len > mtu_payload) {
|
||||||
TCP->data_offset_and_flags = htons(orig_tcp_flags&~(TCP_PSH_FLAG|TCP_FIN_FLAG|TCP_RST_FLAG));
|
TCP->data_offset_and_flags = htons(orig_tcp_flags&~(TCP_PSH_FLAG|TCP_FIN_FLAG|TCP_RST_FLAG));
|
||||||
IP->total_len = htons(mtu_payload + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP));
|
IP->total_len = htons(mtu_payload + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
TCP->data_offset_and_flags = htons(orig_tcp_flags);
|
TCP->data_offset_and_flags = htons(orig_tcp_flags);
|
||||||
IP->total_len = htons(payload_len + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP));
|
IP->total_len = htons(payload_len + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP));
|
||||||
}
|
}
|
||||||
|
@ -2061,7 +2174,8 @@ _eth_fix_ip_jumbo_offload(ETH_DEV* dev, const u_char* msg, int len)
|
||||||
header.caplen = header.len = 14 + ntohs(IP->total_len);
|
header.caplen = header.len = 14 + ntohs(IP->total_len);
|
||||||
eth_packet_trace_ex (dev, ((u_char *)IP)-14, header.len, "reading TCP segment", 1, dev->dbit);
|
eth_packet_trace_ex (dev, ((u_char *)IP)-14, header.len, "reading TCP segment", 1, dev->dbit);
|
||||||
#if ETH_MIN_JUMBO_FRAME < ETH_MAX_PACKET
|
#if ETH_MIN_JUMBO_FRAME < ETH_MAX_PACKET
|
||||||
{ /* Debugging is easier if we read packets directly with pcap
|
if (1) {
|
||||||
|
/* Debugging is easier if we read packets directly with pcap
|
||||||
(i.e. we can use Wireshark to verify packet contents)
|
(i.e. we can use Wireshark to verify packet contents)
|
||||||
we don't want to do this all the time for 2 reasons:
|
we don't want to do this all the time for 2 reasons:
|
||||||
1) sending through pcap involves kernel transitions and
|
1) sending through pcap involves kernel transitions and
|
||||||
|
@ -2155,19 +2269,27 @@ static void
|
||||||
_eth_callback(u_char* info, const struct pcap_pkthdr* header, const u_char* data)
|
_eth_callback(u_char* info, const struct pcap_pkthdr* header, const u_char* data)
|
||||||
{
|
{
|
||||||
ETH_DEV* dev = (ETH_DEV*) info;
|
ETH_DEV* dev = (ETH_DEV*) info;
|
||||||
#ifdef USE_BPF
|
int to_me;
|
||||||
int to_me = 1;
|
int from_me = 0;
|
||||||
|
int i;
|
||||||
|
int bpf_used;
|
||||||
|
|
||||||
|
switch (dev->eth_api) {
|
||||||
|
case ETH_API_PCAP:
|
||||||
|
#ifdef USE_BPF
|
||||||
|
bpf_used = 1;
|
||||||
|
to_me = 1;
|
||||||
/* AUTODIN II hash mode? */
|
/* AUTODIN II hash mode? */
|
||||||
if ((dev->hash_filter) && (data[0] & 0x01) && (!dev->promiscuous) && (!dev->all_multicast))
|
if ((dev->hash_filter) && (data[0] & 0x01) && (!dev->promiscuous) && (!dev->all_multicast))
|
||||||
to_me = _eth_hash_lookup(dev->hash, data);
|
to_me = _eth_hash_lookup(dev->hash, data);
|
||||||
#else /* !USE_BPF */
|
break;
|
||||||
int to_me = 0;
|
#endif /* USE_BPF */
|
||||||
int from_me = 0;
|
case ETH_API_TAP:
|
||||||
int i;
|
case ETH_API_VDE:
|
||||||
|
bpf_used = 0;
|
||||||
|
to_me = 0;
|
||||||
eth_packet_trace (dev, data, header->len, "received");
|
eth_packet_trace (dev, data, header->len, "received");
|
||||||
f
|
|
||||||
for (i = 0; i < dev->addr_count; i++) {
|
for (i = 0; i < dev->addr_count; i++) {
|
||||||
if (memcmp(data, dev->filter_address[i], 6) == 0) to_me = 1;
|
if (memcmp(data, dev->filter_address[i], 6) == 0) to_me = 1;
|
||||||
if (memcmp(&data[6], dev->filter_address[i], 6) == 0) from_me = 1;
|
if (memcmp(&data[6], dev->filter_address[i], 6) == 0) from_me = 1;
|
||||||
|
@ -2182,7 +2304,8 @@ f
|
||||||
/* AUTODIN II hash mode? */
|
/* AUTODIN II hash mode? */
|
||||||
if ((dev->hash_filter) && (!to_me) && (data[0] & 0x01))
|
if ((dev->hash_filter) && (!to_me) && (data[0] & 0x01))
|
||||||
to_me = _eth_hash_lookup(dev->hash, data);
|
to_me = _eth_hash_lookup(dev->hash, data);
|
||||||
#endif /* USE_BPF */
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* detect reception of loopback packet to our physical address */
|
/* detect reception of loopback packet to our physical address */
|
||||||
if (LOOPBACK_SELF_FRAME(dev->physical_addr, data)) {
|
if (LOOPBACK_SELF_FRAME(dev->physical_addr, data)) {
|
||||||
|
@ -2196,20 +2319,15 @@ f
|
||||||
dev->loopback_self_sent--;
|
dev->loopback_self_sent--;
|
||||||
to_me = 0;
|
to_me = 0;
|
||||||
}
|
}
|
||||||
#ifndef USE_BPF
|
|
||||||
else
|
else
|
||||||
|
if (!bpf_used)
|
||||||
from_me = 0;
|
from_me = 0;
|
||||||
#endif
|
|
||||||
#ifdef USE_READER_THREAD
|
#ifdef USE_READER_THREAD
|
||||||
pthread_mutex_unlock (&dev->self_lock);
|
pthread_mutex_unlock (&dev->self_lock);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_BPF
|
if (bpf_used ? to_me : (to_me && !from_me)) {
|
||||||
if (to_me) {
|
|
||||||
#else /* !USE_BPF */
|
|
||||||
if (to_me && !from_me) {
|
|
||||||
#endif
|
|
||||||
if (header->len > ETH_MIN_JUMBO_FRAME) {
|
if (header->len > ETH_MIN_JUMBO_FRAME) {
|
||||||
if (header->len <= header->caplen) /* Whole Frame captured? */
|
if (header->len <= header->caplen) /* Whole Frame captured? */
|
||||||
_eth_fix_ip_jumbo_offload(dev, data, header->len);
|
_eth_fix_ip_jumbo_offload(dev, data, header->len);
|
||||||
|
@ -2247,7 +2365,7 @@ f
|
||||||
pthread_mutex_unlock (&dev->lock);
|
pthread_mutex_unlock (&dev->lock);
|
||||||
free(moved_data);
|
free(moved_data);
|
||||||
}
|
}
|
||||||
#else
|
#else /* !USE_READER_THREAD */
|
||||||
/* set data in passed read packet */
|
/* set data in passed read packet */
|
||||||
dev->read_packet->len = header->len;
|
dev->read_packet->len = header->len;
|
||||||
memcpy(dev->read_packet->msg, data, header->len);
|
memcpy(dev->read_packet->msg, data, header->len);
|
||||||
|
@ -2298,10 +2416,13 @@ int eth_read(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine)
|
||||||
|
|
||||||
/* dispatch read request to either receive a filtered packet or timeout */
|
/* dispatch read request to either receive a filtered packet or timeout */
|
||||||
do {
|
do {
|
||||||
if (dev->pcap_mode)
|
switch (dev->eth_api) {
|
||||||
|
case ETH_API_PCAP:
|
||||||
status = pcap_dispatch((pcap_t*)dev->handle, 1, &_eth_callback, (u_char*)dev);
|
status = pcap_dispatch((pcap_t*)dev->handle, 1, &_eth_callback, (u_char*)dev);
|
||||||
|
break;
|
||||||
#ifdef USE_TAP_NETWORK
|
#ifdef USE_TAP_NETWORK
|
||||||
else {
|
case ETH_API_TAP:
|
||||||
|
if (1) {
|
||||||
struct pcap_pkthdr header;
|
struct pcap_pkthdr header;
|
||||||
int len;
|
int len;
|
||||||
u_char buf[ETH_MAX_JUMBO_FRAME];
|
u_char buf[ETH_MAX_JUMBO_FRAME];
|
||||||
|
@ -2312,11 +2433,32 @@ int eth_read(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine)
|
||||||
status = 1;
|
status = 1;
|
||||||
header.caplen = header.len = len;
|
header.caplen = header.len = len;
|
||||||
_eth_callback((u_char *)dev, &header, buf);
|
_eth_callback((u_char *)dev, &header, buf);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
status = 0;
|
status = 0;
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
#endif /* USE_TAP_NETWORK */
|
#endif /* USE_TAP_NETWORK */
|
||||||
|
#ifdef USE_VDE_NETWORK
|
||||||
|
case ETH_API_VDE:
|
||||||
|
if (1) {
|
||||||
|
struct pcap_pkthdr header;
|
||||||
|
int len;
|
||||||
|
u_char buf[ETH_MAX_JUMBO_FRAME];
|
||||||
|
|
||||||
|
memset(&header, 0, sizeof(header));
|
||||||
|
len = vde_recv((VDECONN*)dev->handle, buf, sizeof(buf), 0);
|
||||||
|
if (len > 0) {
|
||||||
|
status = 1;
|
||||||
|
header.caplen = header.len = len;
|
||||||
|
_eth_callback((u_char *)dev, &header, buf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
status = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif /* USE_VDE_NETWORK */
|
||||||
|
}
|
||||||
} while ((status) && (0 == packet->len));
|
} while ((status) && (0 == packet->len));
|
||||||
|
|
||||||
#else /* USE_READER_THREAD */
|
#else /* USE_READER_THREAD */
|
||||||
|
@ -2484,12 +2626,11 @@ t_stat eth_filter_hash(ETH_DEV* dev, int addr_count, ETH_MAC* const addresses,
|
||||||
sim_debug(dev->dbit, dev->dptr, "BPF string is: |%s|\n", buf);
|
sim_debug(dev->dbit, dev->dptr, "BPF string is: |%s|\n", buf);
|
||||||
|
|
||||||
/* get netmask, which is required for compiling */
|
/* get netmask, which is required for compiling */
|
||||||
if (dev->pcap_mode && (pcap_lookupnet(dev->handle, &bpf_subnet, &bpf_netmask, errbuf)<0)) {
|
if ((dev->eth_api == ETH_API_PCAP) && (pcap_lookupnet(dev->handle, &bpf_subnet, &bpf_netmask, errbuf)<0))
|
||||||
bpf_netmask = 0;
|
bpf_netmask = 0;
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef USE_BPF
|
#ifdef USE_BPF
|
||||||
if (dev->pcap_mode) {
|
if (dev->eth_api == ETH_API_PCAP) {
|
||||||
/* compile filter string */
|
/* compile filter string */
|
||||||
if ((status = pcap_compile(dev->handle, &bpf, buf, 1, bpf_netmask)) < 0) {
|
if ((status = pcap_compile(dev->handle, &bpf, buf, 1, bpf_netmask)) < 0) {
|
||||||
sprintf(errbuf, "%s", pcap_geterr(dev->handle));
|
sprintf(errbuf, "%s", pcap_geterr(dev->handle));
|
||||||
|
@ -2501,7 +2642,8 @@ t_stat eth_filter_hash(ETH_DEV* dev, int addr_count, ETH_MAC* const addresses,
|
||||||
msg = "Eth: BPF string is: |%s|\r\n";
|
msg = "Eth: BPF string is: |%s|\r\n";
|
||||||
printf (msg, buf);
|
printf (msg, buf);
|
||||||
if (sim_log) fprintf (sim_log, msg, buf);
|
if (sim_log) fprintf (sim_log, msg, buf);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
/* apply compiled filter string */
|
/* apply compiled filter string */
|
||||||
if ((status = pcap_setfilter(dev->handle, &bpf)) < 0) {
|
if ((status = pcap_setfilter(dev->handle, &bpf)) < 0) {
|
||||||
sprintf(errbuf, "%s", pcap_geterr(dev->handle));
|
sprintf(errbuf, "%s", pcap_geterr(dev->handle));
|
||||||
|
@ -2509,7 +2651,8 @@ t_stat eth_filter_hash(ETH_DEV* dev, int addr_count, ETH_MAC* const addresses,
|
||||||
printf(msg, errbuf);
|
printf(msg, errbuf);
|
||||||
if (sim_log) fprintf (sim_log, msg, errbuf);
|
if (sim_log) fprintf (sim_log, msg, errbuf);
|
||||||
sim_debug(dev->dbit, dev->dptr, "Eth: pcap_setfilter error: %s\n", errbuf);
|
sim_debug(dev->dbit, dev->dptr, "Eth: pcap_setfilter error: %s\n", errbuf);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
#ifdef USE_SETNONBLOCK
|
#ifdef USE_SETNONBLOCK
|
||||||
/* set file non-blocking */
|
/* set file non-blocking */
|
||||||
status = pcap_setnonblock (dev->handle, 1, errbuf);
|
status = pcap_setnonblock (dev->handle, 1, errbuf);
|
||||||
|
@ -2584,9 +2727,8 @@ int eth_host_devices(int used, int max, ETH_LIST* list)
|
||||||
sprintf( regkey, "SYSTEM\\CurrentControlSet\\Control\\Network\\"
|
sprintf( regkey, "SYSTEM\\CurrentControlSet\\Control\\Network\\"
|
||||||
"{4D36E972-E325-11CE-BFC1-08002BE10318}\\%hs\\Connection", list[i].name+
|
"{4D36E972-E325-11CE-BFC1-08002BE10318}\\%hs\\Connection", list[i].name+
|
||||||
strlen( "\\Device\\NPF_" ) );
|
strlen( "\\Device\\NPF_" ) );
|
||||||
if((status = RegOpenKeyExA (HKEY_LOCAL_MACHINE, regkey, 0, KEY_QUERY_VALUE, ®hnd)) != ERROR_SUCCESS) {
|
if ((status = RegOpenKeyExA (HKEY_LOCAL_MACHINE, regkey, 0, KEY_QUERY_VALUE, ®hnd)) != ERROR_SUCCESS)
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
reglen = sizeof(regval);
|
reglen = sizeof(regval);
|
||||||
|
|
||||||
/* look for user-defined adapter name, bail if not found */
|
/* look for user-defined adapter name, bail if not found */
|
||||||
|
@ -2619,6 +2761,14 @@ int eth_host_devices(int used, int max, ETH_LIST* list)
|
||||||
++used;
|
++used;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_VDE_NETWORK
|
||||||
|
if (used < max) {
|
||||||
|
list[used].num = used;
|
||||||
|
sprintf(list[used].name, "%s", "vde:device");
|
||||||
|
sprintf(list[used].desc, "%s", "Integrated VDE support");
|
||||||
|
++used;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return used;
|
return used;
|
||||||
}
|
}
|
||||||
|
@ -2636,7 +2786,8 @@ int eth_devices(int max, ETH_LIST* list)
|
||||||
char* msg = "Eth: error in pcap_findalldevs: %s\r\n";
|
char* msg = "Eth: error in pcap_findalldevs: %s\r\n";
|
||||||
printf (msg, errbuf);
|
printf (msg, errbuf);
|
||||||
if (sim_log) fprintf (sim_log, msg, errbuf);
|
if (sim_log) fprintf (sim_log, msg, errbuf);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
/* copy device list into the passed structure */
|
/* copy device list into the passed structure */
|
||||||
for (i=0, dev=alldevs; dev; dev=dev->next) {
|
for (i=0, dev=alldevs; dev; dev=dev->next) {
|
||||||
if ((dev->flags & PCAP_IF_LOOPBACK) || (!strcmp("any", dev->name))) continue;
|
if ((dev->flags & PCAP_IF_LOOPBACK) || (!strcmp("any", dev->name))) continue;
|
||||||
|
|
14
sim_ether.h
14
sim_ether.h
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
Modification history:
|
Modification history:
|
||||||
|
|
||||||
|
30-Oct-11 MP Added support for vde (Virtual Distributed Ethernet) networking
|
||||||
18-Apr-11 MP Fixed race condition with self loopback packets in
|
18-Apr-11 MP Fixed race condition with self loopback packets in
|
||||||
multithreaded environments
|
multithreaded environments
|
||||||
09-Dec-10 MP Added support to determine if network address conflicts exist
|
09-Dec-10 MP Added support to determine if network address conflicts exist
|
||||||
|
@ -89,13 +90,13 @@
|
||||||
#if defined (USE_READER_THREAD)
|
#if defined (USE_READER_THREAD)
|
||||||
#if defined (USE_SETNONBLOCK)
|
#if defined (USE_SETNONBLOCK)
|
||||||
#undef USE_SETNONBLOCK
|
#undef USE_SETNONBLOCK
|
||||||
#endif
|
#endif /* USE_SETNONBLOCK */
|
||||||
#undef PCAP_READ_TIMEOUT
|
#undef PCAP_READ_TIMEOUT
|
||||||
#define PCAP_READ_TIMEOUT 15
|
#define PCAP_READ_TIMEOUT 15
|
||||||
#if !defined (xBSD) && !defined(_WIN32) && !defined(VMS)
|
#if (!defined (xBSD) && !defined(_WIN32) && !defined(VMS)) || defined (USE_TAP_NETWORK) || defined (USE_VDE_NETWORK)
|
||||||
#define MUST_DO_SELECT
|
#define MUST_DO_SELECT 1
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
#endif /* USE_READER_THREAD */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
USE_BPF is defined to let this code leverage the libpcap/OS kernel provided
|
USE_BPF is defined to let this code leverage the libpcap/OS kernel provided
|
||||||
|
@ -175,7 +176,10 @@ struct eth_device {
|
||||||
char* name; /* name of ethernet device */
|
char* name; /* name of ethernet device */
|
||||||
void* handle; /* handle of implementation-specific device */
|
void* handle; /* handle of implementation-specific device */
|
||||||
int fd_handle; /* fd to kernel device (where needed) */
|
int fd_handle; /* fd to kernel device (where needed) */
|
||||||
int pcap_mode; /* Flag indicating if pcap API are being used to move packets */
|
int eth_api; /* Designator for which API is being used to move packets */
|
||||||
|
#define ETH_API_PCAP 0 /* Pcap API in use */
|
||||||
|
#define ETH_API_TAP 1 /* tun/tap API in use */
|
||||||
|
#define ETH_API_VDE 2 /* VDE API in use */
|
||||||
ETH_PCALLBACK read_callback; /* read callback function */
|
ETH_PCALLBACK read_callback; /* read callback function */
|
||||||
ETH_PCALLBACK write_callback; /* write callback function */
|
ETH_PCALLBACK write_callback; /* write callback function */
|
||||||
ETH_PACK* read_packet; /* read packet */
|
ETH_PACK* read_packet; /* read packet */
|
||||||
|
|
Loading…
Add table
Reference in a new issue