Merge branch 'master' into Extra-VAXen

This commit is contained in:
Mark Pizzolato 2012-02-28 17:58:44 -08:00
commit a3973f0e8c
12 changed files with 290 additions and 92 deletions

View file

@ -142,8 +142,7 @@ Most *nix platforms have these APIs available and on these platforms
simh is typically built with these available since on these platforms,
pthreads is required for simh networking support. Windows can also
utilize the pthreads APIs if the compile and run time support for the
win32Pthreads package has been installed on the build system and the
run time dll is available in the execution environment.
win32Pthreads package has been installed on the build system.
Sample Asynch I/O device implementations.
The pdp11_rq.c module has been refactored to leverage the asynch I/O

View file

@ -1689,6 +1689,16 @@ t_stat xq_process_loopback(CTLR* xq, ETH_PACK* pack)
physical_address = &xq->var->setup.macs[0];
else
physical_address = &xq->var->mac;
/* The only packets we should be responding to are ones which
we received due to them being directed to our physical MAC address,
OR the Broadcast address OR to a Multicast address we're listening to
(we may receive others if we're in promiscuous mode, but shouldn't
respond to them) */
if ((0 == (pack->msg[0]&1)) && /* Multicast or Broadcast */
(0 != memcmp(physical_address, pack->msg, sizeof(ETH_MAC))))
return SCPE_NOFNC;
memcpy (&response.msg[0], &response.msg[offset+2], sizeof(ETH_MAC));
memcpy (&response.msg[6], physical_address, sizeof(ETH_MAC));
offset += 8 - 16; /* Account for the Ethernet Header and Offset value in this number */

View file

@ -416,6 +416,17 @@ t_stat xu_process_loopback(CTLR* xu, ETH_PACK* pack)
/* create forward response packet */
memcpy (&response, pack, sizeof(ETH_PACK));
memcpy (physical_address, xu->var->setup.macs[0], sizeof(ETH_MAC));
/* The only packets we should be responding to are ones which
we received due to them being directed to our physical MAC address,
OR the Broadcast address OR to a Multicast address we're listening to
(we may receive others if we're in promiscuous mode, but shouldn't
respond to them) */
if ((0 == (pack->msg[0]&1)) && /* Multicast or Broadcast */
(0 != memcmp(physical_address, pack->msg, sizeof(ETH_MAC))))
return SCPE_NOFNC;
memcpy (&response.msg[0], &response.msg[offset+2], sizeof(ETH_MAC));
memcpy (&response.msg[6], physical_address, sizeof(ETH_MAC));
offset += 8;

View file

@ -1,7 +1,9 @@
#ifndef ROM_vax780_vmb_exe_H
#define ROM_vax780_vmb_exe_H 0
/*
VAX/vax780_vmb_exe.h produced at Tue Sep 20 04:39:17 2011
from VAX/vmb.exe which was last modified at Tue Sep 20 03:24:44 2011
file size: 44544 (0xAE00)
VAX/vax780_vmb_exe.h produced at Sun Feb 26 12:32:44 2012
from VAX/vmb.exe which was last modified at Sat Feb 18 00:01:12 2012
file size: 44544 (0xAE00) - checksum: 0xFFC014CC
*/
unsigned char vax780_vmb_exe[] = {
0xD4,0xEF,0x34,0x61,0x00,0x00,0x17,0xEF,0xB8,0x5D,0x00,0x00,0xC1,0xAB,0x38,0xAB,
@ -2788,3 +2790,4 @@ unsigned char vax780_vmb_exe[] = {
0x4C,0x52,0x45,0x41,0x44,0x3A,0x58,0x2D,0x32,0x20,0x20,0x43,0x4F,0x4E,0x49,0x4F,
0x3A,0x58,0x2D,0x33,0x20,0x20,0x2A,0x45,0x6E,0x64,0x20,0x6F,0x66,0x20,0x49,0x64,
0x65,0x6E,0x74,0x20,0x6C,0x69,0x73,0x74,0x73,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,};
#endif /* ROM_vax780_vmb_exe_H */

View file

@ -1,7 +1,9 @@
#ifndef ROM_vax_ka655x_bin_H
#define ROM_vax_ka655x_bin_H 0
/*
VAX/vax_ka655x_bin.h produced at Tue Sep 20 04:39:07 2011
from VAX/ka655x.bin which was last modified at Tue Sep 20 03:24:43 2011
file size: 131072 (0x20000)
VAX/vax_ka655x_bin.h produced at Sun Feb 26 12:32:44 2012
from VAX/ka655x.bin which was last modified at Sat Feb 18 00:01:12 2012
file size: 131072 (0x20000) - checksum: 0xFF7673B6
*/
unsigned char vax_ka655x_bin[] = {
0x11,0x22,0x11,0xFE,0x02,0x03,0x53,0x01,0x31,0x89,0x03,0x00,0x31,0x8B,0x03,0x00,
@ -8196,3 +8198,4 @@ unsigned char vax_ka655x_bin[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,};
#endif /* ROM_vax_ka655x_bin_H */

119
makefile
View file

@ -28,7 +28,9 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin)
ifeq ($(GCC),)
GCC = gcc
endif
ifeq (SunOS,$(shell uname))
OSTYPE = $(shell uname)
OSNAME = $(OSTYPE)
ifeq (SunOS,$(OSTYPE))
TEST = /bin/test
else
TEST = test
@ -40,14 +42,16 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin)
INCPATH:=/usr/include
LIBPATH:=/usr/lib
OS_CCDEFS = -D_GNU_SOURCE
ifeq (Darwin,$(shell uname))
ifeq (Darwin,$(OSTYPE))
OSNAME = OSX
LIBEXT = dylib
else
ifeq (Linux,$(shell uname))
ifeq (Linux,$(OSTYPE))
LIBPATH := $(sort $(foreach lib,$(shell /sbin/ldconfig -p | grep ' => /' | sed 's/^.* => //'),$(dir $(lib))))
LIBEXT = so
else
ifeq (SunOS,$(shell uname))
ifeq (SunOS,$(OSTYPE))
OSNAME = Solaris
LIBPATH := $(shell crle | grep 'Default Library Path' | awk '{ print $$5 }' | sed 's/:/ /g')
LIBEXT = so
OS_LDFLAGS += -lsocket -lnsl
@ -68,7 +72,7 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin)
LIBPATH += /usr/pkg/lib
OS_LDFLAGS += -L/usr/pkg/lib -R/usr/pkg/lib
endif
ifneq (,$(findstring NetBSD,$(shell uname))$(findstring FreeBSD,$(shell uname)))
ifneq (,$(findstring NetBSD,$(OSTYPE))$(findstring FreeBSD,$(OSTYPE)))
LIBEXT = so
else
LIBEXT = a
@ -104,49 +108,41 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin)
OS_LDFLAGS += -ldl
$(info using libdl: $(call find_lib,dl) $(call find_include,dlfcn))
else
ifeq (BSD,$(findstring BSD,$(shell uname)))
ifeq (BSD,$(findstring BSD,$(OSTYPE)))
OS_CCDEFS += -DHAVE_DLOPEN=so
$(info using libdl: $(call find_include,dlfcn))
endif
endif
endif
ifneq (,$(call find_include,pcap))
ifneq (,$(call find_lib,pcap))
ifneq ($(USE_NETWORK),) # Network support specified on the GNU make command line
NETWORK_CCDEFS = -DUSE_NETWORK
NETWORK_LDFLAGS = -lpcap
$(info using libpcap: $(call find_lib,pcap) $(call find_include,pcap))
else # default build uses dynamic libpcap
# building the pdp11, or any vax simulator could use networking support
ifneq (,$(or $(findstring pdp11,$(MAKECMDGOALS)),$(findstring vax,$(MAKECMDGOALS)),$(findstring all,$(MAKECMDGOALS))))
NETWORK_USEFUL = true
else
ifeq ($(MAKECMDGOALS),)
# default target is all
NETWORK_USEFUL = true
endif
endif
ifneq (,$(NETWORK_USEFUL))
ifneq (,$(call find_include,pcap))
ifneq (,$(call find_lib,pcap))
ifneq ($(USE_NETWORK),) # Network support specified on the GNU make command line
NETWORK_CCDEFS = -DUSE_NETWORK
NETWORK_LDFLAGS = -lpcap
$(info using libpcap: $(call find_lib,pcap) $(call find_include,pcap))
else # default build uses dynamic libpcap
NETWORK_CCDEFS = -DUSE_SHARED
$(info using libpcap: $(call find_include,pcap))
endif
$(info *** Simulator(s) being built with networking support using)
$(info *** $(OSTYPE) provided libpcap components)
else
NETWORK_CCDEFS = -DUSE_SHARED
$(info using libpcap: $(call find_include,pcap))
$(info *** Simulator(s) being built with networking support using)
$(info *** $(OSTYPE) provided libpcap components)
endif
else
NETWORK_CCDEFS = -DUSE_SHARED
$(info using libpcap: $(call find_include,pcap))
endif
endif
ifneq (,$(call find_lib,vdeplug))
ifneq (,$(call find_include,libvdeplug))
# Provide support for vde networking
NETWORK_CCDEFS += -DUSE_VDE_NETWORK
NETWORK_LDFLAGS += -lvdeplug
$(info using libvdeplug: $(call find_lib,vdeplug) $(call find_include,libvdeplug))
endif
endif
ifneq (,$(call find_include,linux/if_tun))
# Provide support for Tap networking on Linux
NETWORK_CCDEFS += -DUSE_TAP_NETWORK
endif
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 on BSD platforms (including OS X)
NETWORK_CCDEFS += -DUSE_TAP_NETWORK -DUSE_BSDTUNTAP
endif
ifneq (binexists,$(shell if $(TEST) -e BIN; then echo binexists; fi))
MKDIRBIN = if $(TEST) ! -e BIN; then mkdir BIN; fi
endif
NETWORK_OPT = $(NETWORK_CCDEFS)
ifneq ($(USE_NETWORK),) # Network support specified on the GNU make command line
ifneq (USE_NETWORK,$(findstring USE_NETWORK,$(NETWORK_CCDEFS)))
# Look for package built from tcpdump.org sources with default install target
LIBPATH += /usr/local/lib
INCPATH += /usr/local/include
@ -154,16 +150,55 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin)
LIBEXT = a
ifneq (,$(call find_lib,pcap))
ifneq (,$(call find_include,pcap))
NETWORK_OPT := -DUSE_NETWORK -isystem $(dir $(call find_include,pcap)) $(call find_lib,pcap)
NETWORK_CCDEFS := -DUSE_NETWORK -isystem $(dir $(call find_include,pcap)) $(call find_lib,pcap)
$(info using libpcap: $(call find_lib,pcap) $(call find_include,pcap))
$(info *** Warning ***)
$(info *** Warning *** Simulator(s) being built with networking support using)
$(info *** Warning *** libpcap components from www.tcpdump.org.)
$(info *** Warning *** Some users have had problems using the www.tcpdump.org libpcap)
$(info *** Warning *** components for simh networking. For best results, with)
$(info *** Warning *** simh networking, it is recommended that you install the)
$(info *** Warning *** libpcap-dev package from your $(OSTYPE) distribution)
$(info *** Warning ***)
else
$(error using libpcap: $(call find_lib,pcap) missing pcap.h)
endif
LIBEXT = $(LIBEXTSAVE)
else
$(error missing libpcap)
endif
endif
ifneq (,$(findstring USE_NETWORK,$(NETWORK_CCDEFS))$(findstring USE_SHARED,$(NETWORK_CCDEFS)))
# Given we have libpcap components, consider other network connections as well
ifneq (,$(call find_lib,vdeplug))
# libvdeplug requires the use of the OS provided libpcap
ifeq (,$(findstring usr/local,$(NETWORK_CCDEFS)))
ifneq (,$(call find_include,libvdeplug))
# Provide support for vde networking
NETWORK_CCDEFS += -DUSE_VDE_NETWORK
NETWORK_LDFLAGS += -lvdeplug
$(info using libvdeplug: $(call find_lib,vdeplug) $(call find_include,libvdeplug))
endif
endif
endif
ifneq (,$(call find_include,linux/if_tun))
# Provide support for Tap networking on Linux
NETWORK_CCDEFS += -DUSE_TAP_NETWORK
endif
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 on BSD platforms (including OS X)
NETWORK_CCDEFS += -DUSE_TAP_NETWORK -DUSE_BSDTUNTAP
endif
else
$(info *** Warning ***)
$(info *** Warning *** Simulator(s) are being built WITHOUT networking support)
$(info *** Warning ***)
$(info *** Warning *** To build simulator(s) with networking support you should install)
$(info *** Warning *** the libpcap-dev package from your $(OSTYPE) distribution)
$(info *** Warning ***)
endif
NETWORK_OPT = $(NETWORK_CCDEFS)
endif
ifneq (binexists,$(shell if $(TEST) -e BIN; then echo binexists; fi))
MKDIRBIN = if $(TEST) ! -e BIN; then mkdir BIN; fi
endif
else
#Win32 Environments (via MinGW32)

2
scp.c
View file

@ -3965,6 +3965,8 @@ if (!initialized) {
handle = dlopen("libncurses." __STR(HAVE_DLOPEN), RTLD_NOW|RTLD_GLOBAL);
handle = dlopen("libcurses." __STR(HAVE_DLOPEN), RTLD_NOW|RTLD_GLOBAL);
handle = dlopen("libreadline." __STR(HAVE_DLOPEN), RTLD_NOW|RTLD_GLOBAL);
if (!handle)
handle = dlopen("libreadline." __STR(HAVE_DLOPEN) ".6", RTLD_NOW|RTLD_GLOBAL);
if (handle) {
p_readline = dlsym(handle, "readline");
p_add_history = dlsym(handle, "add_history");

View file

@ -53,7 +53,9 @@
#include <utime.h>
#endif
int sim_make_ROM_include(const char *rom_filename,
int sim_make_ROM_include(const char *rom_filename,
int expected_size,
int expected_checksum,
const char *include_filename,
const char *rom_array_name)
{
@ -64,24 +66,44 @@ int bytes_written = 0;
int c;
struct stat statb;
unsigned char *ROMData = NULL;
unsigned int checksum = 0;
if (NULL == (rFile = fopen (rom_filename, "rb"))) {
printf ("Error Opening '%s' for input: %s\n", rom_filename, strerror(errno));
return -1;
}
if (stat (rom_filename, &statb)) {
printf ("Error Stating '%s': %s\n", rom_filename, strerror(errno));
printf ("Error stating '%s': %s\n", rom_filename, strerror(errno));
fclose (rFile);
return -1;
}
if (statb.st_size != expected_size) {
printf ("Error: ROM file '%s' has an unexpected size: %d vs %d\n", rom_filename, (int)statb.st_size, expected_size);
printf ("This can happen if the file was transferred or unpacked incorrectly\n");
printf ("and in the process tried to convert line endings rather than passing\n");
printf ("the file's contents unmodified\n");
fclose (rFile);
return -1;
}
ROMData = malloc (statb.st_size);
if (statb.st_size != fread (ROMData, sizeof(*ROMData), statb.st_size, rFile)) {
printf ("Error Stating '%s': %s\n", rom_filename, strerror(errno));
printf ("Error reading '%s': %s\n", rom_filename, strerror(errno));
fclose (rFile);
free (ROMData);
return -1;
}
fclose (rFile);
for (c=0; c<statb.st_size; ++c)
checksum += ROMData[c];
checksum = ~checksum;
if ((expected_checksum != 0) && (checksum != expected_checksum)) {
printf ("Error: ROM file '%s' has an unexpected checksum: 0x%08X vs 0x%08X\n", rom_filename, checksum, expected_checksum);
printf ("This can happen if the file was transferred or unpacked incorrectly\n");
printf ("and in the process tried to convert line endings rather than passing\n");
printf ("the file's contents unmodified\n");
fclose (rFile);
return -1;
}
/*
* If the target include file already exists, determine if it contains the exact
* data in the base ROM image. If so, then we are already done
@ -130,7 +152,7 @@ fprintf (iFile, "#define ROM_%s_H 0\n", rom_array_name);
fprintf (iFile, "/*\n");
fprintf (iFile, " %s produced at %s", include_filename, ctime(&now));
fprintf (iFile, " from %s which was last modified at %s", rom_filename, ctime(&statb.st_mtime));
fprintf (iFile, " file size: %d (0x%X)\n", (int)statb.st_size, (int)statb.st_size);
fprintf (iFile, " file size: %d (0x%X) - checksum: 0x%08X\n", (int)statb.st_size, (int)statb.st_size, checksum);
fprintf (iFile, "*/\n");
fprintf (iFile, "unsigned char %s[] = {", rom_array_name);
for (bytes_written=0;bytes_written<statb.st_size; ++bytes_written) {
@ -156,7 +178,8 @@ return 0;
int
main(int argc, char **argv)
{
sim_make_ROM_include ("VAX/ka655x.bin", "VAX/vax_ka655x_bin.h", "vax_ka655x_bin");
sim_make_ROM_include ("VAX/vmb.exe", "VAX/vax780_vmb_exe.h", "vax780_vmb_exe");
exit(0);
int status = 0;
status += sim_make_ROM_include ("VAX/ka655x.bin", 131072, 0xFF7673B6, "VAX/vax_ka655x_bin.h", "vax_ka655x_bin");
status += sim_make_ROM_include ("VAX/vmb.exe", 44544, 0xFFC014CC, "VAX/vax780_vmb_exe.h", "vax780_vmb_exe");
exit((status == 0) ? 0 : 1);
}

View file

@ -930,6 +930,13 @@ static HANDLE std_input;
static HANDLE std_output;
static DWORD saved_mode;
/* Note: This routine catches all the potential events which some aspect
of the windows system can generate. The CTRL_C_EVENT won't be
generated by a user typing in a console session since that
session is in RAW mode. In general, Ctrl-C on a simulator's
console terminal is a useful character to be passed to the
simulator. This code does nothing to disable or affect that. */
static BOOL WINAPI
ControlHandler(DWORD dwCtrlType)
{

View file

@ -2132,6 +2132,7 @@ typedef struct _VHD_DynamicDiskHeader {
} VHD_DynamicDiskHeader;
#define VHD_BAT_FREE_ENTRY (0xFFFFFFFF)
#define VHD_DATA_BLOCK_ALIGNMENT ((uint64)4096) /* Optimum when underlying storage has 4k sectors */
static char *VHD_DiskTypes[] =
{
@ -3214,6 +3215,14 @@ while (sects) {
BitMap = malloc(BitMapSectors*SectorSize);
memset(BitMap, 0xFF, BitMapBytes);
BlockOffset -= sizeof(hVHD->Footer);
/* align the data portion of the block to the desired alignment */
/* compute the address of the data portion of the block */
BlockOffset += BitMapSectors*SectorSize;
/* round up this address to the desired alignment */
BlockOffset += VHD_DATA_BLOCK_ALIGNMENT-1;
BlockOffset &= ~(VHD_DATA_BLOCK_ALIGNMENT-1);
/* the actual block address is the beginning of the block bitmap */
BlockOffset -= BitMapSectors*SectorSize;
hVHD->BAT[BlockNumber] = NtoHl((uint32)(BlockOffset/SectorSize));
if (WriteFilePosition(hVHD->File,
BitMap,

View file

@ -560,7 +560,7 @@ char* eth_getname(int number, char* name)
ETH_LIST list[ETH_MAX_DEVICE];
int count = eth_devices(ETH_MAX_DEVICE, list);
if (count <= number) return 0;
if (count <= number) return NULL;
strcpy(name, list[number].name);
return name;
}
@ -587,7 +587,7 @@ char* eth_getname_bydesc(char* desc, char* name)
return name;
}
/* not found */
return 0;
return NULL;
}
/* strncasecmp() is not available on all platforms */
@ -621,16 +621,13 @@ char* eth_getname_byname(char* name, char* temp)
found = 0;
n = strlen(name);
for (i=0; i<count && !found; i++) {
if (eth_strncasecmp(name, list[i].name, n) == 0) {
if ((n == strlen(list[i].name)) &&
(eth_strncasecmp(name, list[i].name, n) == 0)) {
found = 1;
strcpy(temp, list[i].name); /* only case might be different */
}
}
if (found) {
return temp;
} else {
return 0;
}
return (found ? temp : NULL);
}
void eth_zero(ETH_DEV* dev)
@ -657,7 +654,7 @@ t_stat eth_show (FILE* st, UNIT* uptr, int32 val, void* desc)
for (i=0, min=0; i<number; i++)
if ((len = strlen(list[i].name)) > min) min = len;
for (i=0; i<number; i++)
fprintf(st," %d %-*s (%s)\n", i, (int)min, list[i].name, list[i].desc);
fprintf(st," %2d %-*s (%s)\n", i, (int)min, list[i].name, list[i].desc);
}
return SCPE_OK;
}
@ -1452,16 +1449,16 @@ if ((strlen(name) == 4)
) {
num = atoi(&name[3]);
savname = eth_getname(num, temp);
if (savname == 0) /* didn't translate */
if (savname == NULL) /* didn't translate */
return SCPE_OPENERR;
}
else {
/* are they trying to use device description? */
savname = eth_getname_bydesc(name, temp);
if (savname == 0) { /* didn't translate */
if (savname == NULL) { /* didn't translate */
/* probably is not ethX and has no description */
savname = eth_getname_byname(name, temp);
if (savname == 0) /* didn't translate */
if (savname == NULL) /* didn't translate */
savname = name;
}
}
@ -1724,6 +1721,66 @@ char mac_string[32];
eth_mac_fmt(mac, mac_string);
sim_debug(dev->dbit, dev->dptr, "Determining Address Conflict for MAC address: %s\n", mac_string);
/* The process of checking address conflicts is used in two ways:
1) to determine the behavior of the currently running packet
delivery facility regarding whether it may receive copies
of every packet sent (and how many).
2) to verify if a MAC address which this facility is planning
to use as the source address of packets is already in use
by some other node on the local network
Case #1, doesn't require (and explicitly doesn't want) any
interaction or response from other systems on the LAN so
therefore no considerations regarding switch packet forwarding
are important. Meanwhile, Case #2 does require responses from
other components on the LAN to provide useful functionality.
The original designers of this mechanism did this when essentially
all LANs were single collision domains (i.e. ALL nodes which might
be affected by an address conflict were physically present on a single
Ethernet cable which might have been extended by a couple of repeaters).
Since that time, essentially no networks are single collision domains.
Thick and thinwire Ethernet cables dont exist and very few networks
even have hubs. Today, essentially all LANs are deployed using one
or more layers of network switches. In a switched LAN environment, the
switches on the LAN learn which ports on the LAN source traffic from
which MAC addresses and then forward traffic destined for particular
MAC address to the appropriate ports. If a particular MAC address is
already in use somewhere on the LAN, then the switches know where
it is. The host based test using the loopback protocol is poorly
designed to detect this condition. This test is performed by the host
first changing the devices Physical MAC address to the address which
is to be tested, and then sending a loopback packet FROM AND TO this
MAC address with a loopback reply to be sent by a system which may be
currently using the MAC address. If no reply is received, then the
MAC address is presumed to be unused. The sending of this packet will
result in its delivery to the right system since the switch port/MAC
address tables know where to deliver packets destined to this MAC
address, however the response it generates wont be delivered to the
system performing the test since the switches on the LAN wont know
about the local port being the right target for packets with this MAC
address. A better test design to detect these conflicts would be for
the testing system to send a loopback packet FROM the current physical
MAC address (BEFORE changing it) TO the MAC address being tested with
the loopback response coming to the current physical MAC address of
the device. If a response is received, then the address is in use and
the attempt to change the devices MAC address should fail. Since we
cant change the software running in these simulators to implement this
better conflict detection approach, we can still do the right thing
in the sim_ether layer. Were already handling the loopback test
packets specially since we always had to avoid receiving the packets
which were being sent, but needed to allow for the incoming loopback
packets to be properly dealt with. We can extend this current special
handling to change outgoing loopback to self packets to have source
AND loopback destination addresses in the packets to be the host NICs
physical address. The switch network will already know the correct
MAC/port relationship for the host NICs physical address, so loopback
response packets will be delivered as needed.
Code in _eth_write and _eth_callback provide the special handling to
perform the described loopback packet adjustments, and code in
eth_filter_hash makes sure that the loopback response packets are received.
*/
/* build a loopback forward request packet */
memset (&send, 0, sizeof(ETH_PACK));
send.len = ETH_MIN_PACKET; /* minimum packet size */
@ -1743,7 +1800,7 @@ if (status != SCPE_OK) {
char *msg;
msg = "Eth: Error Transmitting packet: %s\r\n"
"You may need to run as root, or install a libpcap version\r\n"
"which is at least 0.9 from www.tcpdump.org\r\n";
"which is at least 0.9 from your OS vendor or www.tcpdump.org\r\n";
printf(msg, strerror(errno));
if (sim_log) fprintf (sim_log, msg, strerror(errno));
return status;
@ -1755,7 +1812,10 @@ sim_os_ms_sleep (300); /* time for a conflicting host to respond */
do {
memset (&recv, 0, sizeof(ETH_PACK));
status = eth_read (dev, &recv, NULL);
if (memcmp(send.msg, recv.msg, 14)== 0)
if (((0 == memcmp(send.msg+12, recv.msg+12, 2)) && /* Protocol Match */
(0 == memcmp(send.msg, recv.msg+6, 6)) && /* Source Match */
(0 == memcmp(send.msg+6, recv.msg, 6))) || /* Destination Match */
(0 == memcmp(send.msg, recv.msg, 14))) /* Packet Match (Reflection) */
responses++;
} while (recv.len > 0);
@ -1792,12 +1852,16 @@ if (!packet) return SCPE_ARG;
/* make sure packet is acceptable length */
if ((packet->len >= ETH_MIN_PACKET) && (packet->len <= ETH_MAX_PACKET)) {
int loopback_self_frame = LOOPBACK_SELF_FRAME(dev->physical_addr, packet->msg);
int loopback_self_frame = LOOPBACK_SELF_FRAME(packet->msg, packet->msg);
eth_packet_trace (dev, packet->msg, packet->len, "writing");
/* record sending of loopback packet (done before actual send to avoid race conditions with receiver) */
if (loopback_self_frame) {
if (dev->have_host_nic_phy_addr) {
memcpy(&packet->msg[6], dev->host_nic_phy_hw_addr, sizeof(ETH_MAC));
memcpy(&packet->msg[18], dev->host_nic_phy_hw_addr, sizeof(ETH_MAC));
}
#ifdef USE_READER_THREAD
pthread_mutex_lock (&dev->self_lock);
#endif
@ -1806,7 +1870,7 @@ if ((packet->len >= ETH_MIN_PACKET) && (packet->len <= ETH_MAX_PACKET)) {
#ifdef USE_READER_THREAD
pthread_mutex_unlock (&dev->self_lock);
#endif
}
}
/* dispatch write request (synchronous; no need to save write info to dev) */
switch (dev->eth_api) {
@ -2346,6 +2410,17 @@ int from_me = 0;
int i;
int bpf_used;
if ((dev->have_host_nic_phy_addr) &&
(LOOPBACK_PHYSICAL_RESPONSE(dev->host_nic_phy_hw_addr, dev->physical_addr, data))) {
u_char *datacopy = malloc(header->len);
memcpy(datacopy, data, header->len);
memcpy(datacopy, dev->physical_addr, sizeof(ETH_MAC));
memcpy(datacopy+18, dev->physical_addr, sizeof(ETH_MAC));
_eth_callback(info, header, datacopy);
free(datacopy);
return;
}
switch (dev->eth_api) {
case ETH_API_PCAP:
#ifdef USE_BPF
@ -2380,7 +2455,9 @@ switch (dev->eth_api) {
}
/* 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)) ||
(dev->have_host_nic_phy_addr &&
LOOPBACK_PHYSICAL_REFLECTION(dev->host_nic_phy_hw_addr, data))) {
#ifdef USE_READER_THREAD
pthread_mutex_lock (&dev->self_lock);
#endif
@ -2397,7 +2474,7 @@ if (LOOPBACK_SELF_FRAME(dev->physical_addr, data)) {
#ifdef USE_READER_THREAD
pthread_mutex_unlock (&dev->self_lock);
#endif
}
}
if (bpf_used ? to_me : (to_me && !from_me)) {
if (header->len > ETH_MIN_JUMBO_FRAME) {
@ -2689,6 +2766,10 @@ if ((addr_count) && (dev->reflections > 0)) {
memcpy(dev->physical_addr, &dev->filter_address[i], sizeof(ETH_MAC));
/* let packets through where dst and src are the same as our physical address */
sprintf (&buf[strlen(buf)], " or ((ether dst %s) and (ether src %s))", mac, mac);
if (dev->have_host_nic_phy_addr) {
eth_mac_fmt(&dev->host_nic_phy_hw_addr, mac);
sprintf(&buf[strlen(buf)], "or ((ether dst %s) and (ether proto 0x9000))", mac);
}
break;
}
}
@ -2697,8 +2778,10 @@ if ((0 == strlen(buf)) && (!dev->promiscuous)) /* Empty filter means match nothi
strcpy(buf, "ether host fe:ff:ff:ff:ff:ff"); /* this should be a good match nothing filter */
sim_debug(dev->dbit, dev->dptr, "BPF string is: |%s|\n", buf);
/* get netmask, which is required for compiling */
if ((dev->eth_api == ETH_API_PCAP) && (pcap_lookupnet(dev->handle, &bpf_subnet, &bpf_netmask, errbuf)<0))
/* get netmask, which is a required argument for compiling. The value,
in our case isn't actually interesting since the filters we generate
aren't referencing IP fields, networks or values */
if ((dev->eth_api == ETH_API_PCAP) && (pcap_lookupnet(dev->name, &bpf_subnet, &bpf_netmask, errbuf)<0))
bpf_netmask = 0;
#ifdef USE_BPF
@ -2823,7 +2906,6 @@ for (i=0; i<used; i++) {
#ifdef USE_TAP_NETWORK
if (used < max) {
list[used].num = used;
#if defined(__OpenBSD__)
sprintf(list[used].name, "%s", "tap:tunN");
#else
@ -2835,7 +2917,6 @@ if (used < max) {
#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;
@ -2853,6 +2934,7 @@ pcap_if_t* alldevs;
pcap_if_t* dev;
char errbuf[PCAP_ERRBUF_SIZE];
memset(list, 0, max*sizeof(*list));
/* retrieve the device list */
if (pcap_findalldevs(&alldevs, errbuf) == -1) {
char* msg = "Eth: error in pcap_findalldevs: %s\r\n";
@ -2861,15 +2943,13 @@ if (pcap_findalldevs(&alldevs, errbuf) == -1) {
}
else {
/* copy device list into the passed structure */
for (i=0, dev=alldevs; dev; dev=dev->next) {
for (i=0, dev=alldevs; dev && (i < max); dev=dev->next, ++i) {
if ((dev->flags & PCAP_IF_LOOPBACK) || (!strcmp("any", dev->name))) continue;
list[i].num = i;
sprintf(list[i].name, "%s", dev->name);
strncpy(list[i].name, dev->name, sizeof(list[i].name)-1);
if (dev->description)
sprintf(list[i].desc, "%s", dev->description);
strncpy(list[i].desc, dev->description, sizeof(list[i].desc)-1);
else
sprintf(list[i].desc, "%s", "No description available");
if (i++ >= max) break;
strncpy(list[i].desc, "No description available", sizeof(list[i].desc)-1);
}
/* free device list */

View file

@ -130,19 +130,36 @@
#define ETH_MIN_PACKET 60 /* minimum ethernet packet size */
#define ETH_MAX_PACKET 1514 /* maximum ethernet packet size */
#define ETH_MAX_JUMBO_FRAME 65536 /* maximum ethernet jumbo frame size (or Offload Segment Size) */
#define ETH_MAX_DEVICE 10 /* maximum ethernet devices */
#define ETH_MAX_DEVICE 20 /* maximum ethernet devices */
#define ETH_CRC_SIZE 4 /* ethernet CRC size */
#define ETH_FRAME_SIZE (ETH_MAX_PACKET+ETH_CRC_SIZE) /* ethernet maximum frame size */
#define ETH_MIN_JUMBO_FRAME ETH_MAX_PACKET /* Threshold size for Jumbo Frame Processing */
#define LOOPBACK_SELF_FRAME(phy_mac, msg) \
((memcmp(phy_mac, msg , 6) == 0) && \
(memcmp(phy_mac, msg+6, 6) == 0) && \
((msg)[12] == 0x90) && ((msg)[13] == 0x00) && \
(((msg)[12] == 0x90) && ((msg)[13] == 0x00) && \
((msg)[14] == 0x00) && ((msg)[15] == 0x00) && \
((msg)[16] == 0x02) && ((msg)[17] == 0x00) && \
(memcmp(phy_mac, msg+18, 6) == 0) && \
((msg)[24] == 0x01) && ((msg)[25] == 0x00))
((msg)[24] == 0x01) && ((msg)[25] == 0x00) && \
(memcmp(phy_mac, (msg), 6) == 0) && \
(memcmp(phy_mac, (msg)+6, 6) == 0) && \
(memcmp(phy_mac, (msg)+18, 6) == 0))
#define LOOPBACK_PHYSICAL_RESPONSE(host_phy, phy_mac, msg) \
(((msg)[12] == 0x90) && ((msg)[13] == 0x00) && \
((msg)[14] == 0x08) && ((msg)[15] == 0x00) && \
((msg)[16] == 0x02) && ((msg)[17] == 0x00) && \
((msg)[24] == 0x01) && ((msg)[25] == 0x00) && \
(memcmp(host_phy, (msg)+18, 6) == 0) && \
(memcmp(host_phy, (msg), 6) == 0) && \
(memcmp(phy_mac, (msg)+6, 6) == 0))
#define LOOPBACK_PHYSICAL_REFLECTION(host_phy, msg) \
(((msg)[12] == 0x90) && ((msg)[13] == 0x00) && \
((msg)[14] == 0x00) && ((msg)[15] == 0x00) && \
((msg)[16] == 0x02) && ((msg)[17] == 0x00) && \
((msg)[24] == 0x01) && ((msg)[25] == 0x00) && \
(memcmp(host_phy, (msg)+6, 6) == 0) && \
(memcmp(host_phy, (msg)+18, 6) == 0))
struct eth_packet {
uint8 msg[ETH_FRAME_SIZE]; /* ethernet frame (message) */
@ -168,7 +185,6 @@ struct eth_queue {
};
struct eth_list {
int num;
char name[ETH_DEV_NAME_MAX];
char desc[ETH_DEV_DESC_MAX];
};