From c31ea266e2d2e5f59212ef44b6931f9c890ee195 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Sun, 14 Dec 2025 13:36:45 -1000 Subject: [PATCH] ETHER: Add support for Omni OS and Open Indiana plus bridged network support - Some versions of Omni OS no longer include sys/filio.h in sys/ioctl.h - Add more robust support for locating OS tools in scp.c - SHOW VERSION output displays SunOS host system specific info Fix #1238 --- 0readme_ethernet.txt | 7 ++++- README.md | 2 +- makefile | 3 ++ scp.c | 57 ++++++++++++++++++++++++++++++++++++++ sim_ether.c | 65 ++++++++++++++++++++++++++++++++++++-------- 5 files changed, 120 insertions(+), 14 deletions(-) diff --git a/0readme_ethernet.txt b/0readme_ethernet.txt index 87551810..fe4f8137 100644 --- a/0readme_ethernet.txt +++ b/0readme_ethernet.txt @@ -51,7 +51,12 @@ Relatively recently, macOS (since version 10.15 sometime in 2019) has functionality integrated into the OS that automatically provides bridging to address this problem. The capability is provided by the vmnet facility of the OS. The simh sim_ether layer now leverages this vmnet functionality -(when available), and building of simh on automatically includes it. +(when available), and building of simh on macOS automatically includes it. +In general, "attach xq eth0" will be useful to support this as well as +"attach xq eth1" will work using WiFi if it is connected to a network. + +Relatively recently, SunOS (aka illumos) internally provides functionality +so that host<->simulator network traffic also simply works. The following steps were performed to get a working SIMH vax simulator sharing a physical NIC and allowing Host<->SIMH vax communications: diff --git a/README.md b/README.md index 9061f04b..0cb1f9fc 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ Simulator binaries for x86 Linus, x86 macOS, and Windows for all recent changes - Enhanced Ethernet functionality on macOS which leverages the OS provided vmnet capabilities. This is available on all intel and Apple Silicon macOS systems starting with Catalina (10.15) which was released in 2019. - SCP IF command supports RegEx comparisons. - Windows builds are supported running all versions of Microsoft Visual Studio, including the most recent VS2026. -- All simulators build with full functionality on illumos Open Indiana. +- All simulators build with full functionality and extended/simplified network support on illumos Open Indiana and Omni OS. #### All simulators build cleanly under OpenVMS on ia64 systems. diff --git a/makefile b/makefile index d4629497..d83dd8bb 100644 --- a/makefile +++ b/makefile @@ -889,6 +889,9 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin) ifneq (,$(call find_include,sys/ioctl)) OS_CCDEFS += -DHAVE_SYS_IOCTL endif + ifneq (,$(and $(call find_include,sys/filio),$(shell grep FIONBIO $(call find_include,sys/filio)))) + OS_CCDEFS += -DHAVE_SYS_FILIO + endif ifneq (,$(call find_include,linux/cdrom)) OS_CCDEFS += -DHAVE_LINUX_CDROM endif diff --git a/scp.c b/scp.c index f48960ce..b59c9a70 100644 --- a/scp.c +++ b/scp.c @@ -7080,6 +7080,7 @@ fprintf (st, "%s", sprint_capac (dptr, uptr)); const char *sim_get_tool_path (const char *tool) { char findcmd[PATH_MAX+1]; +char notfound[PATH_MAX+1]; static char toolpath[PATH_MAX+1]; FILE *f; @@ -7103,6 +7104,9 @@ if ((f = popen (findcmd, "r"))) { sim_trim_endspc (toolpath); } while (toolpath[0] == '\0'); pclose (f); + snprintf (notfound, sizeof (notfound), "%s not found", tool); + if (strcmp (notfound, toolpath) == 0) + toolpath[0] = '\0'; } if (toolpath[0] == '\0') { /* Not found yet? */ #if defined(FIND_CMD_EXTRA) /* Try with alternative command */ @@ -7114,6 +7118,12 @@ if (toolpath[0] == '\0') { /* Not found yet? */ sim_trim_endspc (toolpath); } while (toolpath[0] == '\0'); pclose (f); + snprintf (notfound, sizeof (notfound), "%s not found", tool); + if (strcmp (notfound, toolpath) == 0) + toolpath[0] = '\0'; + snprintf (notfound, sizeof (notfound), "no %s in ", tool); + if (strstr (toolpath, notfound) != NULL) + toolpath[0] = '\0'; } #endif } @@ -7551,6 +7561,53 @@ if (1) { setenv ("SIM_HOST_MAX_THREADS", procs, 1); } } +#elif defined (__illumos__) + if ((f = popen ("psrinfo -p -v 2>/dev/null", "r"))) { + char line[256]; + int n1, n2; + int cores = 0; + int procs = 0; + char proc_name[PATH_MAX+1] = ""; + char *c; + + do { + if (NULL == fgets (line, sizeof (line), f)) + break; + sim_trim_endspc (line); + if (2 == sscanf (line, "The physical processor has %d cores and %d virtual processors", &n1, &n2)) { + cores = n1; + procs = n2; + continue; + } + if (1 == sscanf (line, "The physical processor has %d virtual processors", &n1)) { + procs = n1; + continue; + } + if ((memcmp (line, " ", 6) == 0) || + (line[0] == '\t')) { + if ((c = strchr (line, '['))) { + *c = '\0'; + sim_trim_spc (line); + } + strlcpy (proc_name, line, sizeof (proc_name)); + } + } while ((proc_name[0] == '\0') || (cores == 0) || (procs == 0)); + pclose (f); + if (proc_name[0] != '\0') + fprintf (st, "\n Processor Name: %s", proc_name); + if ((procs != 0) || (cores != 0)) + fprintf (st, "\n "); + if (cores != 0) { + snprintf (line, sizeof (line), "%d", cores); + fprintf (st, "Cores: %s", line); + setenv ("SIM_HOST_CORE_COUNT", line, 1); + } + if (procs != 0) { + snprintf (line, sizeof (line), "%d", procs); + fprintf (st, "%sLogical Processors: %s", (cores != 0) ? ", " : "", line); + setenv ("SIM_HOST_MAX_THREADS", line, 1); + } + } #endif strlcpy (tarversion, _get_tool_version ("tar"), sizeof (tarversion)); if (tarversion[0]) { diff --git a/sim_ether.c b/sim_ether.c index 4f798870..24587890 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -1126,8 +1126,11 @@ t_stat sim_ether_test (DEVICE *dptr, const char *cptr) #else /* endif unimplemented */ -#if (defined (xBSD) || defined (__APPLE__)) && (defined (HAVE_TAP_NETWORK) || defined (HAVE_PCAP_NETWORK)) +#if (defined (xBSD) || defined (__APPLE__) || defined (__illumos__)) && (defined (HAVE_TAP_NETWORK) || defined (HAVE_PCAP_NETWORK)) #include +#if (!defined (FIONBIO)) && defined (HAVE_SYS_FILIO) +#include +#endif #include #endif @@ -1453,6 +1456,7 @@ else { /* copy device list into the passed structure */ for (used=0, dev=alldevs; dev && (used < max); dev=dev->next) { char Info[ETH_DEV_INFO_MAX]; + static const ETH_MAC zeros = {0, 0, 0, 0, 0, 0}; edev.eth_api = ETH_API_PCAP; eth_get_nic_hw_addr (&edev, dev->name, 0, Info); @@ -1460,11 +1464,17 @@ else { continue; if ((dev->flags & PCAP_IF_LOOPBACK) || (!strcmp("any", dev->name))) continue; + if (memcmp (edev.host_nic_phy_hw_addr, zeros, sizeof (ETH_MAC)) == 0) + continue; strlcpy(list[used].name, dev->name, sizeof(list[used].name)); if (dev->description) strlcpy(list[used].desc, dev->description, sizeof(list[used].desc)); else { +#if defined (__illumos__) + strlcpy(list[used].desc, "Bridged Ethernet support", sizeof(list[used].desc)); +#else strlcpy(list[used].desc, "No description available", sizeof(list[used].desc)); +#endif if (Info[0] != '\0') snprintf(list[used].info, sizeof(list[used].info), "%s", Info); } @@ -2124,11 +2134,12 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, const char *devname, int set_on, c FILE *f; int i; char tool[CBUFSIZE]; - const char *turnon[] = { + static const ETH_MAC zeros = {0, 0, 0, 0, 0, 0}; + static const char *turnon[] = { "ip link set dev %.*s up 2>/dev/null", "ifconfig %.*s up 2>/dev/null", NULL}; - const char *MACpatterns[] = { + static const char *MACpatterns[] = { "ip link show %.*s 2>/dev/null | 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] 2>/dev/null", "ip link show %.*s 2>/dev/null | grep -E [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] 2>/dev/null", "ip link show %.*s 2>/dev/null | egrep [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] 2>/dev/null", @@ -2136,7 +2147,7 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, const char *devname, int set_on, c "ifconfig %.*s 2>/dev/null | grep -E [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] 2>/dev/null", "ifconfig %.*s 2>/dev/null | egrep [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] 2>/dev/null", NULL}; - const char *IPv4patterns[] = { + static const char *IPv4patterns[] = { "ip -4 address show %.*s 2>/dev/null | grep 'inet ' 2>/dev/null", "ip -4 address show %.*s 2>/dev/null | grep -E 'inet ' 2>/dev/null", "ip -4 address show %.*s 2>/dev/null | egrep 'inet ' 2>/dev/null", @@ -2144,15 +2155,15 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, const char *devname, int set_on, c "ifconfig %.*s 2>/dev/null | grep -E 'inet ' 2>/dev/null", "ifconfig %.*s 2>/dev/null | egrep 'inet ' 2>/dev/null", NULL}; - const char *LinkTypepatterns[] = { + static const char *LinkTypepatterns[] = { "ipconfig getsummary %.*s 2>/dev/null | grep 'InterfaceType' 2>/dev/null | awk '{ print $3 }'", "nmcli device 2>/dev/null | grep %.*s 2>/dev/null | grep 'Wired connection' 2>/dev/null | awk '{ print $2 }'", "nmcli device 2>/dev/null | grep %.*s 2>/dev/null | grep -e 'wifi' -e 'ethernet' 2>/dev/null | awk '{ print $2 }'", NULL}; - const char *LinkStatuspatterns[] = { + static const char *LinkStatuspatterns[] = { "ifconfig %.*s 2>/dev/null | grep 'status: ' 2>/dev/null | awk '{if ($0 ~ /status: inactive/) { print \"MediaState: disconnected\" } else {if ($0 ~ /status: active/) { print \"MediaState: connected\" }}}'", NULL}; - const char *LinkStatusDownpatterns[] = { + static const char *LinkStatusDownpatterns[] = { "ip -4 link show %.*s 2>/dev/null | grep 'NO-CARRIER' 2>/dev/null | grep 'state DOWN' 2>/dev/null", NULL}; @@ -2225,14 +2236,16 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, const char *devname, int set_on, c unsigned int byt1, byt2, byt3, byt4; int j; char *p2 = strstr(p1, "netmask"); - int netmask = 0xFFFFFFFF; + uint32 netmask = 0xFFFFFFFF; char cidr[4]; if (NULL != p2) { if (4 == sscanf(p2, "netmask %u.%u.%u.%u", &byt1, &byt2, &byt3, &byt4)) netmask = (byt1 << 24) | (byt2 << 16) | (byt3 << 8) | byt4; - else - sscanf(p2, "netmask 0x%x", &netmask); + else { + if (1 != sscanf(p2, "netmask 0x%x", &netmask)) + sscanf(p2, "netmask %x", &netmask); + } if (netmask != 0xFFFFFFFF) { for (j = 0; j < 32; j++) if (0 == (netmask & (1 << (31 - j)))) { @@ -2383,8 +2396,36 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, const char *devname, int set_on, c } } } - } +#if defined (__illumos__) + if (memcmp (dev->host_nic_phy_hw_addr, zeros, sizeof (ETH_MAC)) != 0) { + t_bool promisc_mode = FALSE; + snprintf(command, sizeof(command), "ifconfig %s 2>/dev/null", devname); + get_glyph_nc (command, tool, 0); + if (sim_get_tool_path (tool)[0]) { + if (NULL != (f = popen(command, "r"))) { + while (fgets(result, sizeof(result), f) != NULL) { + if (strstr (result, "PROMISC") != NULL) { + promisc_mode = TRUE; + break; + } + } + pclose(f); + } + if (promisc_mode == FALSE) { + snprintf(command, sizeof(command), "dladm create-vnic -l %s vnic99; dladm set-linkprop -p promisc-filtered=off vnic0 2>/dev/null", devname); + get_glyph_nc (command, tool, 0); + if (sim_get_tool_path (tool)[0]) { + if (NULL != (f = popen(command, "r"))) { + while (fgets(result, sizeof(result), f) != NULL); + pclose(f); + } + } + } + } + } +#endif + } #endif } @@ -5234,7 +5275,7 @@ if (dev->error_reopen_count) fprintf(st, " Error Reopen Count: %d\n", (int)dev->error_reopen_count); if (1) { int i, count = 0; - ETH_MAC zeros = {0, 0, 0, 0, 0, 0}; + static const ETH_MAC zeros = {0, 0, 0, 0, 0, 0}; char buffer[20]; for (i = 0; i < ETH_FILTER_MAX; i++) {