From e410733781d5ac63db032e37ff63166f0414ea10 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 23 Sep 2011 16:26:00 -0700 Subject: [PATCH 01/30] fixed makefile to correctly use readline on x64 Linux builds which have libreadline available --- makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index 05dcee42..92879ab7 100644 --- a/makefile +++ b/makefile @@ -45,8 +45,8 @@ ifeq ($(WIN32),) OS_CCDEFS += -DSIM_ASYNCH_IO -DUSE_READER_THREAD OS_LDFLAGS += -lpthread endif - ifeq (readline,$(shell if $(TEST) -e /usr/lib/libreadline.$(LIBEXT) -o -e /opt/sfw/lib/libreadline.a; then echo readline; fi)) - ifeq (readline_h,$(shell if $(TEST) -e /usr/include/readline/readline.h; then echo readline_h; fi)) + ifeq (readline,$(shell if $(TEST) -e /usr/lib/libreadline.$(LIBEXT) -o -e /usr/lib64/libreadline.$(LIBEXT) -o -e /opt/sfw/lib/libreadline.a; then echo readline; fi)) + ifeq (readline_h,$(shell if $(TEST) -e /usr/include/readline/readline.h -o -e /usr/include/readline.h; then echo readline_h; fi)) # Use Locally installed and available readline support ifeq (ncurses,$(shell if $(TEST) -e /usr/lib/libncurses.$(LIBEXT) -o -e /opt/sfw/lib/libncurses.a; then echo ncurses; fi)) OS_CCDEFS += -DHAVE_READLINE From 6e098021c2f2d8ef5f352ef22ffd8bb9e2a222f1 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Sun, 25 Sep 2011 08:14:58 -0700 Subject: [PATCH 02/30] Documented current state of sim_ether, etc. and included references for new OpenVMS Integrety (IA64) support. --- 0readme_ethernet.txt | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/0readme_ethernet.txt b/0readme_ethernet.txt index 9c8c7401..5bdf18a6 100644 --- a/0readme_ethernet.txt +++ b/0readme_ethernet.txt @@ -134,6 +134,11 @@ Windows notes: Building on Windows: + Building with MinGW can use the provided makefile following the instructions + below. Alternatively, you can use the free Visual C++ Express 2008 or 2010 + interactive development environments. Read the file + ".\Visual Studio Projects\0ReadMe_Projects.txt" for details. + 1. Install WinPCAP 4.x runtime and the WinPCAP Developer's kit. 2. Put the required .h files (bittypes,devioctl,ip6_misc,pcap,pcap-stdinc @@ -159,8 +164,11 @@ Linux, {Free|Net|Open}BSD, OS/X, and Un*x notes: ----- WARNING ----- WARNING ----- WARNING ----- WARNING ----- WARNING ----- Sim_Ether has been reworked to be more universal; because of this, you will -need to get a version of libpcap that is 0.9 or greater. This can be -downloaded from www.tcpdump.org - see the comments at the top of Sim_ether.c +need to get a version of libpcap that is 0.9 or greater. All current Linux +distributions provide a libpcap-dev package which has the needed version +of libpcap and the required components to build applications using it. +If you are running an older Linux OS, you can download and build the required +library from www.tcpdump.org - see the comments at the top of Sim_ether.c for details. ----- WARNING ----- WARNING ----- WARNING ----- WARNING ----- WARNING ----- @@ -187,11 +195,13 @@ for details. will be welcomed. 2. If you want to use TAP devices, and any surrounding system network/bridge - setup must be done before running SIMH. + setup must be done before running SIMH. However, once that is done + (possibly at system boot time), using the TAP devices can be done without + root privileges. Building on Linux, {Free|Net|Open}BSD, OS/X, Un*x: - 1. Get/make/install the libpcap package for your operating system. Sources: + 1. Get/make/install the libpcap-dev package for your operating system. Sources: All : http://www.tcpdump.org/ Older versions of libpcap can be found, for various systems, at: Linux : search for your variant on http://rpmfind.net @@ -214,7 +224,7 @@ Building on Linux, {Free|Net|Open}BSD, OS/X, Un*x: ------------------------------------------------------------------------------- -OpenVMS Alpha notes: +OpenVMS Alpha and OpenVMS Integrety (IA64) notes: 1. Ethernet support will only work on Alpha VMS 7.3-1 or later, which is when required VCI promiscuous mode support was added. Hobbyists can get the required version of VMS from the OpenVMS Alpha Hobbyist Kit 3.0. @@ -247,10 +257,10 @@ OpenVMS Alpha notes: adapter prior trying to connect with SIMH, or the host may crash. The execlet is not written to create an I/O structure for the device. -Building on OpenVMS Alpha: +Building on OpenVMS Alpha and OpenVMS Integrety (IA64): The current descrip.mms file will build simulators capable of using Ethernet support with them automatically. These currently are: VAX, - PDP11, and PDP10. The descrip.mms driven builds will also build the + VAX780, and PDP11. The descrip.mms driven builds will also build the pcap library and build and install the VCI execlet. 1. Fetch the VMS-PCAP zip file from: @@ -320,7 +330,16 @@ Dave =============================================================================== Change Log =============================================================================== - + + 07-Jul-11 MB VMS Pcap (from Mike Burke) + - Fixed Alpha issues + - Added OpenVMS Integrety support + 17-Aug-11 RMS Fix from Sergey Oboguev relating to XU and XQ Auto Config and + vector assignments + 12-Aug-11 MP Cleaned up payload length determination + Fixed race condition detecting reflections when threaded + reading and writing is enabled + 20-Apr-11 MP Fixed save/restore behavior 12-Jan-11 DTH Added SHOW XU FILTERS modifier 11-Jan-11 DTH Corrected DEUNA/DELUA SELFTEST command, enabling use by VMS 3.7, VMS 4.7, and Ultrix 1.1 From 034e749fce30aa9f743f1b1a242dae57e9dea30b Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Sun, 25 Sep 2011 08:16:40 -0700 Subject: [PATCH 03/30] Added SET ASYNCH and SET NOASYNCH commands to dynamically enable or disable Asynchronous I/O support --- 0readmeAsynchIO.txt | 3 ++ VAX/vax_stddev.c | 1 + scp.c | 74 +++++++++++++++++++++++++++++++++++++++++++++ sim_defs.h | 1 + sim_disk.c | 21 +++++++------ sim_tape.c | 19 +++++++----- 6 files changed, 102 insertions(+), 17 deletions(-) diff --git a/0readmeAsynchIO.txt b/0readmeAsynchIO.txt index b41cf4f9..28a8205b 100644 --- a/0readmeAsynchIO.txt +++ b/0readmeAsynchIO.txt @@ -5,6 +5,9 @@ Theory of operation. Features. - Optional Use. Build with or without SIM_ASYNCH_IO defined and simulators will still build and perform correctly when run. + Additionmally, a simulator built with SIM_ASYNCH_IO defined can + dynamically disable and reenable asynchronous operation with + the scp commands SET NOASYNCH and SET ASYNCH respectively. - Consistent Save/Restore state. The state of a simulator saved on a simulator with (or without) Asynch support can be restored on any simulator of the same version with or without Asynch diff --git a/VAX/vax_stddev.c b/VAX/vax_stddev.c index 881fcefb..4aa97572 100644 --- a/VAX/vax_stddev.c +++ b/VAX/vax_stddev.c @@ -180,6 +180,7 @@ REG clk_reg[] = { { DRDATA (POLL, tmr_poll, 24), REG_NZ + PV_LEFT + REG_HRO }, { DRDATA (TPS, clk_tps, 8), REG_NZ + PV_LEFT }, #if defined (SIM_ASYNCH_IO) + { DRDATA (ASYNCH, sim_asynch_enabled, 1), PV_LEFT }, { DRDATA (LATENCY, sim_asynch_latency, 32), PV_LEFT }, { DRDATA (INST_LATENCY, sim_asynch_inst_latency, 32), PV_LEFT }, #endif diff --git a/scp.c b/scp.c index 47a70ca4..7e1e487b 100644 --- a/scp.c +++ b/scp.c @@ -23,6 +23,17 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 25-Sep-11 MP Added the ability for a simulator built with + SIM_ASYNCH_IO to change whether I/O is actually done + asynchronously by the new scp command SET ASYNCH and + SET NOASYNCH + 22-Sep-11 MP Added signal catching of SIGHUP and SIGTERM to cause + simulator STOP. This allows an externally signalled + event (i.e. system shutdown, or logoff) to signal a + running simulator of these events and to allow + reasonable actions to be taken. This will facilitate + running a simulator as a 'service' on *nix platforms, + given a sufficiently flexible simulator .ini file. 20-Apr-11 MP Added expansion of %STATUS% and %TSTATUS% in do command arguments. STATUS is the numeric value of the last command error status and TSTATUS is the text message @@ -271,6 +282,7 @@ pthread_mutex_t sim_asynch_lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t sim_asynch_wake = PTHREAD_COND_INITIALIZER; pthread_t sim_asynch_main_threadid; struct sim_unit *sim_asynch_queue = NULL; +t_bool sim_asynch_enabled = TRUE; int32 sim_asynch_check; int32 sim_asynch_latency = 4000; /* 4 usec interrupt latency */ int32 sim_asynch_inst_latency = 20; /* assume 5 mip simulator */ @@ -387,6 +399,7 @@ t_stat dep_addr (int32 flag, char *cptr, t_addr addr, DEVICE *dptr, t_stat step_svc (UNIT *ptr); void sub_args (char *instr, char *tmpbuf, int32 maxstr, char *do_arg[]); t_stat set_on (int32 flag, char *cptr); +t_stat set_asynch (int32 flag, char *cptr); /* Global data */ @@ -605,6 +618,8 @@ static CTAB cmd_table[] = { "set nobreak clear breakpoints\n" "set throttle x{M|K|%%} set simulation rate\n" "set nothrottle set simulation rate to maximum\n" + "set asynch enable asynchronous I/O\n" + "set noasynch disable asynchronous I/O\n" "set OCT|DEC|HEX set device display radix\n" "set ENABLED enable device\n" "set DISABLED disable device\n" @@ -628,6 +643,7 @@ static CTAB cmd_table[] = { "sh{ow} q{ueue} show event queue\n" "sh{ow} ti{me} show simulated time\n" "sh{ow} th{rottle} show simulation rate\n" + "sh{ow} a{synch} show asynchronouse I/O state\n" "sh{ow} ve{rsion} show simulator version\n" "sh{ow} RADIX show device display radix\n" "sh{ow} DEBUG show device debug flags\n" @@ -1281,6 +1297,61 @@ if ((sim_do_depth != 0) && return SCPE_OK; } +/* Set asynch/noasynch routine */ + +t_stat sim_set_asynch (int32 flag, char *cptr) +{ +if (cptr && (*cptr != 0)) /* now eol? */ + return SCPE_2MARG; +#ifdef SIM_ASYNCH_IO +if (flag == sim_asynch_enabled) /* already set correctly? */ + return SCPE_OK; +sim_asynch_enabled = flag; +if (1) { + uint32 i, j; + DEVICE *dptr; + UNIT *uptr; + + /* Call unit flush routines to report asynch status change to device layer */ + for (i = 1; (dptr = sim_devices[i]) != NULL; i++) { /* flush attached files */ + for (j = 0; j < dptr->numunits; j++) { /* if not buffered in mem */ + uptr = dptr->units + j; + if ((uptr->flags & UNIT_ATT) && /* attached, */ + !(uptr->flags & UNIT_BUF) && /* not buffered, */ + (uptr->fileref)) /* real file, */ + if (uptr->io_flush) /* unit specific flush routine */ + uptr->io_flush (uptr); + } + } + } +if (!sim_quiet) + printf ("Asynchronous I/O %sabled\n", sim_asynch_enabled ? "en" : "dis"); +if (sim_log) + fprintf (sim_log, "Asynchronous I/O %sabled\n", sim_asynch_enabled ? "en" : "dis"); +return SCPE_OK; +#else +if (!sim_quiet) + printf ("Asynchronous I/O is not available in this simulator\n"); +if (sim_log) + fprintf (sim_log, "Asynchronous I/O is not available in this simulator\n"); +return SCPE_NOFNC; +#endif +} + +/* Show asynch routine */ + +t_stat sim_show_asynch (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +if (cptr && (*cptr != 0)) + return SCPE_2MARG; +#ifdef SIM_ASYNCH_IO +fprintf (st, "Asynchronous I/O is %sabled\n", (sim_asynch_enabled) ? "en" : "dis"); +#else +fprintf (st, "Asynchronous I/O is not available in this simulator\n"); +#endif +return SCPE_OK; +} + /* Set command */ t_stat set_cmd (int32 flag, char *cptr) @@ -1305,6 +1376,8 @@ static CTAB set_glob_tab[] = { { "NODEBUG", &sim_set_deboff, 0 }, /* deprecated */ { "THROTTLE", &sim_set_throt, 1 }, { "NOTHROTTLE", &sim_set_throt, 0 }, + { "ASYNCH", &sim_set_asynch, 1 }, + { "NOASYNCH", &sim_set_asynch, 0 }, { "ON", &set_on, 1 }, { "NOON", &set_on, 0 }, { NULL, NULL, 0 } @@ -1570,6 +1643,7 @@ static SHTAB show_glob_tab[] = { { "TELNET", &sim_show_telnet, 0 }, /* deprecated */ { "DEBUG", &sim_show_debug, 0 }, /* deprecated */ { "THROTTLE", &sim_show_throt, 0 }, + { "ASYNCH", &sim_show_asynch, 0 }, { "ON", &show_on, 0 }, { NULL, NULL, 0 } }; diff --git a/sim_defs.h b/sim_defs.h index 91abc4ef..4df30c98 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -565,6 +565,7 @@ extern pthread_cond_t sim_asynch_wake; extern pthread_t sim_asynch_main_threadid; extern struct sim_unit *sim_asynch_queue; extern t_bool sim_idle_wait; +extern t_bool sim_asynch_enabled; extern int32 sim_asynch_check; extern int32 sim_asynch_latency; extern int32 sim_asynch_inst_latency; diff --git a/sim_disk.c b/sim_disk.c index 5dbbb012..f38c4b45 100644 --- a/sim_disk.c +++ b/sim_disk.c @@ -408,15 +408,17 @@ return SCPE_NOFNC; struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; pthread_attr_t attr; -ctx->asynch_io = 1; +ctx->asynch_io = sim_asynch_enabled; ctx->asynch_io_latency = latency; -pthread_mutex_init (&ctx->io_lock, NULL); -pthread_cond_init (&ctx->io_cond, NULL); -pthread_attr_init(&attr); -pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); -pthread_create (&ctx->io_thread, &attr, _disk_io, (void *)uptr); -pthread_attr_destroy(&attr); -uptr->a_check_completion = _disk_completion_dispatch; +if (ctx->asynch_io) { + pthread_mutex_init (&ctx->io_lock, NULL); + pthread_cond_init (&ctx->io_cond, NULL); + pthread_attr_init(&attr); + pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); + pthread_create (&ctx->io_thread, &attr, _disk_io, (void *)uptr); + pthread_attr_destroy(&attr); + uptr->a_check_completion = _disk_completion_dispatch; + } #endif return SCPE_OK; } @@ -723,7 +725,8 @@ uint32 f = DK_GET_FMT (uptr); #if defined (SIM_ASYNCH_IO) sim_disk_clr_async (uptr); -sim_disk_set_async (uptr, 0); +if (sim_asynch_enabled) + sim_disk_set_async (uptr, 0); #endif switch (f) { /* case on format */ case DKUF_F_STD: /* Simh */ diff --git a/sim_tape.c b/sim_tape.c index d50a4887..a71aa54b 100644 --- a/sim_tape.c +++ b/sim_tape.c @@ -320,14 +320,16 @@ return SCPE_NOFNC; struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; pthread_attr_t attr; -ctx->asynch_io = 1; +ctx->asynch_io = sim_asynch_enabled; ctx->asynch_io_latency = latency; -pthread_mutex_init (&ctx->io_lock, NULL); -pthread_cond_init (&ctx->io_cond, NULL); -pthread_attr_init(&attr); -pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); -pthread_create (&ctx->io_thread, &attr, _tape_io, (void *)uptr); -pthread_attr_destroy(&attr); +if (ctx->asynch_io) { + pthread_mutex_init (&ctx->io_lock, NULL); + pthread_cond_init (&ctx->io_cond, NULL); + pthread_attr_init(&attr); + pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); + pthread_create (&ctx->io_thread, &attr, _tape_io, (void *)uptr); + pthread_attr_destroy(&attr); + } uptr->a_check_completion = _tape_completion_dispatch; #endif return SCPE_OK; @@ -362,7 +364,8 @@ static void _sim_tape_io_flush (UNIT *uptr) { #if defined (SIM_ASYNCH_IO) sim_tape_clr_async (uptr); -sim_tape_set_async (uptr, 0); +if (sim_asynch_enabled) + sim_tape_set_async (uptr, 0); #endif fflush (uptr->fileref); } From 2753c4a3dc76140716141ab81b23a3aeb49f74ea Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 26 Sep 2011 11:09:08 -0700 Subject: [PATCH 04/30] Fixed DO command to properly return and display status from nested invocations. --- scp.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/scp.c b/scp.c index 7e1e487b..ed2e4ab4 100644 --- a/scp.c +++ b/scp.c @@ -1022,13 +1022,6 @@ do { (cmdp->action != &on_cmd) && (cmdp->action != &echo_cmd))) sim_last_cmd_stat = stat; /* save command error status */ - staying = (stat != SCPE_EXIT) && /* decide if staying */ - (stat != SCPE_AFAIL) && - (!errabort || (stat < SCPE_BASE) || (stat == SCPE_STEP)); - if ((stat == SCPE_AFAIL) && /* handle special case AFAIL */ - sim_on_check[sim_do_depth] && /* and use trap action if defined */ - sim_on_actions[sim_do_depth][stat]) /* otherwise exit */ - staying = TRUE; if ((stat >= SCPE_BASE) && (stat != SCPE_EXIT) && /* error from cmd? */ (stat != SCPE_STEP)) { if (!echo && !sim_quiet && /* report if not echoing */ @@ -1039,8 +1032,23 @@ do { } stat = stat & ~SCPE_DOFAILED; /* remove possible flag */ } + switch (stat) { + case SCPE_OK: + case SCPE_STEP: + break; + case SCPE_AFAIL: + staying = (sim_on_check[sim_do_depth] && /* if trap action defined */ + sim_on_actions[sim_do_depth][stat]); /* use it, otherwise exit */ + break; + case SCPE_EXIT: + staying = FALSE; + break; + default: + staying = sim_on_check[sim_do_depth]; + break; + } if ((staying || !interactive) && /* report error if staying */ - (stat >= SCPE_BASE)) { /* or in cmdline file */ + (stat >= SCPE_BASE) && !isdo) { /* or in cmdline file */ printf ("%s\n", sim_error_text (stat)); if (sim_log) fprintf (sim_log, "%s\n", sim_error_text (stat)); @@ -1049,7 +1057,7 @@ do { (sim_on_check[sim_do_depth]) && (stat != SCPE_OK) && (stat != SCPE_STEP)) - if (sim_on_actions[sim_do_depth][stat]) + if ((stat <= SCPE_MAX_ERR) && sim_on_actions[sim_do_depth][stat]) sim_brk_act[sim_do_depth] = sim_on_actions[sim_do_depth][stat]; else sim_brk_act[sim_do_depth] = sim_on_actions[sim_do_depth][0]; From 3ae8a42dae2e74bd4ef562fa07b7b29c446adf5d Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 26 Sep 2011 11:49:43 -0700 Subject: [PATCH 05/30] Allowed SET CONSOLE TELNET=nnn to be issued multiple times, with an automatic SET CONSOLE NOTELNET done as needed. --- sim_console.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sim_console.c b/sim_console.c index 60a69b07..319b14f5 100644 --- a/sim_console.c +++ b/sim_console.c @@ -424,7 +424,8 @@ while (*cptr != 0) { /* do all mods */ *cvptr++ = 0; get_glyph (gbuf, gbuf, 0); /* modifier to UC */ if (isdigit (*gbuf)) { - if (sim_con_tmxr.master) return SCPE_ALATT; /* already open? */ + if (sim_con_tmxr.master) /* already open? */ + sim_set_notelnet (0, NULL); /* close first */ return tmxr_open_master (&sim_con_tmxr, gbuf); /* open master socket */ } else From eef35bd1dc3c2b86b6f798c65fc6406a7e48996f Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 27 Sep 2011 07:22:25 -0700 Subject: [PATCH 06/30] Added a console log flush when starting a simulator and potentially waiting for a telnet connection --- sim_console.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sim_console.c b/sim_console.c index 319b14f5..16e8cd76 100644 --- a/sim_console.c +++ b/sim_console.c @@ -636,6 +636,10 @@ if (sim_con_ldsc.conn || sim_con_ldsc.txbfd) { /* connected or buffered if (!sim_con_ldsc.conn) { printf ("Running with Buffered Console\n"); /* print transition */ fflush (stdout); + if (sim_log) { /* log file? */ + fprintf (sim_log, "Running with Buffered Console\n"); + fflush (sim_log); + } } return SCPE_OK; } @@ -646,6 +650,10 @@ for (i = 0; i < sec; i++) { /* loop */ if (i) { /* if delayed */ printf ("Running\n"); /* print transition */ fflush (stdout); + if (sim_log) { /* log file? */ + fprintf (sim_log, "Running\n"); + fflush (sim_log); + } } return SCPE_OK; /* ready to proceed */ } @@ -655,6 +663,10 @@ for (i = 0; i < sec; i++) { /* loop */ if ((i % 10) == 0) { /* Status every 10 sec */ printf ("Waiting for console Telnet connection\n"); fflush (stdout); + if (sim_log) { /* log file? */ + fprintf (sim_log, "Waiting for console Telnet connection\n"); + fflush (sim_log); + } } sim_os_sleep (1); /* wait 1 second */ } From 5687f9227b3767e5715b4ad4f5edc13406dfbca5 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 28 Sep 2011 15:05:07 -0700 Subject: [PATCH 07/30] VAX & VAX780 Generalized setting TODR for all OSes. Unbound the TODR value from the 100hz clock tick interrupt. TODR now behaves like the original battery backed-up clock and runs with the wall clock, not the simulated instruction clock (except when running ROM diagnostics). Two operational modes are available: - Default VMS mode, which is similar to the previous behavior in that without initializing the TODR it would default to the value VMS would set it to if VMS knew the correct time. This would be correct almost all the time unless a VMS disk hadn't been booted from for more than a year. This mode produces strange time results for non VMS OSes on each system boot. - OS Agnostic mode. This mode behaves precisely like the VAX780 TODR and works correctly for all OSes. This mode is enabled by attaching the TODR to a battery backup state file for the TOY clock (i.e. sim> attach TODR TOY_CLOCK). When operating in OS Agnostic mode, the TODR will initially start counting from 0 and be adjusted differently when an OS specifically writes to the TODR. VMS will prompt to set the time on the initial boot unless the SYSGEN parameter TIMEPROMPTWAIT is set to 0. --- VAX/vax780_stddev.c | 162 +++++++++++++++++++++++++++++++++------ VAX/vax_stddev.c | 179 +++++++++++++++++++++++++++++++++++--------- sim_timer.c | 29 +++++-- sim_timer.h | 10 +++ 4 files changed, 314 insertions(+), 66 deletions(-) diff --git a/VAX/vax780_stddev.c b/VAX/vax780_stddev.c index 9c9b09ce..a7116942 100644 --- a/VAX/vax780_stddev.c +++ b/VAX/vax780_stddev.c @@ -29,6 +29,30 @@ todr TODR clock tmr interval timer + 28-Sep-11 MP Generalized setting TODR for all OSes. + Unbound the TODR value from the 100hz clock tick + interrupt. TODR now behaves like the original + battery backed-up clock and runs with the wall + clock, not the simulated instruction clock. + Two operational modes are available: + - Default VMS mode, which is similar to the previous + behavior in that without initializing the TODR it + would default to the value VMS would set it to if + VMS knew the correct time. This would be correct + almost all the time unless a VMS disk hadn't been + booted from for more than a year. This mode + produces strange time results for non VMS OSes on + each system boot. + - OS Agnostic mode. This mode behaves precisely like + the VAX780 TODR and works correctly for all OSes. + This mode is enabled by attaching the TODR to a + battery backup state file for the TOY clock + (i.e. sim> attach TODR TOY_CLOCK). When operating + in OS Agnostic mode, the TODR will initially start + counting from 0 and be adjusted differently when an + OS specifically writes to the TODR. VMS will prompt + to set the time on each boot unless the SYSGEN + parameter TIMEPROMPTWAIT is set to 0. 21-Mar-11 RMS Added reboot capability 17-Aug-08 RMS Resync TODR on any clock reset 18-Jun-07 RMS Added UNIT_IDLE flag to console input, clock @@ -56,7 +80,7 @@ */ #include "vax_defs.h" -#include + /* Terminal definitions */ @@ -171,6 +195,11 @@ int32 clk_tps = 100; /* ticks/second */ int32 tmxr_poll = CLK_DELAY * TMXR_MULT; /* term mux poll */ int32 tmr_poll = CLK_DELAY; /* pgm timer poll */ int32 todr_reg = 0; /* TODR register */ +struct todr_battery_info { + uint32 toy_gmtbase; /* GMT base of set value */ + uint32 toy_gmtbasemsec; /* The milliseconds of the set value */ + }; +typedef struct todr_battery_info TOY; int32 fl_fnc = 0; /* function */ int32 fl_esr = 0; /* error status */ @@ -197,6 +226,8 @@ t_stat tmr_svc (UNIT *uptr); t_stat tti_reset (DEVICE *dptr); t_stat tto_reset (DEVICE *dptr); t_stat clk_reset (DEVICE *dptr); +t_stat clk_attach (UNIT *uptr, char *cptr); +t_stat clk_detach (UNIT *uptr); t_stat tmr_reset (DEVICE *dptr); t_stat fl_svc (UNIT *uptr); t_stat fl_reset (DEVICE *dptr); @@ -281,7 +312,7 @@ DEVICE tto_dev = { /* TODR and TMR data structures */ -UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0), CLK_DELAY }; /* 100Hz */ +UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE+UNIT_FIX, sizeof(TOY)), CLK_DELAY };/* 100Hz */ REG clk_reg[] = { { DRDATA (TODR, todr_reg, 32), PV_LEFT }, @@ -296,9 +327,9 @@ REG clk_reg[] = { DEVICE clk_dev = { "TODR", &clk_unit, clk_reg, NULL, - 1, 0, 0, 0, 0, 0, + 1, 0, 8, 1, 0, 0, NULL, NULL, &clk_reset, - NULL, NULL, NULL, + NULL, &clk_attach, &clk_detach, NULL, 0 }; @@ -578,7 +609,6 @@ tmr_poll = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */ sim_activate (&clk_unit, tmr_poll); /* reactivate unit */ tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */ AIO_SET_INTERRUPT_LATENCY(tmr_poll*clk_tps); /* set interrrupt latency */ -todr_reg = todr_reg + 1; /* incr TODR */ if ((tmr_iccs & TMR_CSR_RUN) && tmr_use_100hz) /* timer on, std intvl? */ tmr_incr (TMR_INC); /* do timer service */ return SCPE_OK; @@ -651,9 +681,44 @@ t_stat clk_reset (DEVICE *dptr) tmr_poll = sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init 100Hz timer */ sim_activate_abs (&clk_unit, tmr_poll); /* activate 100Hz unit */ tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */ +if (clk_unit.filebuf == NULL) { /* make sure the TODR is initialized */ + clk_unit.filebuf = calloc(sizeof(TOY), 1); + if (clk_unit.filebuf == NULL) + return SCPE_MEM; + todr_resync (); + } return SCPE_OK; } +/* CLK attach */ + +t_stat clk_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +uptr->flags = uptr->flags | (UNIT_ATTABLE | UNIT_BUFABLE); +memset (uptr->filebuf, 0, (size_t)uptr->capac); +r = attach_unit (uptr, cptr); +if (r != SCPE_OK) + uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE); +else + uptr->hwmark = (uint32) uptr->capac; +return r; +} + +/* CLK detach */ + +t_stat clk_detach (UNIT *uptr) +{ +t_stat r; + +r = detach_unit (uptr); +if ((uptr->flags & UNIT_ATT) == 0) + uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE); +return r; +} + + /* Interval timer reset */ t_stat tmr_reset (DEVICE *dptr) @@ -668,36 +733,89 @@ todr_resync (); /* resync TODR */ return SCPE_OK; } + +int +timeval_subtract (result, x, y) + struct timeval *result, *x, *y; +{ +/* Perform the carry for the later subtraction by updating y. */ +if (x->tv_usec < y->tv_usec) { + int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; + y->tv_usec -= 1000000 * nsec; + y->tv_sec += nsec; +} +if (x->tv_usec - y->tv_usec > 1000000) { + int nsec = (x->tv_usec - y->tv_usec) / 1000000; + y->tv_usec += 1000000 * nsec; + y->tv_sec -= nsec; +} + +/* Compute the time remaining to wait. + tv_usec is certainly positive. */ +result->tv_sec = x->tv_sec - y->tv_sec; +result->tv_usec = x->tv_usec - y->tv_usec; + +/* Return 1 if result is negative. */ +return x->tv_sec < y->tv_sec; +} + /* TODR routines */ int32 todr_rd (void) { -return todr_reg; +TOY *toy = (TOY *)clk_unit.filebuf; +struct timespec base, now, val; + +clock_gettime(CLOCK_REALTIME, &now); /* get curr time */ +base.tv_sec = toy->toy_gmtbase; +base.tv_nsec = toy->toy_gmtbasemsec * 1000000; +sim_timespec_diff (&val, &now, &base); +return (int32)(val.tv_sec*100 + val.tv_nsec/10000000); /* 100hz Clock Ticks */ } + void todr_wr (int32 data) { -todr_reg = data; -return; +TOY *toy = (TOY *)clk_unit.filebuf; +struct timespec now, val, base; + +/* Save the GMT time when set value was 0 to record the base for future + read operations in "battery backed-up" state */ + +if (-1 == clock_gettime(CLOCK_REALTIME, &now)) /* get curr time */ + return; /* error? */ +val.tv_sec = ((uint32)data) / 100; +val.tv_nsec = (((uint32)data) % 100) * 10000000; +sim_timespec_diff (&base, &now, &val); /* base = now - data */ +toy->toy_gmtbase = base.tv_sec; +toy->toy_gmtbasemsec = base.tv_nsec/1000000; } t_stat todr_resync (void) { -uint32 base; -time_t curr; -struct tm *ctm; +TOY *toy = (TOY *)clk_unit.filebuf; -curr = time (NULL); /* get curr time */ -if (curr == (time_t) -1) /* error? */ - return SCPE_NOFNC; -ctm = localtime (&curr); /* decompose */ -if (ctm == NULL) /* error? */ - return SCPE_NOFNC; -base = (((((ctm->tm_yday * 24) + /* sec since 1-Jan */ - ctm->tm_hour) * 60) + - ctm->tm_min) * 60) + - ctm->tm_sec; -todr_reg = (base * 100) + 0x10000000; /* cvt to VAX form */ +if (clk_unit.flags & UNIT_ATT) { /* Attached means behave like real VAX780 */ + if (!toy->toy_gmtbase) /* Never set? */ + todr_wr (0); /* Start ticking from 0 */ + } +else { /* Not-Attached means */ + uint32 base; /* behave like simh VMS default */ + time_t curr; + struct tm *ctm; + + curr = time (NULL); /* get curr time */ + if (curr == (time_t) -1) /* error? */ + return SCPE_NOFNC; + ctm = localtime (&curr); /* decompose */ + if (ctm == NULL) /* error? */ + return SCPE_NOFNC; + base = (((((ctm->tm_yday * 24) + /* sec since 1-Jan */ + ctm->tm_hour) * 60) + + ctm->tm_min) * 60) + + ctm->tm_sec; + todr_wr ((base * 100) + 0x10000000); /* use VMS form */ + } return SCPE_OK; } diff --git a/VAX/vax_stddev.c b/VAX/vax_stddev.c index 4aa97572..254f4080 100644 --- a/VAX/vax_stddev.c +++ b/VAX/vax_stddev.c @@ -27,6 +27,31 @@ tto terminal output clk 100Hz and TODR clock + 28-Sep-11 MP Generalized setting TODR for all OSes. + Unbound the TODR value from the 100hz clock tick + interrupt. TODR now behaves like the original + battery backed-up clock and runs with the wall + clock, not the simulated instruction clock + (except when running ROM diagnostics). + Two operational modes are available: + - Default VMS mode, which is similar to the previous + behavior in that without initializing the TODR it + would default to the value VMS would set it to if + VMS knew the correct time. This would be correct + almost all the time unless a VMS disk hadn't been + booted from for more than a year. This mode + produces strange time results for non VMS OSes on + each system boot. + - OS Agnostic mode. This mode behaves precisely like + the VAX780 TODR and works correctly for all OSes. + This mode is enabled by attaching the TODR to a + battery backup state file for the TOY clock + (i.e. sim> attach TODR TOY_CLOCK). When operating + in OS Agnostic mode, the TODR will initially start + counting from 0 and be adjusted differently when an + OS specifically writes to the TODR. VMS will prompt + to set the time on each boot unless the SYSGEN + parameter TIMEPROMPTWAIT is set to 0. 05-Jan-11 MP Added Asynch I/O support 17-Aug-08 RMS Resync TODR on any clock reset 18-Jun-07 RMS Added UNIT_IDLE flag to console input, clock @@ -70,6 +95,11 @@ int32 clk_csr = 0; /* control/status */ int32 clk_tps = 100; /* ticks/second */ int32 todr_reg = 0; /* TODR register */ int32 todr_blow = 1; /* TODR battery low */ +struct todr_battery_info { + uint32 toy_gmtbase; /* GMT base of set value */ + uint32 toy_gmtbasemsec; /* The milliseconds of the set value */ + }; +typedef struct todr_battery_info TOY; int32 tmxr_poll = CLK_DELAY * TMXR_MULT; /* term mux poll */ int32 tmr_poll = CLK_DELAY; /* pgm timer poll */ @@ -79,9 +109,12 @@ t_stat clk_svc (UNIT *uptr); t_stat tti_reset (DEVICE *dptr); t_stat tto_reset (DEVICE *dptr); t_stat clk_reset (DEVICE *dptr); +t_stat clk_attach (UNIT *uptr, char *cptr); +t_stat clk_detach (UNIT *uptr); t_stat todr_resync (void); extern int32 sysd_hlt_enb (void); +extern int32 fault_PC; /* TTI data structures @@ -168,7 +201,7 @@ DEVICE tto_dev = { DIB clk_dib = { 0, 0, NULL, NULL, 1, IVCL (CLK), SCB_INTTIM, { NULL } }; -UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0), CLK_DELAY }; +UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE+UNIT_FIX, sizeof(TOY)), CLK_DELAY };/* 100Hz */ REG clk_reg[] = { { HRDATA (CSR, clk_csr, 16) }, @@ -194,16 +227,15 @@ MTAB clk_mod[] = { DEVICE clk_dev = { "CLK", &clk_unit, clk_reg, clk_mod, - 1, 0, 0, 0, 0, 0, + 1, 0, 8, 1, 0, 0, NULL, NULL, &clk_reset, - NULL, NULL, NULL, + NULL, &clk_attach, &clk_detach, &clk_dib, 0 }; /* Clock and terminal MxPR routines iccs_rd/wr interval timer - todr_rd/wr time of year clock rxcs_rd/wr input control/status rxdb_rd input buffer txcs_rd/wr output control/status @@ -215,11 +247,6 @@ int32 iccs_rd (void) return (clk_csr & CLKCSR_IMP); } -int32 todr_rd (void) -{ -return todr_reg; -} - int32 rxcs_rd (void) { return (tti_csr & TTICSR_IMP); @@ -248,14 +275,6 @@ clk_csr = (clk_csr & ~CLKCSR_RW) | (data & CLKCSR_RW); return; } -void todr_wr (int32 data) -{ -todr_reg = data; -if (data) - todr_blow = 0; -return; -} - void rxcs_wr (int32 data) { if ((data & CSR_IE) == 0) @@ -358,7 +377,8 @@ return SCPE_OK; clk_svc process event (clock tick) clk_reset process reset - todr_powerup powerup for TODR (get date from system) + todr_rd/wr time of year clock + todr_resync powerup for TODR (get date from system) */ t_stat clk_svc (UNIT *uptr) @@ -371,8 +391,8 @@ t = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */ sim_activate (&clk_unit, t); /* reactivate unit */ tmr_poll = t; /* set tmr poll */ tmxr_poll = t * TMXR_MULT; /* set mux poll */ -if (!todr_blow) /* incr TODR */ - todr_reg = todr_reg + 1; +if (!todr_blow && todr_reg) /* if running? */ + todr_reg = todr_reg + 1; /* incr TODR */ return SCPE_OK; } @@ -386,26 +406,80 @@ t = sim_is_active (&clk_unit); return (t? t - 1: wait); } +int32 todr_rd (void) +{ +TOY *toy = (TOY *)clk_unit.filebuf; +struct timespec base, now, val; + +if ((fault_PC&0xFFFE0000) == 0x20040000) /* running from ROM? */ + return todr_reg; /* return counted value for ROM diags */ + +if (0 == todr_reg) /* clock running? */ + return todr_reg; + +/* Maximum number of seconds which can be represented as 10ms ticks + in the 32bit TODR. This is the 33bit value 0x100000000/100 to get seconds */ +#define TOY_MAX_SECS (0x40000000/25) + +clock_gettime(CLOCK_REALTIME, &now); /* get curr time */ +base.tv_sec = toy->toy_gmtbase; +base.tv_nsec = toy->toy_gmtbasemsec * 1000000; +sim_timespec_diff (&val, &now, &base); + +if (val.tv_sec >= TOY_MAX_SECS) /* todr overflowed? */ + return todr_reg = 0; /* stop counting */ + +return (int32)(val.tv_sec*100 + val.tv_nsec/10000000); /* 100hz Clock Ticks */ +} + + +void todr_wr (int32 data) +{ +TOY *toy = (TOY *)clk_unit.filebuf; +struct timespec now, val, base; + +/* Save the GMT time when set value was 0 to record the base for future + read operations in "battery backed-up" state */ + +if (-1 == clock_gettime(CLOCK_REALTIME, &now)) /* get curr time */ + return; /* error? */ +val.tv_sec = ((uint32)data) / 100; +val.tv_nsec = (((uint32)data) % 100) * 10000000; +sim_timespec_diff (&base, &now, &val); /* base = now - data */ +toy->toy_gmtbase = base.tv_sec; +toy->toy_gmtbasemsec = base.tv_nsec/1000000; +todr_reg = data; +if (data) + todr_blow = 0; +} + /* TODR resync routine */ t_stat todr_resync (void) { -uint32 base; -time_t curr; -struct tm *ctm; +TOY *toy = (TOY *)clk_unit.filebuf; -curr = time (NULL); /* get curr time */ -if (curr == (time_t) -1) /* error? */ - return SCPE_NOFNC; -ctm = localtime (&curr); /* decompose */ -if (ctm == NULL) /* error? */ - return SCPE_NOFNC; -base = (((((ctm->tm_yday * 24) + /* sec since 1-Jan */ - ctm->tm_hour) * 60) + - ctm->tm_min) * 60) + - ctm->tm_sec; -todr_reg = (base * 100) + 0x10000000; /* cvt to VAX form */ -todr_blow = 0; +if (clk_unit.flags & UNIT_ATT) { /* Attached means behave like real VAX780 */ + if (!toy->toy_gmtbase) /* Never set? */ + todr_wr (0); /* Start ticking from 0 */ + } +else { /* Not-Attached means */ + uint32 base; /* behave like simh VMS default */ + time_t curr; + struct tm *ctm; + + curr = time (NULL); /* get curr time */ + if (curr == (time_t) -1) /* error? */ + return SCPE_NOFNC; + ctm = localtime (&curr); /* decompose */ + if (ctm == NULL) /* error? */ + return SCPE_NOFNC; + base = (((((ctm->tm_yday * 24) + /* sec since 1-Jan */ + ctm->tm_hour) * 60) + + ctm->tm_min) * 60) + + ctm->tm_sec; + todr_wr ((base * 100) + 0x10000000); /* use VMS form */ + } return SCPE_OK; } @@ -415,13 +489,46 @@ t_stat clk_reset (DEVICE *dptr) { int32 t; -todr_resync (); /* resync clock */ clk_csr = 0; CLR_INT (CLK); t = sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init timer */ sim_activate_abs (&clk_unit, t); /* activate unit */ tmr_poll = t; /* set tmr poll */ tmxr_poll = t * TMXR_MULT; /* set mux poll */ +if (clk_unit.filebuf == NULL) { /* make sure the TODR is initialized */ + clk_unit.filebuf = calloc(sizeof(TOY), 1); + if (clk_unit.filebuf == NULL) + return SCPE_MEM; + todr_resync (); + } return SCPE_OK; } +/* CLK attach */ + +t_stat clk_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +uptr->flags = uptr->flags | (UNIT_ATTABLE | UNIT_BUFABLE); +memset (uptr->filebuf, 0, (size_t)uptr->capac); +r = attach_unit (uptr, cptr); +if (r != SCPE_OK) + uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE); +else + uptr->hwmark = (uint32) uptr->capac; +return r; +} + +/* CLK detach */ + +t_stat clk_detach (UNIT *uptr) +{ +t_stat r; + +r = detach_unit (uptr); +if ((uptr->flags & UNIT_ATT) == 0) + uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE); +return r; +} + diff --git a/sim_timer.c b/sim_timer.c index 0d3feedd..8abdbb3a 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -152,8 +152,7 @@ return sim_os_msec () - stime; } #if defined(SIM_ASYNCH_IO) -#ifndef CLOCK_REALTIME -#define CLOCK_REALTIME 1 +#ifdef NEED_CLOCK_REALTIME int clock_gettime(int clk_id, struct timespec *tp) { uint32 secs, ns, tod[2], unixbase[2] = {0xd53e8000, 0x019db1de}; @@ -225,12 +224,13 @@ Sleep (msec); return sim_os_msec () - stime; } -#if !defined(CLOCK_REALTIME) && defined (SIM_ASYNCH_IO) -#define CLOCK_REALTIME 1 +#if defined(NEED_CLOCK_REALTIME) int clock_gettime(int clk_id, struct timespec *tp) { t_uint64 now, unixbase; +if (clk_id != CLOCK_REALTIME) + return -1; unixbase = 116444736; unixbase *= 1000000000; GetSystemTimeAsFileTime((FILETIME*)&now); @@ -315,8 +315,7 @@ treq.tv_nsec = (milliseconds % MILLIS_PER_SEC) * NANOS_PER_MILLI; return sim_os_msec () - stime; } -#if !defined(CLOCK_REALTIME) && defined (SIM_ASYNCH_IO) -#define CLOCK_REALTIME 1 +#if defined(NEED_CLOCK_REALTIME) int clock_gettime(int clk_id, struct timespec *tp) { struct timeval cur; @@ -377,8 +376,7 @@ if (tim > SIM_IDLE_MAX) return tim; } #if !defined(_POSIX_SOURCE) && defined(SIM_ASYNCH_IO) -#ifndef CLOCK_REALTIME -#define CLOCK_REALTIME 1 +#ifdef NEED_CLOCK_REALTIME typedef int clockid_t; int clock_gettime(clockid_t clk_id, struct timespec *tp) { @@ -408,6 +406,21 @@ return sim_os_msec () - stime; #endif +/* diff = min - sub */ +void +sim_timespec_diff (struct timespec *diff, struct timespec *min, struct timespec *sub) +{ +/* move the minuend value to the difference and operate there. */ +*diff = *min; +/* Borrow as needed for the nsec value */ +if (sub->tv_nsec > min->tv_nsec) { + --diff->tv_sec; + diff->tv_nsec += 1000000000; + } +diff->tv_nsec -= sub->tv_nsec; +diff->tv_sec -= sub->tv_sec; +} + #if defined(SIM_ASYNCH_IO) uint32 sim_idle_ms_sleep (unsigned int msec) { diff --git a/sim_timer.h b/sim_timer.h index 8447cbdd..73174432 100644 --- a/sim_timer.h +++ b/sim_timer.h @@ -31,6 +31,15 @@ #ifndef _SIM_TIMER_H_ #define _SIM_TIMER_H_ 0 +#include + +#ifndef CLOCK_REALTIME +#define CLOCK_REALTIME 1 +#define NEED_CLOCK_REALTIME 1 +int clock_gettime(int clock_id, struct timespec *tp); +#endif + + #define SIM_NTIMERS 8 /* # timers */ #define SIM_TMAX 500 /* max timer makeup */ @@ -51,6 +60,7 @@ #define SIM_THROT_PCT 3 t_bool sim_timer_init (void); +void sim_timespec_diff (struct timespec *diff, struct timespec *min, struct timespec *sub); int32 sim_rtcn_init (int32 time, int32 tmr); void sim_rtcn_init_all (void); int32 sim_rtcn_calb (int32 ticksper, int32 tmr); From 329d84ea0c7e7dc1f61a278d343f8f6b1348493c Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Thu, 29 Sep 2011 06:35:26 -0700 Subject: [PATCH 08/30] Fixed Missing SIM_ASYNCH_IO option in VAX780 Debug build --- Visual Studio Projects/VAX780.vcproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Visual Studio Projects/VAX780.vcproj b/Visual Studio Projects/VAX780.vcproj index 55ee4893..e0139d7a 100644 --- a/Visual Studio Projects/VAX780.vcproj +++ b/Visual Studio Projects/VAX780.vcproj @@ -27,7 +27,7 @@ Date: Wed, 12 Oct 2011 15:39:06 -0700 Subject: [PATCH 09/30] Fixed builds on x64 *nix platforms to properly detect the availability of libm --- makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile b/makefile index 92879ab7..98499b57 100644 --- a/makefile +++ b/makefile @@ -28,7 +28,7 @@ ifeq ($(WIN32),) endif endif OS_CCDEFS = -D_GNU_SOURCE - ifeq (libm,$(shell if $(TEST) -e /usr/lib/libm.$(LIBEXT); then echo libm; fi)) + ifeq (libm,$(shell if $(TEST) -e /usr/lib/libm.$(LIBEXT) -o -e /usr/lib64/libm.$(LIBEXT); then echo libm; fi)) OS_LDFLAGS += -lm endif ifeq (SunOS,$(shell uname)) From 7075a3ec5cbaec7ce57437131848fa78383bf0f1 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Thu, 20 Oct 2011 11:30:44 -0700 Subject: [PATCH 10/30] Added support for concurrent sharing of raw disk images/drives between simulators --- sim_disk.c | 50 +++++++++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/sim_disk.c b/sim_disk.c index f38c4b45..13e90aab 100644 --- a/sim_disk.c +++ b/sim_disk.c @@ -1335,7 +1335,7 @@ if (strchr (openmode, 'r')) DesiredAccess |= GENERIC_READ; if (strchr (openmode, 'w') || strchr (openmode, '+')) DesiredAccess |= GENERIC_WRITE; -Handle = CreateFileA (rawdevicename, DesiredAccess, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL); +Handle = CreateFileA (rawdevicename, DesiredAccess, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS|FILE_FLAG_WRITE_THROUGH, NULL); if (Handle == INVALID_HANDLE_VALUE) { _set_errno_from_status (GetLastError ()); return NULL; @@ -1421,17 +1421,21 @@ static t_stat sim_os_disk_unload_raw (FILE *Disk) { #ifdef IOCTL_STORAGE_EJECT_MEDIA DWORD BytesReturned; +uint32 Removable = FALSE; -if (!DeviceIoControl((HANDLE)Disk, /* handle to disk */ - IOCTL_STORAGE_EJECT_MEDIA, /* dwIoControlCode */ - NULL, /* lpInBuffer */ - 0, /* nInBufferSize */ - NULL, /* lpOutBuffer */ - 0, /* nOutBufferSize */ - (LPDWORD) &BytesReturned, /* number of bytes returned */ - (LPOVERLAPPED) NULL)) { /* OVERLAPPED structure */ - _set_errno_from_status (GetLastError ()); - return SCPE_IOERR; +sim_os_disk_info_raw (Disk, NULL, &Removable); +if (Removable) { + if (!DeviceIoControl((HANDLE)Disk, /* handle to disk */ + IOCTL_STORAGE_EJECT_MEDIA, /* dwIoControlCode */ + NULL, /* lpInBuffer */ + 0, /* nInBufferSize */ + NULL, /* lpOutBuffer */ + 0, /* nOutBufferSize */ + (LPDWORD) &BytesReturned, /* number of bytes returned */ + (LPOVERLAPPED) NULL)) { /* OVERLAPPED structure */ + _set_errno_from_status (GetLastError ()); + return SCPE_IOERR; + } } return SCPE_OK; #else @@ -1443,17 +1447,21 @@ static t_bool sim_os_disk_isavailable_raw (FILE *Disk) { #ifdef IOCTL_STORAGE_EJECT_MEDIA DWORD BytesReturned; +uint32 Removable = FALSE; -if (!DeviceIoControl((HANDLE)Disk, /* handle to disk */ - IOCTL_STORAGE_CHECK_VERIFY, /* dwIoControlCode */ - NULL, /* lpInBuffer */ - 0, /* nInBufferSize */ - NULL, /* lpOutBuffer */ - 0, /* nOutBufferSize */ - (LPDWORD) &BytesReturned, /* number of bytes returned */ - (LPOVERLAPPED) NULL)) { /* OVERLAPPED structure */ - _set_errno_from_status (GetLastError ()); - return FALSE; +sim_os_disk_info_raw (Disk, NULL, &Removable); +if (Removable) { + if (!DeviceIoControl((HANDLE)Disk, /* handle to disk */ + IOCTL_STORAGE_CHECK_VERIFY, /* dwIoControlCode */ + NULL, /* lpInBuffer */ + 0, /* nInBufferSize */ + NULL, /* lpOutBuffer */ + 0, /* nOutBufferSize */ + (LPDWORD) &BytesReturned, /* number of bytes returned */ + (LPOVERLAPPED) NULL)) { /* OVERLAPPED structure */ + _set_errno_from_status (GetLastError ()); + return FALSE; + } } #endif return TRUE; From 9f1f5867143427ccced44e5c3ff8664e0728bbe8 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 21 Oct 2011 02:07:36 -0700 Subject: [PATCH 11/30] Compiler cleanup --- sim_BuildROMs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sim_BuildROMs.c b/sim_BuildROMs.c index f22a273e..d895a4bc 100644 --- a/sim_BuildROMs.c +++ b/sim_BuildROMs.c @@ -130,7 +130,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", statb.st_size, statb.st_size); +fprintf (iFile, " file size: %d (0x%X)\n", (int)statb.st_size, (int)statb.st_size); fprintf (iFile, "*/\n"); fprintf (iFile, "unsigned char %s[] = {", rom_array_name); for (bytes_written=0;bytes_written Date: Tue, 25 Oct 2011 03:52:24 -0700 Subject: [PATCH 12/30] Fixed throttling in several ways: - Sleep for the observed clock tick size while throttling - Recompute the throttling wait once every 10 seconds to account for varying instruction mixes during different phases of a simulator execution or to accommodate the presence of other load on the host system. - Each of the pre-existing throttling modes (Kcps, Mcps, and %) all compute the appropriate throttling interval dynamically. These dynamic computations assume that 100% of the host CPU is dedicated to the current simulator during this computation. This assumption may not always be true and under certain conditions may never provide a way to correctly determine the appropriate throttling wait. An additional throttling mode has been added which allows the simulator operator to explicitly state the desired throttling wait parameters. These are specified by: SET THROT insts/delay where 'insts' is the number of instructions to execute before sleeping for 'delay' milliseconds. --- scp.c | 3 +- sim_timer.c | 86 +++++++++++++++++++++++++++++++++++++++++++---------- sim_timer.h | 7 +++-- 3 files changed, 77 insertions(+), 19 deletions(-) diff --git a/scp.c b/scp.c index ed2e4ab4..9651f41d 100644 --- a/scp.c +++ b/scp.c @@ -616,7 +616,8 @@ static CTAB cmd_table[] = { "set console NODEBUG disable console debugging\n" "set break set breakpoints\n" "set nobreak clear breakpoints\n" - "set throttle x{M|K|%%} set simulation rate\n" + "set throttle {x{M|K|%}}|{x/t}\n" + " set simulation rate\n" "set nothrottle set simulation rate to maximum\n" "set asynch enable asynchronous I/O\n" "set noasynch disable asynchronous I/O\n" diff --git a/sim_timer.c b/sim_timer.c index 8abdbb3a..5b05d00e 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -23,6 +23,28 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 21-Oct-11 MP Fixed throttling in several ways: + - Sleep for the observed clock tick size while throttling + - Recompute the throttling wait once every 10 seconds + to account for varying instruction mixes during + different phases of a simulator execution or to + accommodate the presence of other load on the host + system. + - Each of the pre-existing throttling modes (Kcps, + Mcps, and %) all compute the appropriate throttling + interval dynamically. These dynamic computations + assume that 100% of the host CPU is dedicated to + the current simulator during this computation. + This assumption may not always be true and under + certain conditions may never provide a way to + correctly determine the appropriate throttling + wait. An additional throttling mode has been added + which allows the simulator operator to explicitly + state the desired throttling wait parameters. + These are specified by: + SET THROT insts/delay + where 'insts' is the number of instructions to + execute before sleeping for 'delay' milliseconds. 22-Apr-11 MP Fixed Asynch I/O support to reasonably account cycles when an idle wait is terminated by an external event 05-Jan-11 MP Added Asynch I/O support @@ -67,6 +89,7 @@ static uint32 sim_throt_ms_stop = 0; static uint32 sim_throt_type = 0; static uint32 sim_throt_val = 0; static uint32 sim_throt_state = 0; +static uint32 sim_throt_sleep_time = 0; static int32 sim_throt_wait = 0; extern int32 sim_interval, sim_switches; extern FILE *sim_log; @@ -641,8 +664,11 @@ return SCPE_OK; t_stat sim_show_idle (FILE *st, UNIT *uptr, int32 val, void *desc) { -if (sim_idle_enab) - fprintf (st, "idle enabled, stability wait = %ds, minimum sleep resolution = %dms", sim_idle_stable, sim_idle_rate_ms); +if (sim_idle_enab) { + fprintf (st, "idle enabled"); + if (sim_switches & SWMASK ('D')) + fprintf (st, ", stability wait = %ds, minimum sleep resolution = %dms", sim_idle_stable, sim_idle_rate_ms); + } else fputs ("idle disabled", st); return SCPE_OK; } @@ -652,7 +678,7 @@ return SCPE_OK; t_stat sim_set_throt (int32 arg, char *cptr) { char *tptr, c; -t_value val; +t_value val, val2; if (arg == 0) { if ((cptr != 0) && (*cptr != 0)) @@ -666,8 +692,11 @@ else { val = strtotv (cptr, &tptr, 10); if (cptr == tptr) return SCPE_ARG; + sim_throt_sleep_time = sim_idle_rate_ms; c = toupper (*tptr++); - if (*tptr != 0) + if (c == '/') + val2 = strtotv (tptr, &tptr, 10); + if ((*tptr != 0) || (val == 0)) return SCPE_ARG; if (c == 'M') sim_throt_type = SIM_THROT_MCYC; @@ -675,6 +704,9 @@ else { sim_throt_type = SIM_THROT_KCYC; else if ((c == '%') && (val > 0) && (val < 100)) sim_throt_type = SIM_THROT_PCT; + else if ((c == '/') && (val2 != 0)) { + sim_throt_type = SIM_THROT_SPC; + } else return SCPE_ARG; if (sim_idle_enab) { printf ("Idling disabled\n"); @@ -683,6 +715,14 @@ else { sim_clr_idle (NULL, 0, NULL, NULL); } sim_throt_val = (uint32) val; + if (sim_throt_type == SIM_THROT_SPC) { + if (val2 >= sim_idle_rate_ms) + sim_throt_sleep_time = (uint32) val2; + else { + sim_throt_sleep_time = (uint32) (val2 * sim_idle_rate_ms); + sim_throt_val = (uint32) (val * sim_idle_rate_ms); + } + } } return SCPE_OK; } @@ -706,13 +746,17 @@ else { fprintf (st, "Throttle = %d%%\n", sim_throt_val); break; + case SIM_THROT_SPC: + fprintf (st, "Throttle = %d ms every %d cycles\n", sim_throt_sleep_time, sim_throt_val); + break; + default: fprintf (st, "Throttling disabled\n"); break; } if (sim_switches & SWMASK ('D')) { - fprintf (st, "Wait rate = %d ms\n", sim_idle_rate_ms); + fprintf (st, "minimum sleep resolution = %d ms\n", sim_idle_rate_ms); if (sim_throt_type != 0) fprintf (st, "Throttle interval = %d cycles\n", sim_throt_wait); } @@ -725,7 +769,6 @@ void sim_throt_sched (void) sim_throt_state = 0; if (sim_throt_type) sim_activate (&sim_throt_unit, SIM_THROT_WINIT); -return; } void sim_throt_cancel (void) @@ -735,11 +778,12 @@ sim_cancel (&sim_throt_unit); /* Throttle service - Throttle service has three distinct states + Throttle service has three distinct states used while dynamically + determining a throttling interval: - 0 take initial measurement - 1 take final measurement, calculate wait values - 2 periodic waits to slow down the CPU + 0 take initial measurement + 1 take final measurement, calculate wait values + 2 periodic waits to slow down the CPU */ t_stat sim_throt_svc (UNIT *uptr) @@ -747,12 +791,16 @@ t_stat sim_throt_svc (UNIT *uptr) uint32 delta_ms; double a_cps, d_cps; +if (sim_throt_type == SIM_THROT_SPC) { /* Non dynamic? */ + sim_throt_state = 2; /* force state */ + sim_throt_wait = sim_throt_val; + } switch (sim_throt_state) { case 0: /* take initial reading */ sim_throt_ms_start = sim_os_msec (); sim_throt_wait = SIM_THROT_WST; - sim_throt_state++; /* next state */ + sim_throt_state = 1; /* next state */ break; /* reschedule */ case 1: /* take final reading */ @@ -774,24 +822,32 @@ switch (sim_throt_state) { d_cps = (double) sim_throt_val * 1000.0; else d_cps = (a_cps * ((double) sim_throt_val)) / 100.0; if (d_cps >= a_cps) { - sim_throt_state = 0; + sim_throt_sched (); /* start over */ return SCPE_OK; } sim_throt_wait = (int32) /* time between waits */ ((a_cps * d_cps * ((double) sim_idle_rate_ms)) / (1000.0 * (a_cps - d_cps))); if (sim_throt_wait < SIM_THROT_WMIN) { /* not long enough? */ - sim_throt_state = 0; + sim_throt_sched (); /* start over */ return SCPE_OK; } - sim_throt_state++; + sim_throt_ms_start = sim_throt_ms_stop; + sim_throt_state = 2; // fprintf (stderr, "Throttle values a_cps = %f, d_cps = %f, wait = %d\n", // a_cps, d_cps, sim_throt_wait); } break; case 2: /* throttling */ - sim_os_ms_sleep (1); + sim_os_ms_sleep (sim_throt_sleep_time); + delta_ms = sim_os_msec () - sim_throt_ms_start; + if ((sim_throt_type != SIM_THROT_SPC) && /* when dynamic throttling */ + (delta_ms >= 10000)) { /* recompute every 10 sec */ + sim_throt_ms_start = sim_os_msec (); + sim_throt_wait = SIM_THROT_WST; + sim_throt_state = 1; /* next state */ + } break; } diff --git a/sim_timer.h b/sim_timer.h index 73174432..1bf8aa42 100644 --- a/sim_timer.h +++ b/sim_timer.h @@ -55,9 +55,10 @@ int clock_gettime(int clock_id, struct timespec *tp); #define SIM_THROT_WMIN 100 /* min wait */ #define SIM_THROT_MSMIN 10 /* min for measurement */ #define SIM_THROT_NONE 0 /* throttle parameters */ -#define SIM_THROT_MCYC 1 -#define SIM_THROT_KCYC 2 -#define SIM_THROT_PCT 3 +#define SIM_THROT_MCYC 1 /* MegaCycles Per Sec */ +#define SIM_THROT_KCYC 2 /* KiloCycles Per Sec */ +#define SIM_THROT_PCT 3 /* Max Percent of host CPU */ +#define SIM_THROT_SPC 4 /* Specific periodic Delay */ t_bool sim_timer_init (void); void sim_timespec_diff (struct timespec *diff, struct timespec *min, struct timespec *sub); From 445cb1710d0743e5d672110df55839b818365eb5 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 26 Oct 2011 13:46:21 -0700 Subject: [PATCH 13/30] Fixed SDLC to clear AC (from Dave Gesswein) --- PDP8/pdp8_td.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/PDP8/pdp8_td.c b/PDP8/pdp8_td.c index d02ee571..46703def 100644 --- a/PDP8/pdp8_td.c +++ b/PDP8/pdp8_td.c @@ -28,6 +28,7 @@ td TD8E/TU56 DECtape + 23-Mar-11 RMS Fixed SDLC to clear AC (from Dave Gesswein) 23-Jun-06 RMS Fixed switch conflict in ATTACH 16-Aug-05 RMS Fixed C++ declaration and cast problems 09-Jan-04 RMS Changed sim_fsize calling sequence, added STOP_OFFR @@ -302,6 +303,7 @@ switch (pulse) { if (td_newsa (td_cmd)) /* new command */ return AC | (IORETURN (td_stopoffr, STOP_DTOFF) << IOT_V_REASON); } + AC = 0; break; case 05: /* SDLD */ From 852293e0465bffdacdaed41728b308ed9b645f1a Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 26 Oct 2011 13:47:40 -0700 Subject: [PATCH 14/30] many bug fixes (all from Rick Murphy); now functional --- PDP8/pdp8_fpp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PDP8/pdp8_fpp.c b/PDP8/pdp8_fpp.c index 6845dbe8..4fb04c01 100644 --- a/PDP8/pdp8_fpp.c +++ b/PDP8/pdp8_fpp.c @@ -1,6 +1,6 @@ /* pdp8_fpp.c: PDP-8 floating point processor (FPP8A) - Copyright (c) 2007-2011, Robert M Supnik + Copyright (c) 2007-2010, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), From 2df727b701435d9b03e67931ece2abe49a76e53e Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 26 Oct 2011 13:48:15 -0700 Subject: [PATCH 15/30] adds link to pdp8_fpp.c --- PDP8/pdp8_sys.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PDP8/pdp8_sys.c b/PDP8/pdp8_sys.c index ed7ff85b..3b550941 100644 --- a/PDP8/pdp8_sys.c +++ b/PDP8/pdp8_sys.c @@ -1,6 +1,6 @@ /* pdp8_sys.c: PDP-8 simulator interface - Copyright (c) 1993-2011, Robert M Supnik + Copyright (c) 1993-2009, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -24,7 +24,7 @@ in this Software without prior written authorization from Robert M Supnik. 24-Mar-09 RMS Added link to FPP - 24-Jun-08 RMS Fixed bug in new rim loader (Don North) + 24-Jun-08 RMS Fixed bug in new rim loader (found by Don North) 24-May-08 RMS Fixed signed/unsigned declaration inconsistency 03-Sep-07 RMS Added FPP8 support Rewrote rim and binary loaders From 0c4b62fe8272112f974ab122ed48d88cceb834a7 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 28 Oct 2011 10:04:21 -0700 Subject: [PATCH 16/30] Remove compiler warnings if built with DONT_USE_PCAP_FINDALLDEVS --- sim_ether.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sim_ether.c b/sim_ether.c index e15c1ad3..a66ab23c 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -2608,12 +2608,12 @@ int eth_host_devices(int used, int max, ETH_LIST* list) int eth_devices(int max, ETH_LIST* list) { + int i = 0; +#ifndef DONT_USE_PCAP_FINDALLDEVS pcap_if_t* alldevs; pcap_if_t* dev; - int i = 0; char errbuf[PCAP_ERRBUF_SIZE]; -#ifndef DONT_USE_PCAP_FINDALLDEVS /* retrieve the device list */ if (pcap_findalldevs(&alldevs, errbuf) == -1) { char* msg = "Eth: error in pcap_findalldevs: %s\r\n"; From ec4f0025318cfd0254405f44ec7aafbaec9a6b1b Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 28 Oct 2011 10:06:12 -0700 Subject: [PATCH 17/30] Standardized the simulatar transition messages which is needed on hosts with raw console tty I/O (From the OSX community) --- sim_console.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sim_console.c b/sim_console.c index 16e8cd76..03fc07e8 100644 --- a/sim_console.c +++ b/sim_console.c @@ -634,7 +634,7 @@ if (sim_con_ldsc.conn || sim_con_ldsc.txbfd) { /* connected or buffered tmxr_poll_rx (&sim_con_tmxr); /* poll (check disconn) */ if (sim_con_ldsc.conn || sim_con_ldsc.txbfd) { /* still connected? */ if (!sim_con_ldsc.conn) { - printf ("Running with Buffered Console\n"); /* print transition */ + printf ("Running with Buffered Console\r\n"); /* print transition */ fflush (stdout); if (sim_log) { /* log file? */ fprintf (sim_log, "Running with Buffered Console\n"); @@ -648,7 +648,7 @@ for (i = 0; i < sec; i++) { /* loop */ if (tmxr_poll_conn (&sim_con_tmxr) >= 0) { /* poll connect */ sim_con_ldsc.rcve = 1; /* rcv enabled */ if (i) { /* if delayed */ - printf ("Running\n"); /* print transition */ + printf ("Running\r\n"); /* print transition */ fflush (stdout); if (sim_log) { /* log file? */ fprintf (sim_log, "Running\n"); @@ -661,7 +661,7 @@ for (i = 0; i < sec; i++) { /* loop */ if ((c == SCPE_STOP) || stop_cpu) return SCPE_STOP; if ((i % 10) == 0) { /* Status every 10 sec */ - printf ("Waiting for console Telnet connection\n"); + printf ("Waiting for console Telnet connection\r\n"); fflush (stdout); if (sim_log) { /* log file? */ fprintf (sim_log, "Waiting for console Telnet connection\n"); From eaddb7d24aef17eee3e1b266fe2aeed7d40ca7e6 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Sat, 29 Oct 2011 14:13:33 -0700 Subject: [PATCH 18/30] Added support for integrated Tap networking interfaces on OSX --- 0readme_ethernet.txt | 36 ++++++++++++++++++++++++++++++------ makefile | 2 +- sim_ether.c | 21 +++++++++++++++++++-- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/0readme_ethernet.txt b/0readme_ethernet.txt index 5bdf18a6..3e6f8998 100644 --- a/0readme_ethernet.txt +++ b/0readme_ethernet.txt @@ -43,9 +43,9 @@ bridge, or route TAP devices for you. Integrated Universal TUN/TAP support can be used for host<->simulator network traffic (on the platforms where it is available) by using the SIMH command: "attach xq tap:tapN" (i.e. attach xq tap:tap0). Platforms that this has been -tested on include: Linux, FreeBSD, OpenBSD, NetBSD. Each of these platforms -has some way to create a tap pseudo device and then bridge it with a physical -network interface. +tested on include: Linux, FreeBSD, OpenBSD, NetBSD and OSX. Each of these +platforms has some way to create a tap pseudo device (and possibly then to +bridge it with a physical network interface). The following steps were performed to get a working SIMH vax simulator sharing a physical NIC and allowing Host<->SIMH vax communications: @@ -117,6 +117,29 @@ NetBSD (NetBSD 5.0.2) # Run simulator and "attach xq tap:tap0" +OSX (Snow Leopard) + OSX Does NOT have native support for tun/tap interfaces. It also does not have native + support for bridging. + + Mattias Nissler has created tun/tap functionality available at http://tuntaposx,sourceforge.net/ + + We'll punt on bridging for the sake of this example and move on to use a basic tap + based internal network so a host and guest can communicate directly. + + Download the install package from: + http://sourceforge.net/projects/tuntaposx/files/tuntap/20090913/tuntap_20090913.tar.gz + + Expand the tarball to a directory. + Invoke the package installer tuntap_20090913.pkg + Click through the various prompts accepting things and eventually installing the package. + + # Run simulator and: + sim> attach xq tap:tap0 + 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. + As far as I can tell you must run as root for this to work. + ------------------------------------------------------------------------------- Windows notes: @@ -331,14 +354,15 @@ Dave Change Log =============================================================================== - 07-Jul-11 MB VMS Pcap (from Mike Burke) - - Fixed Alpha issues - - Added OpenVMS Integrety support + 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 vector assignments 12-Aug-11 MP Cleaned up payload length determination Fixed race condition detecting reflections when threaded reading and writing is enabled + 07-Jul-11 MB VMS Pcap (from Mike Burke) + - Fixed Alpha issues + - Added OpenVMS Integrety support 20-Apr-11 MP Fixed save/restore behavior 12-Jan-11 DTH Added SHOW XU FILTERS modifier 11-Jan-11 DTH Corrected DEUNA/DELUA SELFTEST command, enabling use by diff --git a/makefile b/makefile index 98499b57..4004965d 100644 --- a/makefile +++ b/makefile @@ -66,7 +66,7 @@ ifeq ($(WIN32),) # Provide support for Tap networking on Linux NETWORK_TAP_CCDEFS = -DUSE_TAP_NETWORK endif - ifeq (bsdtuntap,$(shell if $(TEST) -e /usr/include/net/if_tun.h; 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 NETWORK_TAP_CCDEFS = -DUSE_TAP_NETWORK -DUSE_BSDTUNTAP endif diff --git a/sim_ether.c b/sim_ether.c index a66ab23c..04692446 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -787,7 +787,7 @@ void eth_show_dev (FILE* st, ETH_DEV* dev) #elif defined(USE_BSDTUNTAP) #include #include -#include +#include #else /* We don't know how to do this on the current platform */ #undef USE_TAP_NETWORK #endif @@ -1399,6 +1399,23 @@ t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit) dev->fd_handle = tun; strcpy(savname, savname+4); } +#if defined (__APPLE__) + if (1) { + struct ifreq ifr; + int s; + + memset (&ifr, 0, sizeof(ifr)); + ifr.ifr_addr.sa_family = AF_INET; + strncpy(ifr.ifr_name, savname+4, sizeof(ifr.ifr_name)); + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { + if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) >= 0) { + ifr.ifr_flags |= IFF_UP; + ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr); + } + close(s); + } + } +#endif } else { strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); } @@ -1465,7 +1482,7 @@ t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit) #endif #endif /* !defined (USE_READER_THREAD */ #if defined (__APPLE__) - if (1) { + if (dev->pcap_mode) { /* Deliver packets immediately, needed for OS X 10.6.2 and later * (Snow-Leopard). * See this thread on libpcap and Mac Os X 10.6 Snow Leopard on From a8a5a5b74fc9478811c841caf980076715e4faa1 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 31 Oct 2011 10:24:30 -0700 Subject: [PATCH 19/30] Fixed error path to properly close file --- sim_disk.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sim_disk.c b/sim_disk.c index 13e90aab..cf5ff17c 100644 --- a/sim_disk.c +++ b/sim_disk.c @@ -2657,6 +2657,7 @@ if (SizeInBytes > ((uint64)(1024*1024*1024))*2040) { } if (File = sim_fopen (szVHDPath, "rb")) { fclose (File); + File = NULL; Status = EEXIST; goto Cleanup_Return; } @@ -2784,7 +2785,8 @@ if (WriteFilePosition(File, Cleanup_Return: free (BAT); -fclose (File); +if (File) + fclose (File); if (Status) { if (Status != EEXIST) remove (szVHDPath); From f84c6109de0117b2f1e3d7a81da4df4bfce73fd8 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 31 Oct 2011 10:25:11 -0700 Subject: [PATCH 20/30] Added useful diagnostic when restore operation fails due to inability to attach a device --- scp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scp.c b/scp.c index 9651f41d..9473b947 100644 --- a/scp.c +++ b/scp.c @@ -2961,7 +2961,9 @@ for (j=0, r = SCPE_OK; j Date: Mon, 31 Oct 2011 10:25:52 -0700 Subject: [PATCH 21/30] Cleanup comments --- descrip.mms | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/descrip.mms b/descrip.mms index 4b0c1a14..27407ab5 100644 --- a/descrip.mms +++ b/descrip.mms @@ -55,8 +55,8 @@ # # MMK/MACRO=(NOASYNCH=1) # -# On AXP the AXP PCAP components are built and used to provide network -# support for the VAX and PDP11 simulators. +# On AXP and IA64 the VMS PCAP components are built and used to provide +# network support for the VAX and PDP11 simulators. # # The AXP PCAP components can only be built using a version of the # DEC/Compaq/HP Compiler version V6.5-001 or later. To build using an From bfb6e54819da987430869967f2d25093d34e7655 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 31 Oct 2011 10:26:58 -0700 Subject: [PATCH 22/30] Compiler warning cleanup --- sim_timer.c | 8 ++++---- sim_timer.h | 9 ++++++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/sim_timer.c b/sim_timer.c index 5b05d00e..2a364cdf 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -175,7 +175,7 @@ return sim_os_msec () - stime; } #if defined(SIM_ASYNCH_IO) -#ifdef NEED_CLOCK_REALTIME +#ifdef NEED_CLOCK_GETTIME int clock_gettime(int clk_id, struct timespec *tp) { uint32 secs, ns, tod[2], unixbase[2] = {0xd53e8000, 0x019db1de}; @@ -247,7 +247,7 @@ Sleep (msec); return sim_os_msec () - stime; } -#if defined(NEED_CLOCK_REALTIME) +#if defined(NEED_CLOCK_GETTIME) int clock_gettime(int clk_id, struct timespec *tp) { t_uint64 now, unixbase; @@ -338,7 +338,7 @@ treq.tv_nsec = (milliseconds % MILLIS_PER_SEC) * NANOS_PER_MILLI; return sim_os_msec () - stime; } -#if defined(NEED_CLOCK_REALTIME) +#if defined(NEED_CLOCK_GETTIME) int clock_gettime(int clk_id, struct timespec *tp) { struct timeval cur; @@ -399,7 +399,7 @@ if (tim > SIM_IDLE_MAX) return tim; } #if !defined(_POSIX_SOURCE) && defined(SIM_ASYNCH_IO) -#ifdef NEED_CLOCK_REALTIME +#ifdef NEED_CLOCK_GETTIME typedef int clockid_t; int clock_gettime(clockid_t clk_id, struct timespec *tp) { diff --git a/sim_timer.h b/sim_timer.h index 1bf8aa42..ace58461 100644 --- a/sim_timer.h +++ b/sim_timer.h @@ -35,7 +35,14 @@ #ifndef CLOCK_REALTIME #define CLOCK_REALTIME 1 -#define NEED_CLOCK_REALTIME 1 +#define NEED_CLOCK_GETTIME 1 +#ifndef HAVE_STRUCT_TIMESPEC +#define HAVE_STRUCT_TIMESPEC 1 +struct timespec { + long tv_sec; + long tv_nsec; +}; +#endif /* HAVE_STRUCT_TIMESPEC */ int clock_gettime(int clock_id, struct timespec *tp); #endif From fd5de0d00564decd3ce12fd1bf6b01d6c22bf96c Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 31 Oct 2011 11:51:19 -0700 Subject: [PATCH 23/30] 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. --- 0readme_ethernet.txt | 31 +- makefile | 13 +- sim_ether.c | 2319 ++++++++++++++++++++++-------------------- sim_ether.h | 14 +- 4 files changed, 1282 insertions(+), 1095 deletions(-) diff --git a/0readme_ethernet.txt b/0readme_ethernet.txt index 3e6f8998..eb1c66f0 100644 --- a/0readme_ethernet.txt +++ b/0readme_ethernet.txt @@ -133,13 +133,37 @@ OSX (Snow Leopard) Invoke the package installer tuntap_20090913.pkg 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> ! 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. - As far as I can tell you must run as root for this to work. + Simulated system uses IP address 192.168.6.2 and host uses 192.167.6.1 + 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 + ------------------------------------------------------------------------------- Windows notes: @@ -354,6 +378,7 @@ Dave 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 17-Aug-11 RMS Fix from Sergey Oboguev relating to XU and XQ Auto Config and vector assignments diff --git a/makefile b/makefile index 4004965d..c4be5123 100644 --- a/makefile +++ b/makefile @@ -13,6 +13,7 @@ # ifeq ($(WIN32),) #*nix Environments (&& cygwin) + GCC = gcc ifeq (SunOS,$(shell uname)) TEST = /bin/test else @@ -62,13 +63,18 @@ ifeq ($(WIN32),) NETWORK_CCDEFS = -DUSE_NETWORK NETWORK_LDFLAGS = -lpcap 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)) # Provide support for Tap networking on Linux - NETWORK_TAP_CCDEFS = -DUSE_TAP_NETWORK + 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 - NETWORK_TAP_CCDEFS = -DUSE_TAP_NETWORK -DUSE_BSDTUNTAP + 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 @@ -79,6 +85,7 @@ ifeq ($(WIN32),) endif else #Win32 Environments (via MinGW32) + GCC = gcc GCC_Path := $(dir $(shell where gcc.exe)) ifeq ($(NOASYNCH),) ifeq (pthreads,$(shell if exist ..\pthreads\Pre-built.2\include\pthread.h echo pthreads)) @@ -119,7 +126,7 @@ else 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) # diff --git a/sim_ether.c b/sim_ether.c index 04692446..3ca7eefa 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -138,6 +138,15 @@ at open time. This functionality is only useful/needed on *nix platforms since native sharing of Windows NIC 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 - Specifies that you are using an older version of libpcap @@ -151,6 +160,11 @@ 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 multithreaded environments 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 /* USE_TAP_NETWORK */ +#ifdef USE_VDE_NETWORK +#include +#endif /* USE_VDE_NETWORK */ + /* Allows windows to look up user-defined adapter names */ #if defined(_WIN32) #include @@ -1092,40 +1110,42 @@ 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)) dev->have_host_nic_phy_addr = 1; #elif !defined (__VMS) -{ - char command[1024]; - FILE *f; + if (1) { + char command[1024]; + FILE *f; - 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); - system(command); - if (f = fopen("NIC.hwaddr", "r")) { - if (fgets(command, sizeof(command)-1, f)) { - char *p1, *p2; + if (0 == strncmp("vde:", devname, 4)) + return; + 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); + system(command); + if (f = fopen("NIC.hwaddr", "r")) { + if (fgets(command, sizeof(command)-1, f)) { + char *p1, *p2; - p1 = strchr(command, ':'); - while (p1) { - p2 = strchr(p1+1, ':'); - if (p2 == p1+3) { - int mac_bytes[6]; - if (6 == sscanf(p1-2, "%02x:%02x:%02x:%02x:%02x:%02x", &mac_bytes[0], &mac_bytes[1], &mac_bytes[2], &mac_bytes[3], &mac_bytes[4], &mac_bytes[5])) { - dev->host_nic_phy_hw_addr[0] = mac_bytes[0]; - dev->host_nic_phy_hw_addr[1] = mac_bytes[1]; - dev->host_nic_phy_hw_addr[2] = mac_bytes[2]; - dev->host_nic_phy_hw_addr[3] = mac_bytes[3]; - dev->host_nic_phy_hw_addr[4] = mac_bytes[4]; - dev->host_nic_phy_hw_addr[5] = mac_bytes[5]; - dev->have_host_nic_phy_addr = 1; + p1 = strchr(command, ':'); + while (p1) { + p2 = strchr(p1+1, ':'); + if (p2 == p1+3) { + int mac_bytes[6]; + if (6 == sscanf(p1-2, "%02x:%02x:%02x:%02x:%02x:%02x", &mac_bytes[0], &mac_bytes[1], &mac_bytes[2], &mac_bytes[3], &mac_bytes[4], &mac_bytes[5])) { + dev->host_nic_phy_hw_addr[0] = mac_bytes[0]; + dev->host_nic_phy_hw_addr[1] = mac_bytes[1]; + dev->host_nic_phy_hw_addr[2] = mac_bytes[2]; + dev->host_nic_phy_hw_addr[3] = mac_bytes[3]; + dev->host_nic_phy_hw_addr[4] = mac_bytes[4]; + dev->host_nic_phy_hw_addr[5] = mac_bytes[5]; + dev->have_host_nic_phy_addr = 1; + } + break; + } + p1 = p2; } - break; } - p1 = p2; + fclose(f); + remove("NIC.hwaddr"); } } - fclose(f); - remove("NIC.hwaddr"); - } -} #endif } @@ -1148,84 +1168,116 @@ int sched_policy; struct sched_param sched_priority; #if defined (_WIN32) HANDLE hWait = pcap_getevent ((pcap_t*)dev->handle); -#endif -#if defined (MUST_DO_SELECT) -struct timeval timeout; +#else int sel_ret; -int pcap_fd; +int do_select = 0; +int select_fd; -if (dev->pcap_mode) - pcap_fd = pcap_get_selectable_fd((pcap_t *)dev->handle); -else - pcap_fd = dev->fd_handle; +switch (dev->eth_api) { + case ETH_API_PCAP: +#if defined (MUST_DO_SELECT) + 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 - sim_debug(dev->dbit, dev->dptr, "Reader Thread Starting\n"); +sim_debug(dev->dbit, dev->dptr, "Reader Thread Starting\n"); - /* Boost Priority for this I/O thread vs the CPU instruction execution - thread which in general won't be readily yielding the processor when - this thread needs to run */ - pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority); - ++sched_priority.sched_priority; - pthread_setschedparam (pthread_self(), sched_policy, &sched_priority); +/* Boost Priority for this I/O thread vs the CPU instruction execution + thread which in general won't be readily yielding the processor when + this thread needs to run */ +pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority); +++sched_priority.sched_priority; +pthread_setschedparam (pthread_self(), sched_policy, &sched_priority); - while ((dev->pcap_mode && dev->handle) || dev->fd_handle) { -#if defined (MUST_DO_SELECT) - fd_set setl; +while (dev->handle) { +#if defined (_WIN32) + if (WAIT_OBJECT_0 == WaitForSingleObject (hWait, 250)) { +#else + fd_set setl; + struct timeval timeout; + + if (do_select) { FD_ZERO(&setl); - FD_SET(pcap_fd, &setl); + FD_SET(select_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 (WAIT_OBJECT_0 == WaitForSingleObject (hWait, 250)) { -#else - if (1) { -#endif -#endif /* MUST_DO_SELECT */ - if ((dev->pcap_mode) && (!dev->handle)) - break; - if ((!dev->pcap_mode) && (!dev->fd_handle)) - break; - /* dispatch read request queue available packets */ - if (dev->pcap_mode) + 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; + /* dispatch read request queue available packets */ + switch (dev->eth_api) { + case ETH_API_PCAP: status = pcap_dispatch ((pcap_t*)dev->handle, -1, &_eth_callback, (u_char*)dev); + break; #ifdef USE_TAP_NETWORK - else { - struct pcap_pkthdr header; - int len; - u_char buf[ETH_MAX_JUMBO_FRAME]; + case ETH_API_TAP: + if (1) { + struct pcap_pkthdr header; + int len; + u_char buf[ETH_MAX_JUMBO_FRAME]; - memset(&header, 0, sizeof(header)); - len = read(dev->fd_handle, buf, sizeof(buf)); - if (len > 0) { - status = 1; - header.caplen = header.len = len; - _eth_callback((u_char *)dev, &header, buf); - } else { - status = 0; - } - } -#endif /* USE_TAP_NETWORK */ - - if ((status > 0) && (dev->asynch_io)) { - int wakeup_needed; - pthread_mutex_lock (&dev->lock); - wakeup_needed = (dev->read_queue.count != 0); - pthread_mutex_unlock (&dev->lock); - if (wakeup_needed) { - sim_debug(dev->dbit, dev->dptr, "Queueing automatic poll\n"); - sim_activate_abs (dev->dptr->units, dev->asynch_io_latency); + memset(&header, 0, sizeof(header)); + len = read(dev->fd_handle, buf, sizeof(buf)); + if (len > 0) { + status = 1; + header.caplen = header.len = len; + _eth_callback((u_char *)dev, &header, buf); + } + else + status = 0; } + break; +#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)) { + int wakeup_needed; + + pthread_mutex_lock (&dev->lock); + wakeup_needed = (dev->read_queue.count != 0); + pthread_mutex_unlock (&dev->lock); + if (wakeup_needed) { + sim_debug(dev->dbit, dev->dptr, "Queueing automatic poll\n"); + sim_activate_abs (dev->dptr->units, dev->asynch_io_latency); } } + } } - sim_debug(dev->dbit, dev->dptr, "Reader Thread Exiting\n"); - return NULL; +sim_debug(dev->dbit, dev->dptr, "Reader Thread Exiting\n"); +return NULL; } static void * @@ -1236,225 +1288,257 @@ struct write_request *request; int sched_policy; struct sched_param sched_priority; - /* Boost Priority for this I/O thread vs the CPU instruction execution - thread which in general won't be readily yielding the processor when - this thread needs to run */ - pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority); - ++sched_priority.sched_priority; - pthread_setschedparam (pthread_self(), sched_policy, &sched_priority); +/* Boost Priority for this I/O thread vs the CPU instruction execution + thread which in general won't be readily yielding the processor when + this thread needs to run */ +pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority); +++sched_priority.sched_priority; +pthread_setschedparam (pthread_self(), sched_policy, &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); - while ((dev->pcap_mode && dev->handle) || dev->fd_handle) { - pthread_cond_wait (&dev->writer_cond, &dev->writer_lock); - while (request = dev->write_requests) { - /* Pull buffer off request list */ - dev->write_requests = request->next; - pthread_mutex_unlock (&dev->writer_lock); - - dev->write_status = _eth_write(dev, &request->packet, NULL); - - pthread_mutex_lock (&dev->writer_lock); - /* Put buffer on free buffer list */ - request->next = dev->write_buffers; - dev->write_buffers = request; +pthread_mutex_lock (&dev->writer_lock); +while (dev->handle) { + pthread_cond_wait (&dev->writer_cond, &dev->writer_lock); + while (request = dev->write_requests) { + /* Pull buffer off request list */ + dev->write_requests = request->next; + pthread_mutex_unlock (&dev->writer_lock); + + dev->write_status = _eth_write(dev, &request->packet, NULL); + + pthread_mutex_lock (&dev->writer_lock); + /* Put buffer on free buffer list */ + request->next = dev->write_buffers; + dev->write_buffers = request; } } - pthread_mutex_unlock (&dev->writer_lock); +pthread_mutex_unlock (&dev->writer_lock); - sim_debug(dev->dbit, dev->dptr, "Writer Thread Exiting\n"); - return NULL; +sim_debug(dev->dbit, dev->dptr, "Writer Thread Exiting\n"); +return NULL; } #endif t_stat eth_set_async (ETH_DEV *dev, int latency) { #if !defined(USE_READER_THREAD) || !defined(SIM_ASYNCH_IO) - char *msg = "Eth: can't operate asynchronously, must poll\r\n"; - printf ("%s", msg); - if (sim_log) fprintf (sim_log, "%s", msg); - return SCPE_NOFNC; +char *msg = "Eth: can't operate asynchronously, must poll\r\n"; +printf ("%s", msg); +if (sim_log) fprintf (sim_log, "%s", msg); +return SCPE_NOFNC; #else - int wakeup_needed; +int wakeup_needed; - dev->asynch_io = 1; - dev->asynch_io_latency = latency; - pthread_mutex_lock (&dev->lock); - wakeup_needed = (dev->read_queue.count != 0); - pthread_mutex_unlock (&dev->lock); - if (wakeup_needed) { - sim_debug(dev->dbit, dev->dptr, "Queueing automatic poll\n"); - sim_activate_abs (dev->dptr->units, dev->asynch_io_latency); +dev->asynch_io = 1; +dev->asynch_io_latency = latency; +pthread_mutex_lock (&dev->lock); +wakeup_needed = (dev->read_queue.count != 0); +pthread_mutex_unlock (&dev->lock); +if (wakeup_needed) { + sim_debug(dev->dbit, dev->dptr, "Queueing automatic poll\n"); + sim_activate_abs (dev->dptr->units, dev->asynch_io_latency); } #endif - return SCPE_OK; +return SCPE_OK; } t_stat eth_clr_async (ETH_DEV *dev) { #if !defined(USE_READER_THREAD) || !defined(SIM_ASYNCH_IO) - return SCPE_NOFNC; +return SCPE_NOFNC; #else - /* make sure device exists */ - if (!dev) return SCPE_UNATT; +/* make sure device exists */ +if (!dev) return SCPE_UNATT; - dev->asynch_io = 0; - return SCPE_OK; +dev->asynch_io = 0; +return SCPE_OK; #endif } t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit) { - int bufsz = (BUFSIZ < ETH_MAX_PACKET) ? ETH_MAX_PACKET : BUFSIZ; - char errbuf[PCAP_ERRBUF_SIZE]; - char temp[1024]; - char* savname = name; - int num; - char* msg; +int bufsz = (BUFSIZ < ETH_MAX_PACKET) ? ETH_MAX_PACKET : BUFSIZ; +char errbuf[PCAP_ERRBUF_SIZE]; +char temp[1024]; +char* savname = name; +int num; +char* msg; - if (bufsz < ETH_MAX_JUMBO_FRAME) - bufsz = ETH_MAX_JUMBO_FRAME; /* Enable handling of jumbo frames */ +if (bufsz < ETH_MAX_JUMBO_FRAME) + bufsz = ETH_MAX_JUMBO_FRAME; /* Enable handling of jumbo frames */ - /* initialize device */ - eth_zero(dev); +/* initialize device */ +eth_zero(dev); - /* translate name of type "ethX" to real device name */ - if ((strlen(name) == 4) - && (tolower(name[0]) == 'e') - && (tolower(name[1]) == 't') - && (tolower(name[2]) == 'h') - && isdigit(name[3]) - ) { - num = atoi(&name[3]); - savname = eth_getname(num, temp); +/* translate name of type "ethX" to real device name */ +if ((strlen(name) == 4) + && (tolower(name[0]) == 'e') + && (tolower(name[1]) == 't') + && (tolower(name[2]) == 'h') + && isdigit(name[3]) + ) { + num = atoi(&name[3]); + savname = eth_getname(num, temp); + if (savname == 0) /* 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 */ + /* probably is not ethX and has no description */ + savname = eth_getname_byname(name, temp); if (savname == 0) /* 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 */ - /* probably is not ethX and has no description */ - savname = eth_getname_byname(name, temp); - if (savname == 0) /* didn't translate */ - savname = name; + savname = name; } } - /* attempt to connect device */ - memset(errbuf, 0, sizeof(errbuf)); - if (strncmp("tap:", savname, 4)) { +/* attempt to connect device */ +memset(errbuf, 0, sizeof(errbuf)); +if (0 == strncmp("tap:", savname, 4)) { + int tun = -1; /* TUN/TAP Socket */ + int on = 1; + char dev_name[64] = ""; + +#if defined(USE_TAP_NETWORK) + if (!strcmp(savname, "tap:tapN")) { + msg = "Eth: Must specify actual tap device name (i.e. tap:tap0)\r\n"; + printf (msg, errbuf); + if (sim_log) fprintf (sim_log, msg, errbuf); + return SCPE_OPENERR; + } +#endif +#if defined(__linux) && defined(USE_TAP_NETWORK) + if ((tun = open("/dev/net/tun", O_RDWR)) >= 0) { + struct ifreq ifr; /* Interface Requests */ + + memset(&ifr, 0, sizeof(ifr)); + /* Set up interface flags */ + strcpy(ifr.ifr_name, savname+4); + ifr.ifr_flags = IFF_TAP|IFF_NO_PI; + + /* Send interface requests to TUN/TAP driver. */ + if (ioctl(tun, TUNSETIFF, &ifr) >= 0) { + if (ioctl(tun, FIONBIO, &on)) { + strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); + close(tun); + } + else { + dev->fd_handle = tun; + strcpy(savname, ifr.ifr_name); + } + } + else + strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); + } + else + strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); +#elif defined(USE_BSDTUNTAP) && defined(USE_TAP_NETWORK) + snprintf(dev_name, sizeof(dev_name)-1, "/dev/%s", savname+4); + dev_name[sizeof(dev_name)-1] = '\0'; + + if ((tun = open(dev_name, O_RDWR)) >= 0) { + if (ioctl(tun, FIONBIO, &on)) { + strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); + close(tun); + } + else { + dev->fd_handle = tun; + strcpy(savname, savname+4); + } +#if defined (__APPLE__) + if (1) { + struct ifreq ifr; + int s; + + memset (&ifr, 0, sizeof(ifr)); + ifr.ifr_addr.sa_family = AF_INET; + strncpy(ifr.ifr_name, savname+4, sizeof(ifr.ifr_name)); + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { + if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) >= 0) { + ifr.ifr_flags |= IFF_UP; + ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr); + } + close(s); + } + } +#endif + } + else + strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); +#else + strncpy(errbuf, "No support for tap: devices", sizeof(errbuf)-1); +#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->pcap_mode = 1; - } else { - int tun = -1; /* TUN/TAP Socket */ - int on = 1; - char dev_name[64] = ""; - -#if defined(USE_TAP_NETWORK) - if (!strcmp(savname, "tap:tapN")) { - msg = "Eth: Must specify actual tap device name (i.e. tap:tap0)\r\n"; - printf (msg, errbuf); - if (sim_log) fprintf (sim_log, msg, errbuf); - return SCPE_OPENERR; - } -#endif -#if defined(__linux) && defined(USE_TAP_NETWORK) - if ((tun = open("/dev/net/tun", O_RDWR)) >= 0) { - struct ifreq ifr; /* Interface Requests */ - - memset(&ifr, 0, sizeof(ifr)); - /* Set up interface flags */ - strcpy(ifr.ifr_name, savname+4); - ifr.ifr_flags = IFF_TAP|IFF_NO_PI; - - // Send interface requests to TUN/TAP driver. - if (ioctl(tun, TUNSETIFF, &ifr) >= 0) { - if (ioctl(tun, FIONBIO, &on)) { - strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); - close(tun); - } else { - dev->fd_handle = tun; - strcpy(savname, ifr.ifr_name); - } - } else - strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); - } else - strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); -#elif defined(USE_BSDTUNTAP) && defined(USE_TAP_NETWORK) - snprintf(dev_name, sizeof(dev_name)-1, "/dev/%s", savname+4); - dev_name[sizeof(dev_name)-1] = '\0'; - - if ((tun = open(dev_name, O_RDWR)) >= 0) { - if (ioctl(tun, FIONBIO, &on)) { - strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); - close(tun); - } else { - dev->fd_handle = tun; - strcpy(savname, savname+4); } -#if defined (__APPLE__) - if (1) { - struct ifreq ifr; - int s; - - memset (&ifr, 0, sizeof(ifr)); - ifr.ifr_addr.sa_family = AF_INET; - strncpy(ifr.ifr_name, savname+4, sizeof(ifr.ifr_name)); - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { - if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) >= 0) { - ifr.ifr_flags |= IFF_UP; - ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr); - } - close(s); - } - } -#endif - } else { - strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); + dev->eth_api = ETH_API_PCAP; } -#else - strncpy(errbuf, "No support for tap: devices", sizeof(errbuf)-1); -#endif /* !defined(__linux) && !defined(USE_BSDTUNTAP) */ +if (errbuf[0]) { + msg = "Eth: open error - %s\r\n"; + printf (msg, errbuf); + if (sim_log) fprintf (sim_log, msg, errbuf); + return SCPE_OPENERR; } - if (errbuf[0]) { - msg = "Eth: open error - %s\r\n"; - printf (msg, errbuf); - if (sim_log) fprintf (sim_log, msg, errbuf); - return SCPE_OPENERR; - } - msg = "Eth: opened OS device %s\r\n"; - printf (msg, savname); - if (sim_log) fprintf (sim_log, msg, savname); +msg = "Eth: opened OS device %s\r\n"; +printf (msg, savname); +if (sim_log) fprintf (sim_log, msg, savname); - /* get the NIC's hardware MAC address */ - eth_get_nic_hw_addr(dev, savname); +/* get the NIC's hardware MAC address */ +eth_get_nic_hw_addr(dev, savname); - /* save name of device */ - dev->name = malloc(strlen(savname)+1); - strcpy(dev->name, savname); +/* save name of device */ +dev->name = malloc(strlen(savname)+1); +strcpy(dev->name, savname); - /* save debugging information */ - dev->dptr = dptr; - dev->dbit = dbit; +/* save debugging information */ +dev->dptr = dptr; +dev->dbit = dbit; #if !defined(HAS_PCAP_SENDPACKET) && defined (xBSD) && !defined (__APPLE__) - /* Tell the kernel that the header is fully-formed when it gets it. - This is required in order to fake the src address. */ - if (dev->pcap_mode) { - int one = 1; - ioctl(pcap_fileno(dev->handle), BIOCSHDRCMPLT, &one); +/* Tell the kernel that the header is fully-formed when it gets it. + This is required in order to fake the src address. */ +if (dev->eth_api == ETH_API_PCAP) { + int one = 1; + ioctl(pcap_fileno(dev->handle), BIOCSHDRCMPLT, &one); } #endif /* xBSD */ #if defined (USE_READER_THREAD) - { +if (1) { pthread_attr_t attr; #if defined(_WIN32) @@ -1473,318 +1557,344 @@ t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit) } #else /* !defined (USE_READER_THREAD */ #ifdef USE_SETNONBLOCK - /* set ethernet device non-blocking so pcap_dispatch() doesn't hang */ - if (dev->pcap_mode && (pcap_setnonblock (dev->handle, 1, errbuf) == -1)) { - msg = "Eth: Failed to set non-blocking: %s\r\n"; - printf (msg, errbuf); - if (sim_log) fprintf (sim_log, msg, errbuf); +/* set ethernet device non-blocking so pcap_dispatch() doesn't hang */ +if ((dev->eth_api == ETH_API_PCAP) && (pcap_setnonblock (dev->handle, 1, errbuf) == -1)) { + msg = "Eth: Failed to set non-blocking: %s\r\n"; + printf (msg, errbuf); + if (sim_log) fprintf (sim_log, msg, errbuf); } #endif #endif /* !defined (USE_READER_THREAD */ #if defined (__APPLE__) - if (dev->pcap_mode) { - /* Deliver packets immediately, needed for OS X 10.6.2 and later - * (Snow-Leopard). - * See this thread on libpcap and Mac Os X 10.6 Snow Leopard on - * the tcpdump mailinglist: http://seclists.org/tcpdump/2010/q1/110 - */ - int v = 1; - ioctl(pcap_fileno(dev->handle), BIOCIMMEDIATE, &v); +if (dev->eth_api == ETH_API_PCAP) { + /* Deliver packets immediately, needed for OS X 10.6.2 and later + * (Snow-Leopard). + * See this thread on libpcap and Mac Os X 10.6 Snow Leopard on + * the tcpdump mailinglist: http://seclists.org/tcpdump/2010/q1/110 + */ + int v = 1; + ioctl(pcap_fileno(dev->handle), BIOCIMMEDIATE, &v); } #endif - return SCPE_OK; +return SCPE_OK; } t_stat eth_close(ETH_DEV* dev) { - char* msg = "Eth: closed %s\r\n"; - pcap_t *pcap; - int pcap_fd = dev->fd_handle; +char* msg = "Eth: closed %s\r\n"; +pcap_t *pcap; +int pcap_fd = dev->fd_handle; - /* make sure device exists */ - if (!dev) return SCPE_UNATT; +/* make sure device exists */ +if (!dev) return SCPE_UNATT; - /* close the device */ - pcap = (pcap_t *)dev->handle; - dev->handle = NULL; - dev->fd_handle = 0; - dev->have_host_nic_phy_addr = 0; +/* close the device */ +pcap = (pcap_t *)dev->handle; +dev->handle = NULL; +dev->fd_handle = 0; +dev->have_host_nic_phy_addr = 0; #if defined (USE_READER_THREAD) - pthread_join (dev->reader_thread, NULL); - pthread_mutex_destroy (&dev->lock); - pthread_cond_signal (&dev->writer_cond); - pthread_join (dev->writer_thread, NULL); - pthread_mutex_destroy (&dev->self_lock); - pthread_mutex_destroy (&dev->writer_lock); - pthread_cond_destroy (&dev->writer_cond); - if (1) { - struct write_request *buffer; - - while (buffer = dev->write_buffers) { - dev->write_buffers = buffer->next; - free(buffer); +pthread_join (dev->reader_thread, NULL); +pthread_mutex_destroy (&dev->lock); +pthread_cond_signal (&dev->writer_cond); +pthread_join (dev->writer_thread, NULL); +pthread_mutex_destroy (&dev->self_lock); +pthread_mutex_destroy (&dev->writer_lock); +pthread_cond_destroy (&dev->writer_cond); +if (1) { + struct write_request *buffer; + while (buffer = dev->write_buffers) { + dev->write_buffers = buffer->next; + free(buffer); } - while (buffer = dev->write_requests) { - dev->write_requests = buffer->next; - free(buffer); + while (buffer = dev->write_requests) { + dev->write_requests = buffer->next; + free(buffer); } } - ethq_destroy (&dev->read_queue); /* release FIFO queue */ +ethq_destroy (&dev->read_queue); /* release FIFO queue */ #endif - if (dev->pcap_mode) +switch (dev->eth_api) { + case ETH_API_PCAP: pcap_close(pcap); + break; #ifdef USE_TAP_NETWORK - else + case ETH_API_TAP: close(pcap_fd); + break; #endif - printf (msg, dev->name); - if (sim_log) fprintf (sim_log, msg, dev->name); +#ifdef USE_VDE_NETWORK + case ETH_API_VDE: + vde_close((VDECONN*)pcap); + break; +#endif + } +printf (msg, dev->name); +if (sim_log) fprintf (sim_log, msg, dev->name); - /* clean up the mess */ - free(dev->name); - eth_zero(dev); +/* clean up the mess */ +free(dev->name); +eth_zero(dev); - return SCPE_OK; +return SCPE_OK; } t_stat eth_check_address_conflict (ETH_DEV* dev, ETH_MAC* const mac) { - ETH_PACK send, recv; - t_stat status; - int responses = 0; - char mac_string[32]; +ETH_PACK send, recv; +t_stat status; +int responses = 0; +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); +eth_mac_fmt(mac, mac_string); +sim_debug(dev->dbit, dev->dptr, "Determining Address Conflict for MAC address: %s\n", mac_string); - /* build a loopback forward request packet */ - memset (&send, 0, sizeof(ETH_PACK)); - send.len = ETH_MIN_PACKET; /* minimum packet size */ - memcpy(&send.msg[0], mac, sizeof(ETH_MAC)); /* target address */ - memcpy(&send.msg[6], mac, sizeof(ETH_MAC)); /* source address */ - send.msg[12] = 0x90; /* loopback packet type */ - send.msg[14] = 0; /* Offset */ - send.msg[16] = 2; /* Forward */ - memcpy(&send.msg[18], mac, sizeof(ETH_MAC)); /* Forward Destination */ - send.msg[24] = 1; /* Reply */ +/* build a loopback forward request packet */ +memset (&send, 0, sizeof(ETH_PACK)); +send.len = ETH_MIN_PACKET; /* minimum packet size */ +memcpy(&send.msg[0], mac, sizeof(ETH_MAC)); /* target address */ +memcpy(&send.msg[6], mac, sizeof(ETH_MAC)); /* source address */ +send.msg[12] = 0x90; /* loopback packet type */ +send.msg[14] = 0; /* Offset */ +send.msg[16] = 2; /* Forward */ +memcpy(&send.msg[18], mac, sizeof(ETH_MAC)); /* Forward Destination */ +send.msg[24] = 1; /* Reply */ - eth_filter(dev, 1, (ETH_MAC *)mac, 0, 0); +eth_filter(dev, 1, (ETH_MAC *)mac, 0, 0); - /* send the packet */ - status = _eth_write (dev, &send, NULL); - 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"; - printf(msg, strerror(errno)); - if (sim_log) fprintf (sim_log, msg, strerror(errno)); - return status; +/* send the packet */ +status = _eth_write (dev, &send, NULL); +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"; + printf(msg, strerror(errno)); + if (sim_log) fprintf (sim_log, msg, strerror(errno)); + return status; } - sim_os_ms_sleep (300); /* time for a conflicting host to respond */ +sim_os_ms_sleep (300); /* time for a conflicting host to respond */ - /* empty the read queue and count the responses */ - do { - memset (&recv, 0, sizeof(ETH_PACK)); - status = eth_read (dev, &recv, NULL); - if (memcmp(send.msg, recv.msg, 14)== 0) - responses++; +/* empty the read queue and count the responses */ +do { + memset (&recv, 0, sizeof(ETH_PACK)); + status = eth_read (dev, &recv, NULL); + if (memcmp(send.msg, recv.msg, 14)== 0) + responses++; } while (recv.len > 0); - sim_debug(dev->dbit, dev->dptr, "Address Conflict = %d\n", responses); - return responses; +sim_debug(dev->dbit, dev->dptr, "Address Conflict = %d\n", responses); +return responses; } t_stat eth_reflect(ETH_DEV* dev) { - /* Test with an address no NIC should have. */ - /* We do this to avoid reflections from the wire, */ - /* in the event that a simulated NIC has a MAC address conflict. */ - ETH_MAC mac = {0xfe,0xff,0xff,0xff,0xff,0xfe}; +/* Test with an address no NIC should have. */ +/* We do this to avoid reflections from the wire, */ +/* in the event that a simulated NIC has a MAC address conflict. */ +ETH_MAC mac = {0xfe,0xff,0xff,0xff,0xff,0xfe}; - sim_debug(dev->dbit, dev->dptr, "Determining Reflections...\n"); +sim_debug(dev->dbit, dev->dptr, "Determining Reflections...\n"); - dev->reflections = 0; - dev->reflections = eth_check_address_conflict (dev, &mac); +dev->reflections = 0; +dev->reflections = eth_check_address_conflict (dev, &mac); - sim_debug(dev->dbit, dev->dptr, "Reflections = %d\n", dev->reflections); - return dev->reflections; +sim_debug(dev->dbit, dev->dptr, "Reflections = %d\n", dev->reflections); +return dev->reflections; } static t_stat _eth_write(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine) { - int status = 1; /* default to failure */ +int status = 1; /* default to failure */ - /* make sure device exists */ - if (!dev) return SCPE_UNATT; +/* make sure device exists */ +if (!dev) return SCPE_UNATT; - /* make sure packet exists */ - if (!packet) return SCPE_ARG; +/* make sure packet exists */ +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); +/* 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); - eth_packet_trace (dev, packet->msg, packet->len, "writing"); + 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) { + /* record sending of loopback packet (done before actual send to avoid race conditions with receiver) */ + if (loopback_self_frame) { #ifdef USE_READER_THREAD - pthread_mutex_lock (&dev->self_lock); + pthread_mutex_lock (&dev->self_lock); #endif - dev->loopback_self_sent += dev->reflections; - dev->loopback_self_sent_total++; + dev->loopback_self_sent += dev->reflections; + dev->loopback_self_sent_total++; #ifdef USE_READER_THREAD - pthread_mutex_unlock (&dev->self_lock); + pthread_mutex_unlock (&dev->self_lock); #endif } /* 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); + break; #ifdef USE_TAP_NETWORK - else + case ETH_API_TAP: status = ((packet->len == write(dev->fd_handle, (void *)packet->msg, packet->len)) ? 0 : -1); + break; #endif - - /* On error, correct loopback bookkeeping */ - if ((status != 0) && loopback_self_frame) { -#ifdef USE_READER_THREAD - pthread_mutex_lock (&dev->self_lock); +#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 - dev->loopback_self_sent -= dev->reflections; - dev->loopback_self_sent_total--; + } + /* On error, correct loopback bookkeeping */ + if ((status != 0) && loopback_self_frame) { #ifdef USE_READER_THREAD - pthread_mutex_unlock (&dev->self_lock); + pthread_mutex_lock (&dev->self_lock); +#endif + dev->loopback_self_sent -= dev->reflections; + dev->loopback_self_sent_total--; +#ifdef USE_READER_THREAD + pthread_mutex_unlock (&dev->self_lock); #endif } } /* if packet->len */ - /* call optional write callback function */ - if (routine) - (routine)(status); +/* call optional write callback function */ +if (routine) + (routine)(status); - return ((status == 0) ? SCPE_OK : SCPE_IOERR); +return ((status == 0) ? SCPE_OK : SCPE_IOERR); } t_stat eth_write(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine) { #ifdef USE_READER_THREAD - struct write_request *request; - int write_queue_size = 1; +struct write_request *request; +int write_queue_size = 1; - /* make sure device exists */ - if (!dev) return SCPE_UNATT; +/* make sure device exists */ +if (!dev) return SCPE_UNATT; - /* Get a buffer */ - pthread_mutex_lock (&dev->writer_lock); - if (request = dev->write_buffers) - dev->write_buffers = request->next; - pthread_mutex_unlock (&dev->writer_lock); - if (!request) - request = malloc(sizeof(*request)); +/* Get a buffer */ +pthread_mutex_lock (&dev->writer_lock); +if (request = dev->write_buffers) + dev->write_buffers = request->next; +pthread_mutex_unlock (&dev->writer_lock); +if (!request) + request = malloc(sizeof(*request)); - /* Copy buffer contents */ - request->packet.len = packet->len; - request->packet.used = packet->used; - request->packet.status = packet->status; - request->packet.crc_len = packet->crc_len; - memcpy(request->packet.msg, packet->msg, packet->len); +/* Copy buffer contents */ +request->packet.len = packet->len; +request->packet.used = packet->used; +request->packet.status = packet->status; +request->packet.crc_len = packet->crc_len; +memcpy(request->packet.msg, packet->msg, packet->len); - /* Insert buffer at the end of the write list (to make sure that */ - /* packets make it to the wire in the order they were presented here) */ - pthread_mutex_lock (&dev->writer_lock); - request->next = NULL; - if (dev->write_requests) { - struct write_request *last_request = dev->write_requests; +/* Insert buffer at the end of the write list (to make sure that */ +/* packets make it to the wire in the order they were presented here) */ +pthread_mutex_lock (&dev->writer_lock); +request->next = NULL; +if (dev->write_requests) { + struct write_request *last_request = dev->write_requests; + ++write_queue_size; + while (last_request->next) { + last_request = last_request->next; ++write_queue_size; - while (last_request->next) { - last_request = last_request->next; - ++write_queue_size; } - last_request->next = request; - } else + last_request->next = request; + } +else dev->write_requests = request; - if (write_queue_size > dev->write_queue_peak) - dev->write_queue_peak = write_queue_size; - pthread_mutex_unlock (&dev->writer_lock); +if (write_queue_size > dev->write_queue_peak) + dev->write_queue_peak = write_queue_size; +pthread_mutex_unlock (&dev->writer_lock); - /* Awaken writer thread to perform actual write */ - pthread_cond_signal (&dev->writer_cond); +/* Awaken writer thread to perform actual write */ +pthread_cond_signal (&dev->writer_cond); - /* Return with a status from some prior write */ - if (routine) - (routine)(dev->write_status); - return dev->write_status; +/* Return with a status from some prior write */ +if (routine) + (routine)(dev->write_status); +return dev->write_status; #else - return _eth_write(dev, packet, routine); +return _eth_write(dev, packet, routine); #endif } static int _eth_hash_lookup(ETH_MULTIHASH hash, const u_char* data) { - int key = 0x3f & (eth_crc32(0, data, 6) >> 26); +int key = 0x3f & (eth_crc32(0, data, 6) >> 26); - key ^= 0x3f; - return (hash[key>>3] & (1 << (key&0x7))); +key ^= 0x3f; +return (hash[key>>3] & (1 << (key&0x7))); } static int _eth_hash_validate(ETH_MAC *MultiCastList, int count, ETH_MULTIHASH hash) { - ETH_MULTIHASH lhash; - int i; +ETH_MULTIHASH lhash; +int i; - memset(lhash, 0, sizeof(lhash)); - for (i=0; i> 26); +memset(lhash, 0, sizeof(lhash)); +for (i=0; i> 26); - key ^= 0x3F; - printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X Key: %X, Byte: %X, Val: %X\n", - MultiCastList[i][0], MultiCastList[i][1], MultiCastList[i][2], MultiCastList[i][3], MultiCastList[i][4], MultiCastList[i][5], - key, key>>3, (1 << (key&0x7))); - lhash[key>>3] |= (1 << (key&0x7)); + key ^= 0x3F; + printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X Key: %X, Byte: %X, Val: %X\n", + MultiCastList[i][0], MultiCastList[i][1], MultiCastList[i][2], MultiCastList[i][3], MultiCastList[i][4], MultiCastList[i][5], + key, key>>3, (1 << (key&0x7))); + lhash[key>>3] |= (1 << (key&0x7)); } - if (memcmp(hash, lhash, sizeof(lhash))) { - printf("Inconsistent Computed Hash:\n"); - printf("Should be: %02X %02X %02X %02X %02X %02X %02X %02X\n", - hash[0], hash[1], hash[2], hash[3], - hash[4], hash[5], hash[6], hash[7]); - printf("Was: %02X %02X %02X %02X %02X %02X %02X %02X\n", - lhash[0], lhash[1], lhash[2], lhash[3], - lhash[4], lhash[5], lhash[6], lhash[7]); +if (memcmp(hash, lhash, sizeof(lhash))) { + printf("Inconsistent Computed Hash:\n"); + printf("Should be: %02X %02X %02X %02X %02X %02X %02X %02X\n", + hash[0], hash[1], hash[2], hash[3], + hash[4], hash[5], hash[6], hash[7]); + printf("Was: %02X %02X %02X %02X %02X %02X %02X %02X\n", + lhash[0], lhash[1], lhash[2], lhash[3], + lhash[4], lhash[5], lhash[6], lhash[7]); } - printf("Should be: %02X %02X %02X %02X %02X %02X %02X %02X\n", - hash[0], hash[1], hash[2], hash[3], - hash[4], hash[5], hash[6], hash[7]); - printf("Was: %02X %02X %02X %02X %02X %02X %02X %02X\n", - lhash[0], lhash[1], lhash[2], lhash[3], - lhash[4], lhash[5], lhash[6], lhash[7]); - return 0; +else { + printf("Should be: %02X %02X %02X %02X %02X %02X %02X %02X\n", + hash[0], hash[1], hash[2], hash[3], + hash[4], hash[5], hash[6], hash[7]); + printf("Was: %02X %02X %02X %02X %02X %02X %02X %02X\n", + lhash[0], lhash[1], lhash[2], lhash[3], + lhash[4], lhash[5], lhash[6], lhash[7]); + } +return 0; } static void _eth_test_multicast_hash() { - ETH_MAC tMacs[] = { - {0xAB, 0x00, 0x04, 0x01, 0xAC, 0x10}, - {0xAB, 0x00, 0x00, 0x04, 0x00, 0x00}, - {0x09, 0x00, 0x2B, 0x00, 0x00, 0x0F}, - {0x09, 0x00, 0x2B, 0x02, 0x01, 0x04}, - {0x09, 0x00, 0x2B, 0x02, 0x01, 0x07}, - {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, - {0x01, 0x00, 0x5E, 0x00, 0x00, 0x01}}; - ETH_MULTIHASH thash = {0x01, 0x40, 0x00, 0x00, 0x48, 0x88, 0x40, 0x00}; +ETH_MAC tMacs[] = { + {0xAB, 0x00, 0x04, 0x01, 0xAC, 0x10}, + {0xAB, 0x00, 0x00, 0x04, 0x00, 0x00}, + {0x09, 0x00, 0x2B, 0x00, 0x00, 0x0F}, + {0x09, 0x00, 0x2B, 0x02, 0x01, 0x04}, + {0x09, 0x00, 0x2B, 0x02, 0x01, 0x07}, + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + {0x01, 0x00, 0x5E, 0x00, 0x00, 0x01}}; +ETH_MULTIHASH thash = {0x01, 0x40, 0x00, 0x00, 0x48, 0x88, 0x40, 0x00}; - _eth_hash_validate(tMacs, sizeof(tMacs)/sizeof(tMacs[0]), thash); +_eth_hash_validate(tMacs, sizeof(tMacs)/sizeof(tMacs[0]), thash); } /* The IP header */ @@ -1807,7 +1917,7 @@ struct IPHeader { uint16 checksum; /* IP checksum */ uint32 source_ip; /* Source Address */ uint32 dest_ip; /* Destination Address */ -}; + }; /* ICMP header */ struct ICMPHeader { @@ -1815,14 +1925,14 @@ struct ICMPHeader { uint8 code; /* Type sub code */ uint16 checksum; /* ICMP Checksum */ uint32 otherstuff[1];/* optional data */ -}; + }; struct UDPHeader { uint16 source_port; uint16 dest_port; uint16 length; /* The length of the entire UDP datagram, including both header and Data fields. */ uint16 checksum; -}; + }; struct TCPHeader { uint16 source_port; @@ -1844,7 +1954,7 @@ struct TCPHeader { uint16 checksum; uint16 urgent; uint16 otherstuff[1]; /* The rest of the packet */ -}; + }; #ifndef IPPROTO_TCP #define IPPROTO_TCP 6 /* tcp */ @@ -1859,484 +1969,516 @@ struct TCPHeader { static uint16 ip_checksum(uint16 *buffer, int size) { - unsigned long cksum = 0; +unsigned long cksum = 0; - /* Sum all the words together, adding the final byte if size is odd */ - while (size > 1) { - cksum += *buffer++; - size -= sizeof(*buffer); - } - if (size) { - uint8 endbytes[2]; +/* Sum all the words together, adding the final byte if size is odd */ +while (size > 1) { + cksum += *buffer++; + size -= sizeof(*buffer); +} +if (size) { + uint8 endbytes[2]; - endbytes[0] = *((uint8 *)buffer); - endbytes[1] = 0; - cksum += *((uint16 *)endbytes); + endbytes[0] = *((uint8 *)buffer); + endbytes[1] = 0; + cksum += *((uint16 *)endbytes); } - /* Do a little shuffling */ - cksum = (cksum >> 16) + (cksum & 0xffff); - cksum += (cksum >> 16); +/* Do a little shuffling */ +cksum = (cksum >> 16) + (cksum & 0xffff); +cksum += (cksum >> 16); - /* Return the bitwise complement of the resulting mishmash */ - return (uint16)(~cksum); +/* Return the bitwise complement of the resulting mishmash */ +return (uint16)(~cksum); } static uint16 pseudo_checksum(uint16 len, uint16 proto, uint16 *src_addr, uint16 *dest_addr, uint8 *buff) { - uint32 sum; +uint32 sum; - /* Sum the data first */ - sum = 0xffff&(~ip_checksum((uint16 *)buff, len)); +/* Sum the data first */ +sum = 0xffff&(~ip_checksum((uint16 *)buff, len)); - /* add the pseudo header which contains the IP source and destinationn addresses */ - sum += src_addr[0]; - sum += src_addr[1]; - sum += dest_addr[0]; - sum += dest_addr[1]; - /* and the protocol number and the length of the UDP packet */ - sum = sum + htons(proto) + htons(len); +/* add the pseudo header which contains the IP source and destinationn addresses */ +sum += src_addr[0]; +sum += src_addr[1]; +sum += dest_addr[0]; +sum += dest_addr[1]; +/* and the protocol number and the length of the UDP packet */ +sum = sum + htons(proto) + htons(len); - /* Do a little shuffling */ - sum = (sum >> 16) + (sum & 0xffff); - sum += (sum >> 16); +/* Do a little shuffling */ +sum = (sum >> 16) + (sum & 0xffff); +sum += (sum >> 16); - /* Return the bitwise complement of the resulting mishmash */ - return (uint16)(~sum); +/* Return the bitwise complement of the resulting mishmash */ +return (uint16)(~sum); } static void _eth_fix_ip_jumbo_offload(ETH_DEV* dev, const u_char* msg, int len) { - unsigned short* proto = (unsigned short*) &msg[12]; - struct IPHeader *IP; - struct TCPHeader *TCP = NULL; - struct UDPHeader *UDP; - struct ICMPHeader *ICMP; - uint16 orig_checksum; - uint16 payload_len; - uint16 mtu_payload; - uint16 ip_flags; - uint16 frag_offset; - struct pcap_pkthdr header; - uint16 orig_tcp_flags; +unsigned short* proto = (unsigned short*) &msg[12]; +struct IPHeader *IP; +struct TCPHeader *TCP = NULL; +struct UDPHeader *UDP; +struct ICMPHeader *ICMP; +uint16 orig_checksum; +uint16 payload_len; +uint16 mtu_payload; +uint16 ip_flags; +uint16 frag_offset; +struct pcap_pkthdr header; +uint16 orig_tcp_flags; - /* Only interested in IP frames */ - if (ntohs(*proto) != 0x0800) { - ++dev->jumbo_dropped; /* Non IP Frames are dropped */ - return; +/* Only interested in IP frames */ +if (ntohs(*proto) != 0x0800) { + ++dev->jumbo_dropped; /* Non IP Frames are dropped */ + return; } - IP = (struct IPHeader *)&msg[14]; - if (IP_VERSION(IP) != 4) { - ++dev->jumbo_dropped; /* Non IPv4 jumbo frames are dropped */ - return; +IP = (struct IPHeader *)&msg[14]; +if (IP_VERSION(IP) != 4) { + ++dev->jumbo_dropped; /* Non IPv4 jumbo frames are dropped */ + return; } - if ((IP_HLEN(IP) > len) || (ntohs(IP->total_len) > len)) { - ++dev->jumbo_dropped; /* Bogus header length frames are dropped */ - return; +if ((IP_HLEN(IP) > len) || (ntohs(IP->total_len) > len)) { + ++dev->jumbo_dropped; /* Bogus header length frames are dropped */ + return; } - if (IP_FRAG_OFFSET(IP) || IP_FRAG_MF(IP)) { - ++dev->jumbo_dropped; /* Previously fragmented, but currently jumbo sized frames are dropped */ - return; +if (IP_FRAG_OFFSET(IP) || IP_FRAG_MF(IP)) { + ++dev->jumbo_dropped; /* Previously fragmented, but currently jumbo sized frames are dropped */ + return; } - switch (IP->proto) { - case IPPROTO_UDP: - UDP = (struct UDPHeader *)(((char *)IP)+IP_HLEN(IP)); - if (ntohs(UDP->length) > (len-IP_HLEN(IP))) { - ++dev->jumbo_dropped; /* Bogus UDP packet length (packet contained length exceeds packet size) frames are dropped */ - return; - } - if (UDP->checksum == 0) - break; /* UDP Checksums are disabled */ - orig_checksum = UDP->checksum; - UDP->checksum = 0; - UDP->checksum = pseudo_checksum(ntohs(UDP->length), IPPROTO_UDP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)UDP); - if (orig_checksum != UDP->checksum) - eth_packet_trace (dev, msg, len, "reading jumbo UDP header Checksum Fixed"); - break; - case IPPROTO_ICMP: - ICMP = (struct ICMPHeader *)(((char *)IP)+IP_HLEN(IP)); - orig_checksum = ICMP->checksum; - ICMP->checksum = 0; - ICMP->checksum = ip_checksum((uint16 *)ICMP, ntohs(IP->total_len)-IP_HLEN(IP)); - if (orig_checksum != ICMP->checksum) - eth_packet_trace (dev, msg, len, "reading jumbo ICMP header Checksum Fixed"); - break; - case IPPROTO_TCP: - TCP = (struct TCPHeader *)(((char *)IP)+IP_HLEN(IP)); - if ((TCP_DATA_OFFSET(TCP) > (len-IP_HLEN(IP))) || (TCP_DATA_OFFSET(TCP) < 20)) { - ++dev->jumbo_dropped; /* Bogus TCP packet header length (packet contained length exceeds packet size) frames are dropped */ - return; - } - /* We don't do anything with the TCP checksum since we're going to resegment the TCP data below */ - break; - default: - ++dev->jumbo_dropped; /* We onlt handle UDP, ICMP and TCP jumbo frames others are dropped */ +switch (IP->proto) { + case IPPROTO_UDP: + UDP = (struct UDPHeader *)(((char *)IP)+IP_HLEN(IP)); + if (ntohs(UDP->length) > (len-IP_HLEN(IP))) { + ++dev->jumbo_dropped; /* Bogus UDP packet length (packet contained length exceeds packet size) frames are dropped */ return; + } + if (UDP->checksum == 0) + break; /* UDP Checksums are disabled */ + orig_checksum = UDP->checksum; + UDP->checksum = 0; + UDP->checksum = pseudo_checksum(ntohs(UDP->length), IPPROTO_UDP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)UDP); + if (orig_checksum != UDP->checksum) + eth_packet_trace (dev, msg, len, "reading jumbo UDP header Checksum Fixed"); + break; + case IPPROTO_ICMP: + ICMP = (struct ICMPHeader *)(((char *)IP)+IP_HLEN(IP)); + orig_checksum = ICMP->checksum; + ICMP->checksum = 0; + ICMP->checksum = ip_checksum((uint16 *)ICMP, ntohs(IP->total_len)-IP_HLEN(IP)); + if (orig_checksum != ICMP->checksum) + eth_packet_trace (dev, msg, len, "reading jumbo ICMP header Checksum Fixed"); + break; + case IPPROTO_TCP: + TCP = (struct TCPHeader *)(((char *)IP)+IP_HLEN(IP)); + if ((TCP_DATA_OFFSET(TCP) > (len-IP_HLEN(IP))) || (TCP_DATA_OFFSET(TCP) < 20)) { + ++dev->jumbo_dropped; /* Bogus TCP packet header length (packet contained length exceeds packet size) frames are dropped */ + return; + } + /* We don't do anything with the TCP checksum since we're going to resegment the TCP data below */ + break; + default: + ++dev->jumbo_dropped; /* We onlt handle UDP, ICMP and TCP jumbo frames others are dropped */ + return; } - /* Reasonable Checksums are now in the jumbo packet, but we've got to actually */ - /* deliver ONLY standard sized ethernet frames. Our job here is to now act as */ - /* a router might have to and fragment these IPv4 frames as they are delivered */ - /* into the virtual NIC. We do this by walking down the packet and dispatching */ - /* a chunk at a time recomputing an appropriate header for each chunk. For */ - /* datagram oriented protocols (UDP and ICMP) this is done by simple packet */ - /* fragmentation. For TCP this is done by breaking large packets into separate */ - /* TCP packets. */ - memset(&header, 0, sizeof(header)); - switch (IP->proto) { - case IPPROTO_UDP: - case IPPROTO_ICMP: - ++dev->jumbo_fragmented; - /* When we're performing LSO (Large Send Offload), we're given a - 'template' header which may not include a value being populated - in the IP header length (which is only 16 bits). - We process as payload everything which isn't known header data. */ - payload_len = len - (14 + IP_HLEN(IP)); - mtu_payload = ETH_MIN_JUMBO_FRAME - (14 + IP_HLEN(IP)); - frag_offset = 0; - while (payload_len > 0) { - ip_flags = frag_offset; - if (payload_len > mtu_payload) { - ip_flags |= IP_MF_FLAG; - IP->total_len = htons(((mtu_payload>>3)<<3) + IP_HLEN(IP)); - } else { - IP->total_len = htons(payload_len + IP_HLEN(IP)); +/* Reasonable Checksums are now in the jumbo packet, but we've got to actually */ +/* deliver ONLY standard sized ethernet frames. Our job here is to now act as */ +/* a router might have to and fragment these IPv4 frames as they are delivered */ +/* into the virtual NIC. We do this by walking down the packet and dispatching */ +/* a chunk at a time recomputing an appropriate header for each chunk. For */ +/* datagram oriented protocols (UDP and ICMP) this is done by simple packet */ +/* fragmentation. For TCP this is done by breaking large packets into separate */ +/* TCP packets. */ +memset(&header, 0, sizeof(header)); +switch (IP->proto) { + case IPPROTO_UDP: + case IPPROTO_ICMP: + ++dev->jumbo_fragmented; + /* When we're performing LSO (Large Send Offload), we're given a + 'template' header which may not include a value being populated + in the IP header length (which is only 16 bits). + We process as payload everything which isn't known header data. */ + payload_len = len - (14 + IP_HLEN(IP)); + mtu_payload = ETH_MIN_JUMBO_FRAME - (14 + IP_HLEN(IP)); + frag_offset = 0; + while (payload_len > 0) { + ip_flags = frag_offset; + if (payload_len > mtu_payload) { + ip_flags |= IP_MF_FLAG; + IP->total_len = htons(((mtu_payload>>3)<<3) + IP_HLEN(IP)); } - IP->flags = htons(ip_flags); - IP->checksum = 0; - IP->checksum = ip_checksum((uint16 *)IP, IP_HLEN(IP)); - header.caplen = header.len = 14 + ntohs(IP->total_len); - eth_packet_trace (dev, ((u_char *)IP)-14, header.len, "reading Datagram fragment"); + else { + IP->total_len = htons(payload_len + IP_HLEN(IP)); + } + IP->flags = htons(ip_flags); + IP->checksum = 0; + IP->checksum = ip_checksum((uint16 *)IP, IP_HLEN(IP)); + header.caplen = header.len = 14 + ntohs(IP->total_len); + eth_packet_trace (dev, ((u_char *)IP)-14, header.len, "reading Datagram fragment"); #if ETH_MIN_JUMBO_FRAME < ETH_MAX_PACKET - { /* Debugging is easier if we read packets directly with pcap - (i.e. we can use Wireshark to verify packet contents) - we don't want to do this all the time for 2 reasons: - 1) sending through pcap involves kernel transitions and - 2) if the current system reflects sent packets, the - recieving side will receive and process 2 copies of - any packets sent this way. */ - ETH_PACK pkt; + if (1) { + /* Debugging is easier if we read packets directly with pcap + (i.e. we can use Wireshark to verify packet contents) + we don't want to do this all the time for 2 reasons: + 1) sending through pcap involves kernel transitions and + 2) if the current system reflects sent packets, the + recieving side will receive and process 2 copies of + any packets sent this way. */ + ETH_PACK pkt; - memset(&pkt, 0, sizeof(pkt)); - memcpy(pkt.msg, ((u_char *)IP)-14, header.len); - pkt.len = header.len; - _eth_write(dev, &pkt, NULL); - } + memset(&pkt, 0, sizeof(pkt)); + memcpy(pkt.msg, ((u_char *)IP)-14, header.len); + pkt.len = header.len; + _eth_write(dev, &pkt, NULL); + } #else - _eth_callback((u_char *)dev, &header, ((u_char *)IP)-14); + _eth_callback((u_char *)dev, &header, ((u_char *)IP)-14); #endif - payload_len -= (ntohs(IP->total_len) - IP_HLEN(IP)); - frag_offset += (ntohs(IP->total_len) - IP_HLEN(IP))>>3; - if (payload_len > 0) { - /* Move the MAC and IP headers down to just prior to the next payload segment */ - memcpy(((u_char *)IP) + ntohs(IP->total_len) - (14 + IP_HLEN(IP)), ((u_char *)IP) - 14, 14 + IP_HLEN(IP)); - IP = (struct IPHeader *)(((u_char *)IP) + ntohs(IP->total_len) - IP_HLEN(IP)); + payload_len -= (ntohs(IP->total_len) - IP_HLEN(IP)); + frag_offset += (ntohs(IP->total_len) - IP_HLEN(IP))>>3; + if (payload_len > 0) { + /* Move the MAC and IP headers down to just prior to the next payload segment */ + memcpy(((u_char *)IP) + ntohs(IP->total_len) - (14 + IP_HLEN(IP)), ((u_char *)IP) - 14, 14 + IP_HLEN(IP)); + IP = (struct IPHeader *)(((u_char *)IP) + ntohs(IP->total_len) - IP_HLEN(IP)); } } - break; - case IPPROTO_TCP: - ++dev->jumbo_fragmented; - eth_packet_trace_ex (dev, ((u_char *)IP)-14, len, "Fragmenting Jumbo TCP segment", 1, dev->dbit); - TCP = (struct TCPHeader *)(((char *)IP)+IP_HLEN(IP)); - orig_tcp_flags = ntohs(TCP->data_offset_and_flags); - /* When we're performing LSO (Large Send Offload), we're given a - 'template' header which may not include a value being populated - in the IP header length (which is only 16 bits). - We process as payload everything which isn't known header data. */ - payload_len = len - (14 + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)); - mtu_payload = ETH_MIN_JUMBO_FRAME - (14 + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)); - while (payload_len > 0) { - if (payload_len > mtu_payload) { - 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)); - } else { - TCP->data_offset_and_flags = htons(orig_tcp_flags); - IP->total_len = htons(payload_len + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)); + break; + case IPPROTO_TCP: + ++dev->jumbo_fragmented; + eth_packet_trace_ex (dev, ((u_char *)IP)-14, len, "Fragmenting Jumbo TCP segment", 1, dev->dbit); + TCP = (struct TCPHeader *)(((char *)IP)+IP_HLEN(IP)); + orig_tcp_flags = ntohs(TCP->data_offset_and_flags); + /* When we're performing LSO (Large Send Offload), we're given a + 'template' header which may not include a value being populated + in the IP header length (which is only 16 bits). + We process as payload everything which isn't known header data. */ + payload_len = len - (14 + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)); + mtu_payload = ETH_MIN_JUMBO_FRAME - (14 + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)); + while (payload_len > 0) { + if (payload_len > mtu_payload) { + 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->checksum = 0; - IP->checksum = ip_checksum((uint16 *)IP, IP_HLEN(IP)); - TCP->checksum = 0; - TCP->checksum = pseudo_checksum(ntohs(IP->total_len)-IP_HLEN(IP), IPPROTO_TCP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)TCP); - 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); + else { + TCP->data_offset_and_flags = htons(orig_tcp_flags); + IP->total_len = htons(payload_len + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)); + } + IP->checksum = 0; + IP->checksum = ip_checksum((uint16 *)IP, IP_HLEN(IP)); + TCP->checksum = 0; + TCP->checksum = pseudo_checksum(ntohs(IP->total_len)-IP_HLEN(IP), IPPROTO_TCP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)TCP); + 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); #if ETH_MIN_JUMBO_FRAME < ETH_MAX_PACKET - { /* Debugging is easier if we read packets directly with pcap - (i.e. we can use Wireshark to verify packet contents) - we don't want to do this all the time for 2 reasons: - 1) sending through pcap involves kernel transitions and - 2) if the current system reflects sent packets, the - recieving side will receive and process 2 copies of - any packets sent this way. */ - ETH_PACK pkt; + if (1) { + /* Debugging is easier if we read packets directly with pcap + (i.e. we can use Wireshark to verify packet contents) + we don't want to do this all the time for 2 reasons: + 1) sending through pcap involves kernel transitions and + 2) if the current system reflects sent packets, the + recieving side will receive and process 2 copies of + any packets sent this way. */ + ETH_PACK pkt; - memset(&pkt, 0, sizeof(pkt)); - memcpy(pkt.msg, ((u_char *)IP)-14, header.len); - pkt.len = header.len; - _eth_write(dev, &pkt, NULL); - } + memset(&pkt, 0, sizeof(pkt)); + memcpy(pkt.msg, ((u_char *)IP)-14, header.len); + pkt.len = header.len; + _eth_write(dev, &pkt, NULL); + } #else - _eth_callback((u_char *)dev, &header, ((u_char *)IP)-14); + _eth_callback((u_char *)dev, &header, ((u_char *)IP)-14); #endif - payload_len -= (ntohs(IP->total_len) - (IP_HLEN(IP) + TCP_DATA_OFFSET(TCP))); - if (payload_len > 0) { - /* Move the MAC, IP and TCP headers down to just prior to the next payload segment */ - memcpy(((u_char *)IP) + ntohs(IP->total_len) - (14 + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)), ((u_char *)IP) - 14, 14 + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)); - IP = (struct IPHeader *)(((u_char *)IP) + ntohs(IP->total_len) - (IP_HLEN(IP) + TCP_DATA_OFFSET(TCP))); - TCP = (struct TCPHeader *)(((char *)IP)+IP_HLEN(IP)); - TCP->sequence_number = htonl(mtu_payload + ntohl(TCP->sequence_number)); + payload_len -= (ntohs(IP->total_len) - (IP_HLEN(IP) + TCP_DATA_OFFSET(TCP))); + if (payload_len > 0) { + /* Move the MAC, IP and TCP headers down to just prior to the next payload segment */ + memcpy(((u_char *)IP) + ntohs(IP->total_len) - (14 + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)), ((u_char *)IP) - 14, 14 + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)); + IP = (struct IPHeader *)(((u_char *)IP) + ntohs(IP->total_len) - (IP_HLEN(IP) + TCP_DATA_OFFSET(TCP))); + TCP = (struct TCPHeader *)(((char *)IP)+IP_HLEN(IP)); + TCP->sequence_number = htonl(mtu_payload + ntohl(TCP->sequence_number)); } } - break; + break; } } static void _eth_fix_ip_xsum_offload(ETH_DEV* dev, u_char* msg, int len) { - unsigned short* proto = (unsigned short*) &msg[12]; - struct IPHeader *IP; - struct TCPHeader *TCP; - struct UDPHeader *UDP; - struct ICMPHeader *ICMP; - uint16 orig_checksum; +unsigned short* proto = (unsigned short*) &msg[12]; +struct IPHeader *IP; +struct TCPHeader *TCP; +struct UDPHeader *UDP; +struct ICMPHeader *ICMP; +uint16 orig_checksum; - /* Only need to process locally originated packets */ - if ((!dev->have_host_nic_phy_addr) || (memcmp(msg+6, dev->host_nic_phy_hw_addr, 6))) - return; - /* Only interested in IP frames */ - if (ntohs(*proto) != 0x0800) - return; - IP = (struct IPHeader *)&msg[14]; - if (IP_VERSION(IP) != 4) - return; /* Only interested in IPv4 frames */ - if ((IP_HLEN(IP) > len) || (ntohs(IP->total_len) > len)) - return; /* Bogus header length */ - orig_checksum = IP->checksum; - IP->checksum = 0; - IP->checksum = ip_checksum((uint16 *)IP, IP_HLEN(IP)); - if (orig_checksum != IP->checksum) - eth_packet_trace (dev, msg, len, "reading IP header Checksum Fixed"); - if (IP_FRAG_OFFSET(IP) || IP_FRAG_MF(IP)) - return; /* Insufficient data to compute payload checksum */ - switch (IP->proto) { - case IPPROTO_UDP: - UDP = (struct UDPHeader *)(((char *)IP)+IP_HLEN(IP)); - if (ntohs(UDP->length) > (len-IP_HLEN(IP))) - return; /* packet contained length exceeds packet size */ - if (UDP->checksum == 0) - return; /* UDP Checksums are disabled */ - orig_checksum = UDP->checksum; - UDP->checksum = 0; - UDP->checksum = pseudo_checksum(ntohs(UDP->length), IPPROTO_UDP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)UDP); - if (orig_checksum != UDP->checksum) - eth_packet_trace (dev, msg, len, "reading UDP header Checksum Fixed"); - break; - case IPPROTO_TCP: - TCP = (struct TCPHeader *)(((char *)IP)+IP_HLEN(IP)); - orig_checksum = TCP->checksum; - TCP->checksum = 0; - TCP->checksum = pseudo_checksum(ntohs(IP->total_len)-IP_HLEN(IP), IPPROTO_TCP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)TCP); - if (orig_checksum != TCP->checksum) - eth_packet_trace (dev, msg, len, "reading TCP header Checksum Fixed"); - break; - case IPPROTO_ICMP: - ICMP = (struct ICMPHeader *)(((char *)IP)+IP_HLEN(IP)); - orig_checksum = ICMP->checksum; - ICMP->checksum = 0; - ICMP->checksum = ip_checksum((uint16 *)ICMP, ntohs(IP->total_len)-IP_HLEN(IP)); - if (orig_checksum != ICMP->checksum) - eth_packet_trace (dev, msg, len, "reading ICMP header Checksum Fixed"); - break; +/* Only need to process locally originated packets */ +if ((!dev->have_host_nic_phy_addr) || (memcmp(msg+6, dev->host_nic_phy_hw_addr, 6))) + return; +/* Only interested in IP frames */ +if (ntohs(*proto) != 0x0800) + return; +IP = (struct IPHeader *)&msg[14]; +if (IP_VERSION(IP) != 4) + return; /* Only interested in IPv4 frames */ +if ((IP_HLEN(IP) > len) || (ntohs(IP->total_len) > len)) + return; /* Bogus header length */ +orig_checksum = IP->checksum; +IP->checksum = 0; +IP->checksum = ip_checksum((uint16 *)IP, IP_HLEN(IP)); +if (orig_checksum != IP->checksum) + eth_packet_trace (dev, msg, len, "reading IP header Checksum Fixed"); +if (IP_FRAG_OFFSET(IP) || IP_FRAG_MF(IP)) + return; /* Insufficient data to compute payload checksum */ +switch (IP->proto) { + case IPPROTO_UDP: + UDP = (struct UDPHeader *)(((char *)IP)+IP_HLEN(IP)); + if (ntohs(UDP->length) > (len-IP_HLEN(IP))) + return; /* packet contained length exceeds packet size */ + if (UDP->checksum == 0) + return; /* UDP Checksums are disabled */ + orig_checksum = UDP->checksum; + UDP->checksum = 0; + UDP->checksum = pseudo_checksum(ntohs(UDP->length), IPPROTO_UDP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)UDP); + if (orig_checksum != UDP->checksum) + eth_packet_trace (dev, msg, len, "reading UDP header Checksum Fixed"); + break; + case IPPROTO_TCP: + TCP = (struct TCPHeader *)(((char *)IP)+IP_HLEN(IP)); + orig_checksum = TCP->checksum; + TCP->checksum = 0; + TCP->checksum = pseudo_checksum(ntohs(IP->total_len)-IP_HLEN(IP), IPPROTO_TCP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)TCP); + if (orig_checksum != TCP->checksum) + eth_packet_trace (dev, msg, len, "reading TCP header Checksum Fixed"); + break; + case IPPROTO_ICMP: + ICMP = (struct ICMPHeader *)(((char *)IP)+IP_HLEN(IP)); + orig_checksum = ICMP->checksum; + ICMP->checksum = 0; + ICMP->checksum = ip_checksum((uint16 *)ICMP, ntohs(IP->total_len)-IP_HLEN(IP)); + if (orig_checksum != ICMP->checksum) + eth_packet_trace (dev, msg, len, "reading ICMP header Checksum Fixed"); + break; } } static void _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; +int to_me; +int from_me = 0; +int i; +int bpf_used; + +switch (dev->eth_api) { + case ETH_API_PCAP: #ifdef USE_BPF - int to_me = 1; - - /* AUTODIN II hash mode? */ - if ((dev->hash_filter) && (data[0] & 0x01) && (!dev->promiscuous) && (!dev->all_multicast)) - to_me = _eth_hash_lookup(dev->hash, data); -#else /* !USE_BPF */ - int to_me = 0; - int from_me = 0; - int i; - - eth_packet_trace (dev, data, header->len, "received"); -f - for (i = 0; i < dev->addr_count; i++) { - 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; - } - - /* all multicast mode? */ - if (dev->all_multicast && (data[0] & 0x01)) to_me = 1; - - /* promiscuous mode? */ - if (dev->promiscuous) to_me = 1; - - /* AUTODIN II hash mode? */ - if ((dev->hash_filter) && (!to_me) && (data[0] & 0x01)) - to_me = _eth_hash_lookup(dev->hash, data); + bpf_used = 1; + to_me = 1; + /* AUTODIN II hash mode? */ + if ((dev->hash_filter) && (data[0] & 0x01) && (!dev->promiscuous) && (!dev->all_multicast)) + to_me = _eth_hash_lookup(dev->hash, data); + break; #endif /* USE_BPF */ + case ETH_API_TAP: + case ETH_API_VDE: + bpf_used = 0; + to_me = 0; + eth_packet_trace (dev, data, header->len, "received"); - /* detect reception of loopback packet to our physical address */ - if (LOOPBACK_SELF_FRAME(dev->physical_addr, data)) { + for (i = 0; i < dev->addr_count; i++) { + 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; + } + + /* all multicast mode? */ + if (dev->all_multicast && (data[0] & 0x01)) to_me = 1; + + /* promiscuous mode? */ + if (dev->promiscuous) to_me = 1; + + /* AUTODIN II hash mode? */ + if ((dev->hash_filter) && (!to_me) && (data[0] & 0x01)) + to_me = _eth_hash_lookup(dev->hash, data); + break; + } + +/* detect reception of loopback packet to our physical address */ +if (LOOPBACK_SELF_FRAME(dev->physical_addr, data)) { #ifdef USE_READER_THREAD - pthread_mutex_lock (&dev->self_lock); + pthread_mutex_lock (&dev->self_lock); #endif - dev->loopback_self_rcvd_total++; - /* lower reflection count - if already zero, pass it on */ - if (dev->loopback_self_sent > 0) { - eth_packet_trace (dev, data, header->len, "ignored"); - dev->loopback_self_sent--; - to_me = 0; - } -#ifndef USE_BPF - else + dev->loopback_self_rcvd_total++; + /* lower reflection count - if already zero, pass it on */ + if (dev->loopback_self_sent > 0) { + eth_packet_trace (dev, data, header->len, "ignored"); + dev->loopback_self_sent--; + to_me = 0; + } + else + if (!bpf_used) from_me = 0; -#endif #ifdef USE_READER_THREAD - pthread_mutex_unlock (&dev->self_lock); + pthread_mutex_unlock (&dev->self_lock); #endif } -#ifdef USE_BPF - if (to_me) { -#else /* !USE_BPF */ - if (to_me && !from_me) { -#endif - if (header->len > ETH_MIN_JUMBO_FRAME) { - if (header->len <= header->caplen) /* Whole Frame captured? */ - _eth_fix_ip_jumbo_offload(dev, data, header->len); - else - ++dev->jumbo_truncated; - return; +if (bpf_used ? to_me : (to_me && !from_me)) { + if (header->len > ETH_MIN_JUMBO_FRAME) { + if (header->len <= header->caplen) /* Whole Frame captured? */ + _eth_fix_ip_jumbo_offload(dev, data, header->len); + else + ++dev->jumbo_truncated; + return; } #if defined (USE_READER_THREAD) - if (1) { - int crc_len = 0; - uint8 crc_data[4]; - uint32 len = header->len; - u_char* moved_data = NULL; + if (1) { + int crc_len = 0; + uint8 crc_data[4]; + uint32 len = header->len; + u_char* moved_data = NULL; - if (header->len < ETH_MIN_PACKET) { /* Pad runt packets before CRC append */ - moved_data = malloc(ETH_MIN_PACKET); - memcpy(moved_data, data, len); - memset(moved_data + len, 0, ETH_MIN_PACKET-len); - len = ETH_MIN_PACKET; - data = moved_data; + if (header->len < ETH_MIN_PACKET) { /* Pad runt packets before CRC append */ + moved_data = malloc(ETH_MIN_PACKET); + memcpy(moved_data, data, len); + memset(moved_data + len, 0, ETH_MIN_PACKET-len); + len = ETH_MIN_PACKET; + data = moved_data; } - /* If necessary, fix IP header checksums for packets originated locally */ - /* but were presumed to be traversing a NIC which was going to handle that task */ - /* This must be done before any needed CRC calculation */ - _eth_fix_ip_xsum_offload(dev, (u_char*)data, len); - - if (dev->need_crc) - crc_len = eth_get_packet_crc32_data(data, len, crc_data); - - eth_packet_trace (dev, data, len, "rcvqd"); - - pthread_mutex_lock (&dev->lock); - ethq_insert_data(&dev->read_queue, 2, data, 0, len, crc_len, crc_data, 0); - pthread_mutex_unlock (&dev->lock); - free(moved_data); - } -#else - /* set data in passed read packet */ - dev->read_packet->len = header->len; - memcpy(dev->read_packet->msg, data, header->len); - /* Handle runt case and pad with zeros. */ - /* The real NIC won't hand us runts from the wire, BUT we may be getting */ - /* some packets looped back before they actually traverse the wire */ - /* (by an internal bridge device for instance) */ - if (header->len < ETH_MIN_PACKET) { - memset(&dev->read_packet->msg[header->len], 0, ETH_MIN_PACKET-header->len); - dev->read_packet->len = ETH_MIN_PACKET; - } - /* If necessary, fix IP header checksums for packets originated by the local host */ + /* If necessary, fix IP header checksums for packets originated locally */ /* but were presumed to be traversing a NIC which was going to handle that task */ /* This must be done before any needed CRC calculation */ - _eth_fix_ip_xsum_offload(dev, dev->read_packet->msg, dev->read_packet->len); + _eth_fix_ip_xsum_offload(dev, (u_char*)data, len); + if (dev->need_crc) - dev->read_packet->crc_len = eth_add_packet_crc32(dev->read_packet->msg, dev->read_packet->len); - else - dev->read_packet->crc_len = 0; + crc_len = eth_get_packet_crc32_data(data, len, crc_data); - eth_packet_trace (dev, dev->read_packet->msg, dev->read_packet->len, "reading"); + eth_packet_trace (dev, data, len, "rcvqd"); - /* call optional read callback function */ - if (dev->read_callback) - (dev->read_callback)(0); + pthread_mutex_lock (&dev->lock); + ethq_insert_data(&dev->read_queue, 2, data, 0, len, crc_len, crc_data, 0); + pthread_mutex_unlock (&dev->lock); + free(moved_data); + } +#else /* !USE_READER_THREAD */ + /* set data in passed read packet */ + dev->read_packet->len = header->len; + memcpy(dev->read_packet->msg, data, header->len); + /* Handle runt case and pad with zeros. */ + /* The real NIC won't hand us runts from the wire, BUT we may be getting */ + /* some packets looped back before they actually traverse the wire */ + /* (by an internal bridge device for instance) */ + if (header->len < ETH_MIN_PACKET) { + memset(&dev->read_packet->msg[header->len], 0, ETH_MIN_PACKET-header->len); + dev->read_packet->len = ETH_MIN_PACKET; + } + /* If necessary, fix IP header checksums for packets originated by the local host */ + /* but were presumed to be traversing a NIC which was going to handle that task */ + /* This must be done before any needed CRC calculation */ + _eth_fix_ip_xsum_offload(dev, dev->read_packet->msg, dev->read_packet->len); + if (dev->need_crc) + dev->read_packet->crc_len = eth_add_packet_crc32(dev->read_packet->msg, dev->read_packet->len); + else + dev->read_packet->crc_len = 0; + + eth_packet_trace (dev, dev->read_packet->msg, dev->read_packet->len, "reading"); + + /* call optional read callback function */ + if (dev->read_callback) + (dev->read_callback)(0); #endif } } int eth_read(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine) { - int status; +int status; - /* make sure device exists */ +/* make sure device exists */ - if (!dev) return 0; +if (!dev) return 0; - /* make sure packet exists */ - if (!packet) return 0; +/* make sure packet exists */ +if (!packet) return 0; - packet->len = 0; +packet->len = 0; #if !defined (USE_READER_THREAD) - /* set read packet */ - dev->read_packet = packet; +/* set read packet */ +dev->read_packet = packet; - /* set optional callback routine */ - dev->read_callback = routine; +/* set optional callback routine */ +dev->read_callback = routine; - /* dispatch read request to either receive a filtered packet or timeout */ - do { - if (dev->pcap_mode) +/* dispatch read request to either receive a filtered packet or timeout */ +do { + switch (dev->eth_api) { + case ETH_API_PCAP: status = pcap_dispatch((pcap_t*)dev->handle, 1, &_eth_callback, (u_char*)dev); + break; #ifdef USE_TAP_NETWORK - else { - struct pcap_pkthdr header; - int len; - u_char buf[ETH_MAX_JUMBO_FRAME]; + case ETH_API_TAP: + if (1) { + struct pcap_pkthdr header; + int len; + u_char buf[ETH_MAX_JUMBO_FRAME]; - memset(&header, 0, sizeof(header)); - len = read(dev->fd_handle, buf, sizeof(buf)); - if (len > 0) { - status = 1; - header.caplen = header.len = len; - _eth_callback((u_char *)dev, &header, buf); - } else { - status = 0; - } - } + memset(&header, 0, sizeof(header)); + len = read(dev->fd_handle, buf, sizeof(buf)); + if (len > 0) { + status = 1; + header.caplen = header.len = len; + _eth_callback((u_char *)dev, &header, buf); + } + else + status = 0; + } + break; #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)); #else /* USE_READER_THREAD */ - status = 0; - pthread_mutex_lock (&dev->lock); - if (dev->read_queue.count > 0) { - ETH_ITEM* item = &dev->read_queue.item[dev->read_queue.head]; - packet->len = item->packet.len; - packet->crc_len = item->packet.crc_len; - memcpy(packet->msg, item->packet.msg, ((packet->len > packet->crc_len) ? packet->len : packet->crc_len)); - status = 1; - ethq_remove(&dev->read_queue); - } - pthread_mutex_unlock (&dev->lock); - if ((status) && (routine)) - routine(0); + status = 0; + pthread_mutex_lock (&dev->lock); + if (dev->read_queue.count > 0) { + ETH_ITEM* item = &dev->read_queue.item[dev->read_queue.head]; + packet->len = item->packet.len; + packet->crc_len = item->packet.crc_len; + memcpy(packet->msg, item->packet.msg, ((packet->len > packet->crc_len) ? packet->len : packet->crc_len)); + status = 1; + ethq_remove(&dev->read_queue); + } + pthread_mutex_unlock (&dev->lock); + if ((status) && (routine)) + routine(0); #endif - return status; +return status; } t_stat eth_filter(ETH_DEV* dev, int addr_count, ETH_MAC* const addresses, @@ -2351,181 +2493,182 @@ t_stat eth_filter_hash(ETH_DEV* dev, int addr_count, ETH_MAC* const addresses, ETH_BOOL all_multicast, ETH_BOOL promiscuous, ETH_MULTIHASH* const hash) { - int i; - bpf_u_int32 bpf_subnet, bpf_netmask; - char buf[114+66*ETH_FILTER_MAX]; - char errbuf[PCAP_ERRBUF_SIZE]; - char mac[20]; - char* buf2; - t_stat status; +int i; +bpf_u_int32 bpf_subnet, bpf_netmask; +char buf[114+66*ETH_FILTER_MAX]; +char errbuf[PCAP_ERRBUF_SIZE]; +char mac[20]; +char* buf2; +t_stat status; #ifdef USE_BPF - struct bpf_program bpf; - char* msg; +struct bpf_program bpf; +char* msg; #endif - /* make sure device exists */ - if (!dev) return SCPE_UNATT; +/* make sure device exists */ +if (!dev) return SCPE_UNATT; - /* filter count OK? */ - if ((addr_count < 0) || (addr_count > ETH_FILTER_MAX)) - return SCPE_ARG; - else - if (!addresses) return SCPE_ARG; +/* filter count OK? */ +if ((addr_count < 0) || (addr_count > ETH_FILTER_MAX)) + return SCPE_ARG; +else + if (!addresses) return SCPE_ARG; - /* test reflections. This is done early in this routine since eth_reflect */ - /* calls eth_filter recursively and thus changes the state of the device. */ - if (dev->reflections == -1) - status = eth_reflect(dev); +/* test reflections. This is done early in this routine since eth_reflect */ +/* calls eth_filter recursively and thus changes the state of the device. */ +if (dev->reflections == -1) + status = eth_reflect(dev); - /* set new filter addresses */ - for (i = 0; i < addr_count; i++) - memcpy(dev->filter_address[i], addresses[i], sizeof(ETH_MAC)); - dev->addr_count = addr_count; +/* set new filter addresses */ +for (i = 0; i < addr_count; i++) + memcpy(dev->filter_address[i], addresses[i], sizeof(ETH_MAC)); +dev->addr_count = addr_count; - /* store other flags */ - dev->all_multicast = all_multicast; - dev->promiscuous = promiscuous; +/* store other flags */ +dev->all_multicast = all_multicast; +dev->promiscuous = promiscuous; - /* store multicast hash data */ - dev->hash_filter = (hash != NULL); - if (hash) { - memcpy(dev->hash, hash, sizeof(*hash)); - sim_debug(dev->dbit, dev->dptr, "Multicast Hash: %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n", - dev->hash[0], dev->hash[1], dev->hash[2], dev->hash[3], - dev->hash[4], dev->hash[5], dev->hash[6], dev->hash[7]); +/* store multicast hash data */ +dev->hash_filter = (hash != NULL); +if (hash) { + memcpy(dev->hash, hash, sizeof(*hash)); + sim_debug(dev->dbit, dev->dptr, "Multicast Hash: %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n", + dev->hash[0], dev->hash[1], dev->hash[2], dev->hash[3], + dev->hash[4], dev->hash[5], dev->hash[6], dev->hash[7]); } - /* print out filter information if debugging */ - if (dev->dptr->dctrl & dev->dbit) { - sim_debug(dev->dbit, dev->dptr, "Filter Set\n"); - for (i = 0; i < addr_count; i++) { - char mac[20]; - eth_mac_fmt(&dev->filter_address[i], mac); - sim_debug(dev->dbit, dev->dptr, " Addr[%d]: %s\n", i, mac); +/* print out filter information if debugging */ +if (dev->dptr->dctrl & dev->dbit) { + sim_debug(dev->dbit, dev->dptr, "Filter Set\n"); + for (i = 0; i < addr_count; i++) { + char mac[20]; + eth_mac_fmt(&dev->filter_address[i], mac); + sim_debug(dev->dbit, dev->dptr, " Addr[%d]: %s\n", i, mac); } - if (dev->all_multicast) - sim_debug(dev->dbit, dev->dptr, "All Multicast\n"); - if (dev->promiscuous) - sim_debug(dev->dbit, dev->dptr, "Promiscuous\n"); + if (dev->all_multicast) + sim_debug(dev->dbit, dev->dptr, "All Multicast\n"); + if (dev->promiscuous) + sim_debug(dev->dbit, dev->dptr, "Promiscuous\n"); } - /* setup BPF filters and other fields to minimize packet delivery */ - strcpy(buf, ""); +/* setup BPF filters and other fields to minimize packet delivery */ +strcpy(buf, ""); - /* construct destination filters - since the real ethernet interface was set - into promiscuous mode by eth_open(), we need to filter out the packets that - our simulated interface doesn't want. */ - if (!dev->promiscuous) { - for (i = 0; i < addr_count; i++) { - eth_mac_fmt(&dev->filter_address[i], mac); - if (!strstr(buf, mac)) /* eliminate duplicates */ - sprintf(&buf[strlen(buf)], "%s(ether dst %s)", (*buf) ? " or " : "((", mac); +/* construct destination filters - since the real ethernet interface was set + into promiscuous mode by eth_open(), we need to filter out the packets that + our simulated interface doesn't want. */ +if (!dev->promiscuous) { + for (i = 0; i < addr_count; i++) { + eth_mac_fmt(&dev->filter_address[i], mac); + if (!strstr(buf, mac)) /* eliminate duplicates */ + sprintf(&buf[strlen(buf)], "%s(ether dst %s)", (*buf) ? " or " : "((", mac); } - if (dev->all_multicast || dev->hash_filter) - sprintf(&buf[strlen(buf)], "%s(ether multicast)", (*buf) ? " or " : "(("); - if (strlen(buf) > 0) - sprintf(&buf[strlen(buf)], ")"); - } - - /* construct source filters - this prevents packets from being reflected back - by systems where WinPcap and libpcap cause packet reflections. Note that - some systems do not reflect packets at all. This *assumes* that the - simulated NIC will not send out packets with multicast source fields. */ - if ((addr_count > 0) && (dev->reflections > 0)) { - if (strlen(buf) > 0) - sprintf(&buf[strlen(buf)], " and "); - sprintf (&buf[strlen(buf)], "not ("); - buf2 = &buf[strlen(buf)]; - for (i = 0; i < addr_count; i++) { - if (dev->filter_address[i][0] & 0x01) continue; /* skip multicast addresses */ - eth_mac_fmt(&dev->filter_address[i], mac); - if (!strstr(buf2, mac)) /* eliminate duplicates */ - sprintf(&buf2[strlen(buf2)], "%s(ether src %s)", (*buf2) ? " or " : "", mac); - } - sprintf (&buf[strlen(buf)], ")"); - } + if (dev->all_multicast || dev->hash_filter) + sprintf(&buf[strlen(buf)], "%s(ether multicast)", (*buf) ? " or " : "(("); if (strlen(buf) > 0) sprintf(&buf[strlen(buf)], ")"); - /* When changing the Physical Address on a LAN interface, VMS sends out a - loopback packet with the source and destination addresses set to the same - value as the Physical Address which is being setup. This packet is - designed to find and help diagnose MAC address conflicts (which also - include DECnet address conflicts). Normally, this packet would not be - seen by the sender, only by the other machine that has the same Physical - Address (or possibly DECnet address). If the ethernet subsystem is - reflecting packets, the network startup will fail to start if it sees the - reflected packet, since it thinks another system is using this Physical - Address (or DECnet address). We have to let these packets through, so - that if another machine has the same Physical Address (or DECnet address) - that we can detect it. Both eth_write() and _eth_callback() help by - checking the reflection count - eth_write() adds the reflection count to - dev->loopback_self_sent, and _eth_callback() check the value - if the - dev->loopback_self_sent count is zero, then the packet has come from - another machine with the same address, and needs to be passed on to the - simulated machine. */ - memset(dev->physical_addr, 0, sizeof(ETH_MAC)); - dev->loopback_self_sent = 0; - /* check for physical address in filters */ - if ((addr_count) && (dev->reflections > 0)) { - for (i = 0; i < addr_count; i++) { - if (dev->filter_address[i][0]&1) - continue; /* skip all multicast addresses */ - eth_mac_fmt(&dev->filter_address[i], mac); - if (strcmp(mac, "00:00:00:00:00:00") != 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); - break; + } + +/* construct source filters - this prevents packets from being reflected back + by systems where WinPcap and libpcap cause packet reflections. Note that + some systems do not reflect packets at all. This *assumes* that the + simulated NIC will not send out packets with multicast source fields. */ +if ((addr_count > 0) && (dev->reflections > 0)) { + if (strlen(buf) > 0) + sprintf(&buf[strlen(buf)], " and "); + sprintf (&buf[strlen(buf)], "not ("); + buf2 = &buf[strlen(buf)]; + for (i = 0; i < addr_count; i++) { + if (dev->filter_address[i][0] & 0x01) continue; /* skip multicast addresses */ + eth_mac_fmt(&dev->filter_address[i], mac); + if (!strstr(buf2, mac)) /* eliminate duplicates */ + sprintf(&buf2[strlen(buf2)], "%s(ether src %s)", (*buf2) ? " or " : "", mac); + } + sprintf (&buf[strlen(buf)], ")"); + } +if (strlen(buf) > 0) + sprintf(&buf[strlen(buf)], ")"); +/* When changing the Physical Address on a LAN interface, VMS sends out a + loopback packet with the source and destination addresses set to the same + value as the Physical Address which is being setup. This packet is + designed to find and help diagnose MAC address conflicts (which also + include DECnet address conflicts). Normally, this packet would not be + seen by the sender, only by the other machine that has the same Physical + Address (or possibly DECnet address). If the ethernet subsystem is + reflecting packets, the network startup will fail to start if it sees the + reflected packet, since it thinks another system is using this Physical + Address (or DECnet address). We have to let these packets through, so + that if another machine has the same Physical Address (or DECnet address) + that we can detect it. Both eth_write() and _eth_callback() help by + checking the reflection count - eth_write() adds the reflection count to + dev->loopback_self_sent, and _eth_callback() check the value - if the + dev->loopback_self_sent count is zero, then the packet has come from + another machine with the same address, and needs to be passed on to the + simulated machine. */ +memset(dev->physical_addr, 0, sizeof(ETH_MAC)); +dev->loopback_self_sent = 0; +/* check for physical address in filters */ +if ((addr_count) && (dev->reflections > 0)) { + for (i = 0; i < addr_count; i++) { + if (dev->filter_address[i][0]&1) + continue; /* skip all multicast addresses */ + eth_mac_fmt(&dev->filter_address[i], mac); + if (strcmp(mac, "00:00:00:00:00:00") != 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); + break; } } } - if ((0 == strlen(buf)) && (!dev->promiscuous)) /* Empty filter means match nothing */ - 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); +if ((0 == strlen(buf)) && (!dev->promiscuous)) /* Empty filter means match nothing */ + 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->pcap_mode && (pcap_lookupnet(dev->handle, &bpf_subnet, &bpf_netmask, errbuf)<0)) { - bpf_netmask = 0; - } +/* get netmask, which is required for compiling */ +if ((dev->eth_api == ETH_API_PCAP) && (pcap_lookupnet(dev->handle, &bpf_subnet, &bpf_netmask, errbuf)<0)) + bpf_netmask = 0; #ifdef USE_BPF - if (dev->pcap_mode) { - /* compile filter string */ - if ((status = pcap_compile(dev->handle, &bpf, buf, 1, bpf_netmask)) < 0) { +if (dev->eth_api == ETH_API_PCAP) { + /* compile filter string */ + if ((status = pcap_compile(dev->handle, &bpf, buf, 1, bpf_netmask)) < 0) { + sprintf(errbuf, "%s", pcap_geterr(dev->handle)); + msg = "Eth: pcap_compile error: %s\r\n"; + printf(msg, errbuf); + if (sim_log) fprintf (sim_log, msg, errbuf); + sim_debug(dev->dbit, dev->dptr, "Eth: pcap_compile error: %s\n", errbuf); + /* show erroneous BPF string */ + msg = "Eth: BPF string is: |%s|\r\n"; + printf (msg, buf); + if (sim_log) fprintf (sim_log, msg, buf); + } + else { + /* apply compiled filter string */ + if ((status = pcap_setfilter(dev->handle, &bpf)) < 0) { sprintf(errbuf, "%s", pcap_geterr(dev->handle)); - msg = "Eth: pcap_compile error: %s\r\n"; + msg = "Eth: pcap_setfilter error: %s\r\n"; printf(msg, errbuf); if (sim_log) fprintf (sim_log, msg, errbuf); - sim_debug(dev->dbit, dev->dptr, "Eth: pcap_compile error: %s\n", errbuf); - /* show erroneous BPF string */ - msg = "Eth: BPF string is: |%s|\r\n"; - printf (msg, buf); - if (sim_log) fprintf (sim_log, msg, buf); - } else { - /* apply compiled filter string */ - if ((status = pcap_setfilter(dev->handle, &bpf)) < 0) { - sprintf(errbuf, "%s", pcap_geterr(dev->handle)); - msg = "Eth: pcap_setfilter error: %s\r\n"; - printf(msg, errbuf); - if (sim_log) fprintf (sim_log, msg, errbuf); - sim_debug(dev->dbit, dev->dptr, "Eth: pcap_setfilter error: %s\n", errbuf); - } else { + sim_debug(dev->dbit, dev->dptr, "Eth: pcap_setfilter error: %s\n", errbuf); + } + else { #ifdef USE_SETNONBLOCK - /* set file non-blocking */ - status = pcap_setnonblock (dev->handle, 1, errbuf); + /* set file non-blocking */ + status = pcap_setnonblock (dev->handle, 1, errbuf); #endif /* USE_SETNONBLOCK */ } - pcap_freecode(&bpf); + pcap_freecode(&bpf); } #ifdef USE_READER_THREAD - pthread_mutex_lock (&dev->lock); - ethq_clear (&dev->read_queue); /* Empty FIFO Queue when filter list changes */ - pthread_mutex_unlock (&dev->lock); + pthread_mutex_lock (&dev->lock); + ethq_clear (&dev->read_queue); /* Empty FIFO Queue when filter list changes */ + pthread_mutex_unlock (&dev->lock); #endif } #endif /* USE_BPF */ - return SCPE_OK; +return SCPE_OK; } /* @@ -2549,149 +2692,157 @@ t_stat eth_filter_hash(ETH_DEV* dev, int addr_count, ETH_MAC* const addresses, */ int eth_host_devices(int used, int max, ETH_LIST* list) { - pcap_t* conn; - int i, j, datalink; - char errbuf[PCAP_ERRBUF_SIZE]; +pcap_t* conn; +int i, j, datalink; +char errbuf[PCAP_ERRBUF_SIZE]; - for (i=0; i sizeof(regval))) { - RegCloseKey (reghnd); - continue; + /* make sure value is the right type, bail if not acceptable */ + if ((regtype != REG_SZ) || (reglen > sizeof(regval))) { + RegCloseKey (reghnd); + continue; } - /* registry value seems OK, finish up and replace description */ - RegCloseKey (reghnd ); - sprintf (list[i].desc, "%s", regval); + /* registry value seems OK, finish up and replace description */ + RegCloseKey (reghnd ); + sprintf (list[i].desc, "%s", regval); } } /* for */ #endif #ifdef USE_TAP_NETWORK - if (used < max) { - list[used].num = used; +if (used < max) { + list[used].num = used; #if defined(__OpenBSD__) - sprintf(list[used].name, "%s", "tap:tunN"); + sprintf(list[used].name, "%s", "tap:tunN"); #else - sprintf(list[used].name, "%s", "tap:tapN"); + sprintf(list[used].name, "%s", "tap:tapN"); #endif - sprintf(list[used].desc, "%s", "Integrated Tun/Tap support"); - ++used; + sprintf(list[used].desc, "%s", "Integrated Tun/Tap support"); + ++used; + } +#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; } int eth_devices(int max, ETH_LIST* list) { - int i = 0; +int i = 0; #ifndef DONT_USE_PCAP_FINDALLDEVS - pcap_if_t* alldevs; - pcap_if_t* dev; - char errbuf[PCAP_ERRBUF_SIZE]; +pcap_if_t* alldevs; +pcap_if_t* dev; +char errbuf[PCAP_ERRBUF_SIZE]; - /* retrieve the device list */ - if (pcap_findalldevs(&alldevs, errbuf) == -1) { - char* msg = "Eth: error in pcap_findalldevs: %s\r\n"; - printf (msg, errbuf); - if (sim_log) fprintf (sim_log, msg, errbuf); - } else { - /* copy device list into the passed structure */ - for (i=0, dev=alldevs; dev; dev=dev->next) { - if ((dev->flags & PCAP_IF_LOOPBACK) || (!strcmp("any", dev->name))) continue; - list[i].num = i; - sprintf(list[i].name, "%s", dev->name); - if (dev->description) - sprintf(list[i].desc, "%s", dev->description); - else - sprintf(list[i].desc, "%s", "No description available"); - if (i++ >= max) break; +/* retrieve the device list */ +if (pcap_findalldevs(&alldevs, errbuf) == -1) { + char* msg = "Eth: error in pcap_findalldevs: %s\r\n"; + printf (msg, errbuf); + if (sim_log) fprintf (sim_log, msg, errbuf); + } +else { + /* copy device list into the passed structure */ + for (i=0, dev=alldevs; dev; dev=dev->next) { + if ((dev->flags & PCAP_IF_LOOPBACK) || (!strcmp("any", dev->name))) continue; + list[i].num = i; + sprintf(list[i].name, "%s", dev->name); + if (dev->description) + sprintf(list[i].desc, "%s", dev->description); + else + sprintf(list[i].desc, "%s", "No description available"); + if (i++ >= max) break; } - /* free device list */ - pcap_freealldevs(alldevs); + /* free device list */ + pcap_freealldevs(alldevs); } #endif - /* Add any host specific devices and/or validate those already found */ - i = eth_host_devices(i, max, list); +/* Add any host specific devices and/or validate those already found */ +i = eth_host_devices(i, max, list); - /* return device count */ - return i; +/* return device count */ +return i; } void eth_show_dev (FILE *st, ETH_DEV* dev) { - fprintf(st, "Ethernet Device:\n"); - if (!dev) { - fprintf(st, "-- Not Attached\n"); - return; +fprintf(st, "Ethernet Device:\n"); +if (!dev) { + fprintf(st, "-- Not Attached\n"); + return; } - fprintf(st, " Name: %s\n", dev->name); - fprintf(st, " Reflections: %d\n", dev->reflections); - fprintf(st, " Self Loopbacks Sent: %d\n", dev->loopback_self_sent_total); - fprintf(st, " Self Loopbacks Rcvd: %d\n", dev->loopback_self_rcvd_total); - if (dev->have_host_nic_phy_addr) { - char hw_mac[20]; +fprintf(st, " Name: %s\n", dev->name); +fprintf(st, " Reflections: %d\n", dev->reflections); +fprintf(st, " Self Loopbacks Sent: %d\n", dev->loopback_self_sent_total); +fprintf(st, " Self Loopbacks Rcvd: %d\n", dev->loopback_self_rcvd_total); +if (dev->have_host_nic_phy_addr) { + char hw_mac[20]; - eth_mac_fmt(&dev->host_nic_phy_hw_addr, hw_mac); - fprintf(st, " Host NIC Address: %s\n", hw_mac); + eth_mac_fmt(&dev->host_nic_phy_hw_addr, hw_mac); + fprintf(st, " Host NIC Address: %s\n", hw_mac); } - if (dev->jumbo_dropped) - fprintf(st, " Jumbo Dropped: %d\n", dev->jumbo_dropped); - if (dev->jumbo_fragmented) - fprintf(st, " Jumbo Fragmented: %d\n", dev->jumbo_fragmented); - if (dev->jumbo_truncated) - fprintf(st, " Jumbo Truncated: %d\n", dev->jumbo_truncated); +if (dev->jumbo_dropped) + fprintf(st, " Jumbo Dropped: %d\n", dev->jumbo_dropped); +if (dev->jumbo_fragmented) + fprintf(st, " Jumbo Fragmented: %d\n", dev->jumbo_fragmented); +if (dev->jumbo_truncated) + fprintf(st, " Jumbo Truncated: %d\n", dev->jumbo_truncated); #if defined(USE_READER_THREAD) - fprintf(st, " Asynch Interrupts: %s\n", dev->asynch_io?"Enabled":"Disabled"); - if (dev->asynch_io) - fprintf(st, " Interrupt Latency: %d uSec\n", dev->asynch_io_latency); - fprintf(st, " Read Queue: Count: %d\n", dev->read_queue.count); - fprintf(st, " Read Queue: High: %d\n", dev->read_queue.high); - fprintf(st, " Read Queue: Loss: %d\n", dev->read_queue.loss); - fprintf(st, " Peak Write Queue Size: %d\n", dev->write_queue_peak); +fprintf(st, " Asynch Interrupts: %s\n", dev->asynch_io?"Enabled":"Disabled"); +if (dev->asynch_io) + fprintf(st, " Interrupt Latency: %d uSec\n", dev->asynch_io_latency); +fprintf(st, " Read Queue: Count: %d\n", dev->read_queue.count); +fprintf(st, " Read Queue: High: %d\n", dev->read_queue.high); +fprintf(st, " Read Queue: Loss: %d\n", dev->read_queue.loss); +fprintf(st, " Peak Write Queue Size: %d\n", dev->write_queue_peak); #endif } #endif /* USE_NETWORK */ diff --git a/sim_ether.h b/sim_ether.h index de155548..1478c40c 100644 --- a/sim_ether.h +++ b/sim_ether.h @@ -28,6 +28,7 @@ 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 multithreaded environments 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_SETNONBLOCK) #undef USE_SETNONBLOCK -#endif +#endif /* USE_SETNONBLOCK */ #undef PCAP_READ_TIMEOUT #define PCAP_READ_TIMEOUT 15 -#if !defined (xBSD) && !defined(_WIN32) && !defined(VMS) -#define MUST_DO_SELECT -#endif +#if (!defined (xBSD) && !defined(_WIN32) && !defined(VMS)) || defined (USE_TAP_NETWORK) || defined (USE_VDE_NETWORK) +#define MUST_DO_SELECT 1 #endif +#endif /* USE_READER_THREAD */ /* 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 */ void* handle; /* handle of implementation-specific device */ 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 write_callback; /* write callback function */ ETH_PACK* read_packet; /* read packet */ From cbc14bc01012d8aa24a0b7519b91a68aa609fa9f Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 2 Nov 2011 05:45:01 -0700 Subject: [PATCH 24/30] Fix memory leak on error path and proper polling vs async conditions --- PDP11/pdp11_xq.c | 5 +++-- PDP11/pdp11_xq.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/PDP11/pdp11_xq.c b/PDP11/pdp11_xq.c index ec5e2a0e..c4eb46e7 100644 --- a/PDP11/pdp11_xq.c +++ b/PDP11/pdp11_xq.c @@ -450,10 +450,10 @@ MTAB xq_mod[] = { { MTAB_XTD | MTAB_VDV, 0, "TYPE", "TYPE={DEQNA|DELQA|DELQA-T}", &xq_set_type, &xq_show_type, NULL }, #ifdef USE_READER_THREAD - { MTAB_XTD | MTAB_VDV, 0, "POLL", "POLL={DEFAULT|DISABLED|4..2500|DELAY=nnn}", + { MTAB_XTD | MTAB_VDV, 0, "POLL", "POLL={DEFAULT|DISABLED|4..2500|DELAY=nnn}", &xq_set_poll, &xq_show_poll, NULL }, #else - { MTAB_XTD | MTAB_VDV, 0, "POLL", "POLL={DEFAULT|DISABLED|4..2500}", + { MTAB_XTD | MTAB_VDV, 0, "POLL", "POLL={DEFAULT|DISABLED|4..2500}", &xq_set_poll, &xq_show_poll, NULL }, #endif { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "SANITY", "SANITY={ON|OFF}", @@ -2584,6 +2584,7 @@ t_stat xq_attach(UNIT* uptr, char* cptr) if (xq->var->poll == 0) { status = eth_set_async(xq->var->etherface, xq->var->coalesce_latency_ticks); if (status != SCPE_OK) { + eth_close(xq->var->etherface); free(tptr); free(xq->var->etherface); xq->var->etherface = NULL; diff --git a/PDP11/pdp11_xq.h b/PDP11/pdp11_xq.h index 5f786975..b71a725e 100644 --- a/PDP11/pdp11_xq.h +++ b/PDP11/pdp11_xq.h @@ -87,7 +87,7 @@ extern int32 int_req[IPL_HLVL]; #define XQ_QUE_MAX 500 /* read queue size in packets */ #define XQ_FILTER_MAX 14 /* number of filters allowed */ -#if defined SIM_ASYNCH_IO +#if defined(SIM_ASYNCH_IO) && defined(USE_READER_THREAD) #define XQ_SERVICE_INTERVAL 0 /* polling interval - No Polling with Asynch I/O */ #else #define XQ_SERVICE_INTERVAL 100 /* polling interval - X per second */ From 02c5302039b5e0d5e40deccc6a45790142c1b3e3 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 2 Nov 2011 08:32:24 -0700 Subject: [PATCH 25/30] cleaned up Solaris build issues --- makefile | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/makefile b/makefile index c4be5123..ebe7379a 100644 --- a/makefile +++ b/makefile @@ -25,7 +25,11 @@ ifeq ($(WIN32),) ifeq (Linux,$(shell uname)) LIBEXT = so else - LIBEXT = a + ifeq (SunOS,$(shell uname)) + LIBEXT = so + else + LIBEXT = a + endif endif endif OS_CCDEFS = -D_GNU_SOURCE @@ -33,7 +37,7 @@ ifeq ($(WIN32),) OS_LDFLAGS += -lm endif ifeq (SunOS,$(shell uname)) - OS_CCDEFS += -I/opt/sfw/include + OS_CCDEFS += -I/opt/sfw/include -DSIM_ASYNCH_IO -DUSE_READER_THREAD OS_LDFLAGS += -lsocket -lnsl -lrt -lm -lpthread -L/opt/sfw/lib -R/opt/sfw/lib endif ifeq (cygwin,$(findstring cygwin,$(OSTYPE))) @@ -47,14 +51,21 @@ ifeq ($(WIN32),) OS_LDFLAGS += -lpthread endif ifeq (readline,$(shell if $(TEST) -e /usr/lib/libreadline.$(LIBEXT) -o -e /usr/lib64/libreadline.$(LIBEXT) -o -e /opt/sfw/lib/libreadline.a; then echo readline; fi)) - ifeq (readline_h,$(shell if $(TEST) -e /usr/include/readline/readline.h -o -e /usr/include/readline.h; then echo readline_h; fi)) + ifeq (readline_h,$(shell if $(TEST) -e /usr/include/readline/readline.h -o -e /usr/include/readline.h -o -e /opt/sfw/include/readline/readline.h; then echo readline_h; fi)) # Use Locally installed and available readline support ifeq (ncurses,$(shell if $(TEST) -e /usr/lib/libncurses.$(LIBEXT) -o -e /opt/sfw/lib/libncurses.a; then echo ncurses; fi)) OS_CCDEFS += -DHAVE_READLINE OS_LDFLAGS += -lreadline -lncurses else - OS_CCDEFS += -DHAVE_READLINE - OS_LDFLAGS += -lreadline + ifeq (curses,$(shell if $(TEST) -e /usr/lib/libcurses.$(LIBEXT); then echo curses; fi)) + OS_CCDEFS += -DHAVE_READLINE + OS_LDFLAGS += -lreadline -lcurses + else + ifeq (solaris_readline,$(shell if $(TEST) ! -e /opt/sfw/lib/libreadline.a; then echo solaris_readline; fi)) + OS_CCDEFS += -DHAVE_READLINE + OS_LDFLAGS += -lreadline + endif + endif endif endif endif From 158a02df5a29c55f890c3befa56fce421f6d6ac4 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 2 Nov 2011 08:45:21 -0700 Subject: [PATCH 26/30] Removed unused utility routine which doesn't compile on some platforms --- VAX/vax780_stddev.c | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/VAX/vax780_stddev.c b/VAX/vax780_stddev.c index a7116942..2288b481 100644 --- a/VAX/vax780_stddev.c +++ b/VAX/vax780_stddev.c @@ -733,32 +733,6 @@ todr_resync (); /* resync TODR */ return SCPE_OK; } - -int -timeval_subtract (result, x, y) - struct timeval *result, *x, *y; -{ -/* Perform the carry for the later subtraction by updating y. */ -if (x->tv_usec < y->tv_usec) { - int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; - y->tv_usec -= 1000000 * nsec; - y->tv_sec += nsec; -} -if (x->tv_usec - y->tv_usec > 1000000) { - int nsec = (x->tv_usec - y->tv_usec) / 1000000; - y->tv_usec += 1000000 * nsec; - y->tv_sec -= nsec; -} - -/* Compute the time remaining to wait. - tv_usec is certainly positive. */ -result->tv_sec = x->tv_sec - y->tv_sec; -result->tv_usec = x->tv_usec - y->tv_usec; - -/* Return 1 if result is negative. */ -return x->tv_sec < y->tv_sec; -} - /* TODR routines */ int32 todr_rd (void) From d733bc3eb9e64777ca8bbc67901191e82336fefe Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 2 Nov 2011 13:38:06 -0700 Subject: [PATCH 27/30] Fixed Interrupt Priority Level of DELQA and DELQA-T devices to be BR4 devices. Reported by Sergey Oboguev --- 0readme_ethernet.txt | 2 ++ PDP11/pdp11_defs.h | 9 ++++++--- PDP11/pdp11_xq.c | 27 ++++++++++++++++++++------- VAX/vaxmod_defs.h | 10 +++++++--- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/0readme_ethernet.txt b/0readme_ethernet.txt index eb1c66f0..6775ec06 100644 --- a/0readme_ethernet.txt +++ b/0readme_ethernet.txt @@ -378,6 +378,8 @@ Dave Change Log =============================================================================== + 02-Nov-11 MP Fixed Interrupt Priority Level of DELQA and DELQA-T devices to + be BR4 devices. Reported by Sergey Oboguev 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 17-Aug-11 RMS Fix from Sergey Oboguev relating to XU and XQ Auto Config and diff --git a/PDP11/pdp11_defs.h b/PDP11/pdp11_defs.h index 269c1cd3..3c25b105 100644 --- a/PDP11/pdp11_defs.h +++ b/PDP11/pdp11_defs.h @@ -652,7 +652,7 @@ typedef struct pdp_dib DIB; #define INT_V_DZTX 9 #define INT_V_TQ 10 #define INT_V_RY 11 -#define INT_V_XQ 12 +#define INT_V_XQDEQNA 12 #define INT_V_XU 13 #define INT_V_TU 14 #define INT_V_RF 15 @@ -672,6 +672,7 @@ typedef struct pdp_dib DIB; #define INT_V_DCI 10 #define INT_V_DCO 11 #define INT_V_PIR4 12 +#define INT_V_XQDELQA 13 #define INT_V_PIR3 0 /* BR3 */ #define INT_V_PIR2 0 /* BR2 */ @@ -695,7 +696,8 @@ typedef struct pdp_dib DIB; #define INT_DZTX (1u << INT_V_DZTX) #define INT_TQ (1u << INT_V_TQ) #define INT_RY (1u << INT_V_RY) -#define INT_XQ (1u << INT_V_XQ) +#define INT_XQDEQNA (1u << INT_V_XQDEQNA) +#define INT_XQDELQA (1u << INT_V_XQDELQA) #define INT_XU (1u << INT_V_XU) #define INT_TU (1u << INT_V_TU) #define INT_RF (1u << INT_V_RF) @@ -734,7 +736,8 @@ typedef struct pdp_dib DIB; #define IPL_DZTX 5 #define IPL_TQ 5 #define IPL_RY 5 -#define IPL_XQ 5 +#define IPL_XQDEQNA 5 +#define IPL_XQDELQA 4 #define IPL_XU 5 #define IPL_TU 5 #define IPL_RF 5 diff --git a/PDP11/pdp11_xq.c b/PDP11/pdp11_xq.c index c4eb46e7..d58fe660 100644 --- a/PDP11/pdp11_xq.c +++ b/PDP11/pdp11_xq.c @@ -323,7 +323,7 @@ struct xq_device xqb = { /* SIMH device structures */ DIB xqa_dib = { IOBA_XQ, IOLN_XQ, &xq_rd, &xq_wr, - 1, IVCL (XQ), 0, { &xq_int } }; + 1, IVCL (XQDELQA), 0, { &xq_int } }; UNIT xqa_unit[] = { { UDATA (&xq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 2047) }, /* receive timer */ @@ -347,6 +347,7 @@ REG xqa_reg[] = { { GRDATA ( CSR, xqa.csr, XQ_RDX, 16, 0), REG_FIT }, { FLDATA ( INT, xqa.irq, 0) }, { GRDATA ( TYPE, xqa.type, XQ_RDX, 32, 0), REG_FIT }, + { GRDATA ( VLOC, xqa_dib.vloc, XQ_RDX, 32, 0), REG_FIT }, { GRDATA ( MODE, xqa.mode, XQ_RDX, 32, 0), REG_FIT }, { GRDATA ( POLL, xqa.poll, XQ_RDX, 16, 0), REG_HRO}, { GRDATA ( CLAT, xqa.coalesce_latency, XQ_RDX, 16, 0), REG_HRO}, @@ -379,7 +380,7 @@ REG xqa_reg[] = { }; DIB xqb_dib = { IOBA_XQB, IOLN_XQB, &xq_rd, &xq_wr, - 1, IVCL (XQ), 0, { &xq_int } }; + 1, IVCL (XQDELQA), 0, { &xq_int } }; UNIT xqb_unit[] = { { UDATA (&xq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 2047) }, /* receive timer */ @@ -403,6 +404,7 @@ REG xqb_reg[] = { { GRDATA ( CSR, xqb.csr, XQ_RDX, 16, 0), REG_FIT }, { FLDATA ( INT, xqb.irq, 0) }, { GRDATA ( TYPE, xqb.type, XQ_RDX, 32, 0), REG_FIT }, + { GRDATA ( VLOC, xqb_dib.vloc, XQ_RDX, 32, 0), REG_FIT }, { GRDATA ( MODE, xqb.mode, XQ_RDX, 32, 0), REG_FIT }, { GRDATA ( POLL, xqb.poll, XQ_RDX, 16, 0), REG_HRO}, { GRDATA ( CLAT, xqb.coalesce_latency, XQ_RDX, 16, 0), REG_HRO}, @@ -744,8 +746,11 @@ t_stat xq_set_type (UNIT* uptr, int32 val, char* cptr, void* desc) else if (!strcmp(cptr, "DELQA-T")) xq->var->type = XQ_T_DELQA_PLUS; else return SCPE_ARG; xq->var->mode = XQ_T_DELQA; - if (xq->var->type == XQ_T_DEQNA) + xq->dib->vloc = IVCL (XQDELQA); + if (xq->var->type == XQ_T_DEQNA) { xq->var->mode = XQ_T_DEQNA; + xq->dib->vloc = IVCL (XQDEQNA); + } return SCPE_OK; } @@ -2674,7 +2679,10 @@ void xq_setint(CTLR* xq) sim_debug(DBG_TRC, xq->dev, "xq_setint() - Generate Interrupt\n"); xq->var->irq = 1; - SET_INT(XQ); + if (xq->var->type == XQ_T_DEQNA) + SET_INT(XQDEQNA); + else + SET_INT(XQDELQA); return; } @@ -2683,12 +2691,17 @@ void xq_clrint(CTLR* xq) int i; xq->var->irq = 0; /* set controller irq off */ /* clear master interrupt? */ + if (xq->var->type == XQ_T_DEQNA) + CLR_INT(XQDEQNA); /* clear DEQNA master interrupt */ + else + CLR_INT(XQDELQA); /* clear DELQA master interrupt */ for (i=0; iirq) { /* if any irqs enabled */ - SET_INT(XQ); /* set master interrupt on */ - return; + if (xq->var->type == XQ_T_DEQNA) + SET_INT(XQDEQNA); /* set DEQNA master interrupt on */ + else + SET_INT(XQDELQA); /* set DELQA master interrupt on */ } - CLR_INT(XQ); /* clear master interrupt */ return; } diff --git a/VAX/vaxmod_defs.h b/VAX/vaxmod_defs.h index c8584397..5b6306b3 100644 --- a/VAX/vaxmod_defs.h +++ b/VAX/vaxmod_defs.h @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 02-Nov-11 MP Added separate IPL for DELQA/DELQA-T vs DEQNA 29-Apr-07 RMS Separated checks for PxBR and SBR 17-May-06 RMS Added CR11/CD11 support 10-May-06 RMS Added NOP'd reserved operand checking macros @@ -336,7 +337,7 @@ typedef struct { #define INT_V_RP 4 /* RP,RM drives */ #define INT_V_TS 5 /* TS11/TSV05 */ #define INT_V_TQ 6 /* TMSCP */ -#define INT_V_XQ 7 /* DEQNA/DELQA */ +#define INT_V_XQDEQNA 7 /* DEQNA */ #define INT_V_RY 8 /* RXV21 */ /* IPL 14 */ @@ -354,6 +355,7 @@ typedef struct { #define INT_V_VHTX 10 #define INT_V_QDSS 11 /* QDSS */ #define INT_V_CR 12 +#define INT_V_XQDELQA 13 /* DELQA */ #define INT_CLK (1u << INT_V_CLK) #define INT_RQ (1u << INT_V_RQ) @@ -363,7 +365,8 @@ typedef struct { #define INT_RP (1u << INT_V_RP) #define INT_TS (1u << INT_V_TS) #define INT_TQ (1u << INT_V_TQ) -#define INT_XQ (1u << INT_V_XQ) +#define INT_XQDEQNA (1u << INT_V_XQDEQNA) +#define INT_XQDELQA (1u << INT_V_XQDELQA) #define INT_RY (1u << INT_V_RY) #define INT_TTI (1u << INT_V_TTI) #define INT_TTO (1u << INT_V_TTO) @@ -387,7 +390,8 @@ typedef struct { #define IPL_RP (0x15 - IPL_HMIN) #define IPL_TS (0x15 - IPL_HMIN) #define IPL_TQ (0x15 - IPL_HMIN) -#define IPL_XQ (0x15 - IPL_HMIN) +#define IPL_XQDEQNA (0x15 - IPL_HMIN) +#define IPL_XQDELQA (0x14 - IPL_HMIN) #define IPL_RY (0x15 - IPL_HMIN) #define IPL_TTI (0x14 - IPL_HMIN) #define IPL_TTO (0x14 - IPL_HMIN) From 1d490907ad1ecfd89c8beec2921be5840a86ad65 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 2 Nov 2011 14:54:00 -0700 Subject: [PATCH 28/30] Fix for OSX clean compile --- sim_timer.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sim_timer.h b/sim_timer.h index ace58461..56896f92 100644 --- a/sim_timer.h +++ b/sim_timer.h @@ -33,6 +33,10 @@ #include +#if defined (__APPLE__) +#define HAVE_STRUCT_TIMESPEC 1 /* OSX defined the structure but doesn't tell us */ +#endif + #ifndef CLOCK_REALTIME #define CLOCK_REALTIME 1 #define NEED_CLOCK_GETTIME 1 From 8e606f0af771d5c0b048f795c6951cf5d8ae436a Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 2 Nov 2011 16:10:10 -0700 Subject: [PATCH 29/30] Fix compiler warning due to extra arguments passed to printf --- PDP11/pdp11_tu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PDP11/pdp11_tu.c b/PDP11/pdp11_tu.c index bec28535..f4b2144f 100644 --- a/PDP11/pdp11_tu.c +++ b/PDP11/pdp11_tu.c @@ -469,7 +469,7 @@ den = GET_DEN (tutc); /* get density */ uptr = tu_dev.units + drv; /* get unit */ if (DEBUG_PRS (tu_dev)) { fprintf (sim_deb, ">>TU%d STRT: fnc=%s, fc=%06o, fs=%06o, er=%06o, pos=", - drv, tu_fname[fnc], tufc, tufs, tuer, uptr->pos); + drv, tu_fname[fnc], tufc, tufs, tuer); fprint_val (sim_deb, uptr->pos, 10, T_ADDR_W, PV_LEFT); fprintf (sim_deb, "\n"); } From f9521eaf01a158676c4b564a301245d8d4599718 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 7 Nov 2011 14:31:58 -0800 Subject: [PATCH 30/30] Reverting Interrupt Priority Level change for DEQNA/DELQA. There is a general issue with all Qbus devices which is not specific to the DEQNA/DELQA. Fix coming later from Bob Supnik --- 0readme_ethernet.txt | 2 -- PDP11/pdp11_defs.h | 9 +++------ PDP11/pdp11_xq.c | 27 +++++++-------------------- VAX/vaxmod_defs.h | 10 +++------- 4 files changed, 13 insertions(+), 35 deletions(-) diff --git a/0readme_ethernet.txt b/0readme_ethernet.txt index 6775ec06..eb1c66f0 100644 --- a/0readme_ethernet.txt +++ b/0readme_ethernet.txt @@ -378,8 +378,6 @@ Dave Change Log =============================================================================== - 02-Nov-11 MP Fixed Interrupt Priority Level of DELQA and DELQA-T devices to - be BR4 devices. Reported by Sergey Oboguev 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 17-Aug-11 RMS Fix from Sergey Oboguev relating to XU and XQ Auto Config and diff --git a/PDP11/pdp11_defs.h b/PDP11/pdp11_defs.h index 3c25b105..269c1cd3 100644 --- a/PDP11/pdp11_defs.h +++ b/PDP11/pdp11_defs.h @@ -652,7 +652,7 @@ typedef struct pdp_dib DIB; #define INT_V_DZTX 9 #define INT_V_TQ 10 #define INT_V_RY 11 -#define INT_V_XQDEQNA 12 +#define INT_V_XQ 12 #define INT_V_XU 13 #define INT_V_TU 14 #define INT_V_RF 15 @@ -672,7 +672,6 @@ typedef struct pdp_dib DIB; #define INT_V_DCI 10 #define INT_V_DCO 11 #define INT_V_PIR4 12 -#define INT_V_XQDELQA 13 #define INT_V_PIR3 0 /* BR3 */ #define INT_V_PIR2 0 /* BR2 */ @@ -696,8 +695,7 @@ typedef struct pdp_dib DIB; #define INT_DZTX (1u << INT_V_DZTX) #define INT_TQ (1u << INT_V_TQ) #define INT_RY (1u << INT_V_RY) -#define INT_XQDEQNA (1u << INT_V_XQDEQNA) -#define INT_XQDELQA (1u << INT_V_XQDELQA) +#define INT_XQ (1u << INT_V_XQ) #define INT_XU (1u << INT_V_XU) #define INT_TU (1u << INT_V_TU) #define INT_RF (1u << INT_V_RF) @@ -736,8 +734,7 @@ typedef struct pdp_dib DIB; #define IPL_DZTX 5 #define IPL_TQ 5 #define IPL_RY 5 -#define IPL_XQDEQNA 5 -#define IPL_XQDELQA 4 +#define IPL_XQ 5 #define IPL_XU 5 #define IPL_TU 5 #define IPL_RF 5 diff --git a/PDP11/pdp11_xq.c b/PDP11/pdp11_xq.c index d58fe660..c4eb46e7 100644 --- a/PDP11/pdp11_xq.c +++ b/PDP11/pdp11_xq.c @@ -323,7 +323,7 @@ struct xq_device xqb = { /* SIMH device structures */ DIB xqa_dib = { IOBA_XQ, IOLN_XQ, &xq_rd, &xq_wr, - 1, IVCL (XQDELQA), 0, { &xq_int } }; + 1, IVCL (XQ), 0, { &xq_int } }; UNIT xqa_unit[] = { { UDATA (&xq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 2047) }, /* receive timer */ @@ -347,7 +347,6 @@ REG xqa_reg[] = { { GRDATA ( CSR, xqa.csr, XQ_RDX, 16, 0), REG_FIT }, { FLDATA ( INT, xqa.irq, 0) }, { GRDATA ( TYPE, xqa.type, XQ_RDX, 32, 0), REG_FIT }, - { GRDATA ( VLOC, xqa_dib.vloc, XQ_RDX, 32, 0), REG_FIT }, { GRDATA ( MODE, xqa.mode, XQ_RDX, 32, 0), REG_FIT }, { GRDATA ( POLL, xqa.poll, XQ_RDX, 16, 0), REG_HRO}, { GRDATA ( CLAT, xqa.coalesce_latency, XQ_RDX, 16, 0), REG_HRO}, @@ -380,7 +379,7 @@ REG xqa_reg[] = { }; DIB xqb_dib = { IOBA_XQB, IOLN_XQB, &xq_rd, &xq_wr, - 1, IVCL (XQDELQA), 0, { &xq_int } }; + 1, IVCL (XQ), 0, { &xq_int } }; UNIT xqb_unit[] = { { UDATA (&xq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 2047) }, /* receive timer */ @@ -404,7 +403,6 @@ REG xqb_reg[] = { { GRDATA ( CSR, xqb.csr, XQ_RDX, 16, 0), REG_FIT }, { FLDATA ( INT, xqb.irq, 0) }, { GRDATA ( TYPE, xqb.type, XQ_RDX, 32, 0), REG_FIT }, - { GRDATA ( VLOC, xqb_dib.vloc, XQ_RDX, 32, 0), REG_FIT }, { GRDATA ( MODE, xqb.mode, XQ_RDX, 32, 0), REG_FIT }, { GRDATA ( POLL, xqb.poll, XQ_RDX, 16, 0), REG_HRO}, { GRDATA ( CLAT, xqb.coalesce_latency, XQ_RDX, 16, 0), REG_HRO}, @@ -746,11 +744,8 @@ t_stat xq_set_type (UNIT* uptr, int32 val, char* cptr, void* desc) else if (!strcmp(cptr, "DELQA-T")) xq->var->type = XQ_T_DELQA_PLUS; else return SCPE_ARG; xq->var->mode = XQ_T_DELQA; - xq->dib->vloc = IVCL (XQDELQA); - if (xq->var->type == XQ_T_DEQNA) { + if (xq->var->type == XQ_T_DEQNA) xq->var->mode = XQ_T_DEQNA; - xq->dib->vloc = IVCL (XQDEQNA); - } return SCPE_OK; } @@ -2679,10 +2674,7 @@ void xq_setint(CTLR* xq) sim_debug(DBG_TRC, xq->dev, "xq_setint() - Generate Interrupt\n"); xq->var->irq = 1; - if (xq->var->type == XQ_T_DEQNA) - SET_INT(XQDEQNA); - else - SET_INT(XQDELQA); + SET_INT(XQ); return; } @@ -2691,17 +2683,12 @@ void xq_clrint(CTLR* xq) int i; xq->var->irq = 0; /* set controller irq off */ /* clear master interrupt? */ - if (xq->var->type == XQ_T_DEQNA) - CLR_INT(XQDEQNA); /* clear DEQNA master interrupt */ - else - CLR_INT(XQDELQA); /* clear DELQA master interrupt */ for (i=0; iirq) { /* if any irqs enabled */ - if (xq->var->type == XQ_T_DEQNA) - SET_INT(XQDEQNA); /* set DEQNA master interrupt on */ - else - SET_INT(XQDELQA); /* set DELQA master interrupt on */ + SET_INT(XQ); /* set master interrupt on */ + return; } + CLR_INT(XQ); /* clear master interrupt */ return; } diff --git a/VAX/vaxmod_defs.h b/VAX/vaxmod_defs.h index 5b6306b3..c8584397 100644 --- a/VAX/vaxmod_defs.h +++ b/VAX/vaxmod_defs.h @@ -23,7 +23,6 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - 02-Nov-11 MP Added separate IPL for DELQA/DELQA-T vs DEQNA 29-Apr-07 RMS Separated checks for PxBR and SBR 17-May-06 RMS Added CR11/CD11 support 10-May-06 RMS Added NOP'd reserved operand checking macros @@ -337,7 +336,7 @@ typedef struct { #define INT_V_RP 4 /* RP,RM drives */ #define INT_V_TS 5 /* TS11/TSV05 */ #define INT_V_TQ 6 /* TMSCP */ -#define INT_V_XQDEQNA 7 /* DEQNA */ +#define INT_V_XQ 7 /* DEQNA/DELQA */ #define INT_V_RY 8 /* RXV21 */ /* IPL 14 */ @@ -355,7 +354,6 @@ typedef struct { #define INT_V_VHTX 10 #define INT_V_QDSS 11 /* QDSS */ #define INT_V_CR 12 -#define INT_V_XQDELQA 13 /* DELQA */ #define INT_CLK (1u << INT_V_CLK) #define INT_RQ (1u << INT_V_RQ) @@ -365,8 +363,7 @@ typedef struct { #define INT_RP (1u << INT_V_RP) #define INT_TS (1u << INT_V_TS) #define INT_TQ (1u << INT_V_TQ) -#define INT_XQDEQNA (1u << INT_V_XQDEQNA) -#define INT_XQDELQA (1u << INT_V_XQDELQA) +#define INT_XQ (1u << INT_V_XQ) #define INT_RY (1u << INT_V_RY) #define INT_TTI (1u << INT_V_TTI) #define INT_TTO (1u << INT_V_TTO) @@ -390,8 +387,7 @@ typedef struct { #define IPL_RP (0x15 - IPL_HMIN) #define IPL_TS (0x15 - IPL_HMIN) #define IPL_TQ (0x15 - IPL_HMIN) -#define IPL_XQDEQNA (0x15 - IPL_HMIN) -#define IPL_XQDELQA (0x14 - IPL_HMIN) +#define IPL_XQ (0x15 - IPL_HMIN) #define IPL_RY (0x15 - IPL_HMIN) #define IPL_TTI (0x14 - IPL_HMIN) #define IPL_TTO (0x14 - IPL_HMIN)