From f2b583759a2d0f684029769968d9eecd23819c72 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 6 Feb 2012 10:03:09 -0800 Subject: [PATCH 01/11] Clarified operational requirements for SIM_ASYNCH_IO on Windows --- 0readmeAsynchIO.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/0readmeAsynchIO.txt b/0readmeAsynchIO.txt index 28a8205b..00f5b7c6 100644 --- a/0readmeAsynchIO.txt +++ b/0readmeAsynchIO.txt @@ -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 From 98e343f43f741915fce5c12c4f75cff30aeaa9f4 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 17 Feb 2012 16:33:06 -0800 Subject: [PATCH 02/11] Fixed call to pcap_lookupnet to actually use the device name as the argument. --- sim_ether.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sim_ether.c b/sim_ether.c index 82057c3c..454be442 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -2697,8 +2697,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 From 4838d1f7ddc5126cd12cc4a90e8bebca16a2fb2d Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Sat, 25 Feb 2012 08:45:52 -0800 Subject: [PATCH 03/11] Align VHD disk data blocks for optimal performance when a VHD resides on storage with 4K sector size. --- sim_disk.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sim_disk.c b/sim_disk.c index 7d95b794..96679193 100644 --- a/sim_disk.c +++ b/sim_disk.c @@ -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, From 153e9053393c21a5a77b8b02227b633c22c8851e Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Sat, 25 Feb 2012 08:56:25 -0800 Subject: [PATCH 04/11] Added checking to detect unexpected file sizes for ROM image files. This can happen if the file was transferred or unpacked incorrectly and in the process tried to convert line endings rather than passing the file's contents unmodified. --- sim_BuildROMs.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/sim_BuildROMs.c b/sim_BuildROMs.c index d895a4bc..3a60e248 100644 --- a/sim_BuildROMs.c +++ b/sim_BuildROMs.c @@ -53,7 +53,8 @@ #include #endif -int sim_make_ROM_include(const char *rom_filename, +int sim_make_ROM_include(const char *rom_filename, + int expected_size, const char *include_filename, const char *rom_array_name) { @@ -70,13 +71,21 @@ if (NULL == (rFile = fopen (rom_filename, "rb"))) { 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", (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; @@ -156,7 +165,7 @@ 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"); +sim_make_ROM_include ("VAX/ka655x.bin", 131072, "VAX/vax_ka655x_bin.h", "vax_ka655x_bin"); +sim_make_ROM_include ("VAX/vmb.exe", 44544, "VAX/vax780_vmb_exe.h", "vax780_vmb_exe"); exit(0); } From f09637186db2ea12d8659bc5189d5b78d04eef0a Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Sun, 26 Feb 2012 10:13:20 -0800 Subject: [PATCH 05/11] Change default makefile behavior to prefer OS provided libpcap components over www.tcpdump.org components and to suggest that the build should be done with the OS libpcap-dev package. --- makefile | 119 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 77 insertions(+), 42 deletions(-) diff --git a/makefile b/makefile index a9d10382..3abeb767 100644 --- a/makefile +++ b/makefile @@ -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) From cf49864327021a9d9adb35288f6d21b7682e04d6 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Sun, 26 Feb 2012 12:38:07 -0800 Subject: [PATCH 06/11] More robust detection of file transfer/conversion errors in ROM/boot code --- VAX/vax780_vmb_exe.h | 9 ++++++--- VAX/vax_ka655x_bin.h | 9 ++++++--- sim_BuildROMs.c | 24 +++++++++++++++++++----- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/VAX/vax780_vmb_exe.h b/VAX/vax780_vmb_exe.h index e15fe616..6b6af820 100644 --- a/VAX/vax780_vmb_exe.h +++ b/VAX/vax780_vmb_exe.h @@ -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 */ diff --git a/VAX/vax_ka655x_bin.h b/VAX/vax_ka655x_bin.h index 7fdea0c6..6cc64347 100644 --- a/VAX/vax_ka655x_bin.h +++ b/VAX/vax_ka655x_bin.h @@ -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 */ diff --git a/sim_BuildROMs.c b/sim_BuildROMs.c index 3a60e248..ba573de3 100644 --- a/sim_BuildROMs.c +++ b/sim_BuildROMs.c @@ -55,6 +55,7 @@ int sim_make_ROM_include(const char *rom_filename, int expected_size, + int expected_checksum, const char *include_filename, const char *rom_array_name) { @@ -65,6 +66,7 @@ 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)); @@ -76,7 +78,7 @@ if (stat (rom_filename, &statb)) { return -1; } if (statb.st_size != expected_size) { - printf ("Error: ROM file '%s' has an unexpected size: %d vs %d\n", (int)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"); @@ -91,6 +93,17 @@ if (statb.st_size != fread (ROMData, sizeof(*ROMData), statb.st_size, rFile)) { return -1; } fclose (rFile); +for (c=0; c Date: Tue, 28 Feb 2012 12:09:05 -0800 Subject: [PATCH 07/11] Fixed internal loopback packet processing. We should only respond to loopback packets addressed to the physical MAC address OR the Broadcast address OR a Multicast address we're listening to (we may receive other loopback packets if we're in promiscuous mode but we should not respond to them). --- PDP11/pdp11_xq.c | 10 ++++++++++ PDP11/pdp11_xu.c | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/PDP11/pdp11_xq.c b/PDP11/pdp11_xq.c index c4eb46e7..f3b3ce1f 100644 --- a/PDP11/pdp11_xq.c +++ b/PDP11/pdp11_xq.c @@ -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 */ diff --git a/PDP11/pdp11_xu.c b/PDP11/pdp11_xu.c index 36e97ca0..05bccaed 100644 --- a/PDP11/pdp11_xu.c +++ b/PDP11/pdp11_xu.c @@ -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; From 4ce92b4f38c55931e1573711c6b6f03d996c5812 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 28 Feb 2012 13:31:46 -0800 Subject: [PATCH 08/11] Fixed overrun bug in eth_devices. Fixed device name compare in eth_getname_byname to compare the whole name Removed unused num field in eth_list structure Extended the number of devices supported since some platforms may have many libpcap accessable devices but only a few basic Ethernet ones --- sim_ether.c | 34 ++++++++++++++-------------------- sim_ether.h | 3 +-- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/sim_ether.c b/sim_ether.c index 454be442..2de2564f 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -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 min) min = len; for (i=0; inext) { + 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 */ diff --git a/sim_ether.h b/sim_ether.h index 2314e835..8200116e 100644 --- a/sim_ether.h +++ b/sim_ether.h @@ -130,7 +130,7 @@ #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 */ @@ -168,7 +168,6 @@ struct eth_queue { }; struct eth_list { - int num; char name[ETH_DEV_NAME_MAX]; char desc[ETH_DEV_DESC_MAX]; }; From 4ab52659be60bbb0109818babc9056e9e67c8fe4 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 28 Feb 2012 14:02:49 -0800 Subject: [PATCH 09/11] Provided Console Control Event explanation as comments in the sim_console code. --- sim_console.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sim_console.c b/sim_console.c index bf023c49..3bffbf42 100644 --- a/sim_console.c +++ b/sim_console.c @@ -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) { From 4f6ad323956e80edb293867bcabb7941fd5b80dd Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 28 Feb 2012 14:10:08 -0800 Subject: [PATCH 10/11] Fixed MAC Address Conflict detection support. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VMS engineers designed the address conflict strategy 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 don’t 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 device’s 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 won’t be delivered to the system performing the test since the switches on the LAN won’t 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 device’s MAC address should fail. Since we can’t 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. We’re 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 NIC’s physical address. The switch network will already know the correct MAC/port relationship for the host NIC’s physical address, so loopback response packets will be delivered as needed. --- sim_ether.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++----- sim_ether.h | 27 +++++++++++--- 2 files changed, 115 insertions(+), 14 deletions(-) diff --git a/sim_ether.c b/sim_ether.c index 2de2564f..3cc40ace 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -1721,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 don’t 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 device’s 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 won’t be delivered to the + system performing the test since the switches on the LAN won’t 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 device’s MAC address should fail. Since we + can’t 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. We’re 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 NIC’s + physical address. The switch network will already know the correct + MAC/port relationship for the host NIC’s 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 */ @@ -1740,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; @@ -1752,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); @@ -1789,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 @@ -1803,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) { @@ -2343,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 @@ -2377,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 @@ -2394,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) { @@ -2686,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; } } @@ -2694,9 +2778,9 @@ 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 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 */ +/* 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; diff --git a/sim_ether.h b/sim_ether.h index 8200116e..29c9e7a8 100644 --- a/sim_ether.h +++ b/sim_ether.h @@ -136,13 +136,30 @@ #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) */ From 9386369bd5d3e3114b8b4bf7bf924e457984e367 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 28 Feb 2012 17:56:41 -0800 Subject: [PATCH 11/11] Made dynamic libreadline loading more robust for some systems --- scp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scp.c b/scp.c index 3e5dd88b..2d7b5deb 100644 --- a/scp.c +++ b/scp.c @@ -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");