mirror of
https://github.com/simh/simh.git
synced 2026-01-11 23:52:58 +00:00
ETHER: Add vmnet support for macOS Catalina 10.15.7 through Big Sur 11.7.10
This commit is contained in:
parent
df31a5b7f9
commit
caea0c0970
@ -108,6 +108,7 @@ Simulator binaries for x86 Linus, x86 macOS, and Windows for all recent changes
|
||||
- Ethernet enhancements on all platforms and and much simplified platform support on macOS.
|
||||
- Almost all existing simulators have useful SET CONSOLE SPEED=nnn behaviors in both the bare console session as well as TELNET console sessions.
|
||||
- Simh global/startup configuration commands can be contained in the first of simh.ini found in: 1) The current working directory, 2) The User login directory, 3) The directory containing the simulator executable, 4) The ~/Library/Preferences directory, 5) The /Library/Preferences directory, or 6) The /etc directory.
|
||||
- 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.
|
||||
|
||||
#### All simulators build cleanly under OpenVMS on ia64 systems.
|
||||
|
||||
@ -138,7 +139,7 @@ Simulator binaries for x86 Linus, x86 macOS, and Windows for all recent changes
|
||||
- VAX Instruction history can be recorded to disk both for all instructions executed as well as every n instructions.
|
||||
- VAX Unibus simulators (780, 750, 730, 8600, 8200) run DEC supplied diagnostics at the speed of the original systems and also run the privileged instruction diagnostic that was supported on the original systems.
|
||||
|
||||
### All relevant changes in the simh v3.12-4 release have been merged into this repo
|
||||
### All relevant changes in Bob Supnik's simh v3.12-4 release have been merged into this repo
|
||||
|
||||
### Bill Beech has made significant enhancements and bug fixes to the SWTP simulators along with a new disk controller from Roberto Sancho Villa
|
||||
|
||||
|
||||
6
makefile
6
makefile
@ -972,12 +972,18 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin)
|
||||
else
|
||||
DONT_USE_VMNET = $(shell if ${TEST} $(macOSMajor) -lt 10; then echo DONT_USE_VMNET; fi)
|
||||
endif
|
||||
ifeq (,$(DONT_USE_VMNET)$(DONT_USE_VMNET_HOST))
|
||||
DONT_USE_VMNET_HOST = $(shell if ${TEST} $(macOSMajor) -lt 11; then echo DONT_USE_VMNET_HOST; fi)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
ifneq (,$(if $(DONT_USE_VMNET),,$(call find_include,vmnet.framework/Headers/vmnet)))
|
||||
# sim_ether reduces network features to the appropriate minimal set
|
||||
NETWORK_LAN_FEATURES += VMNET
|
||||
NETWORK_CCDEFS += -DUSE_SHARED -I slirp -I slirp_glue -I slirp_glue/qemu -DHAVE_VMNET_NETWORK
|
||||
ifneq (,$(DONT_USE_VMNET_HOST))
|
||||
NETWORK_CCDEFS += -DDONT_USE_VMNET_HOST
|
||||
endif
|
||||
NETWORK_DEPS += slirp/*.c slirp_glue/*.c
|
||||
NETWORK_LDFLAGS += -framework vmnet
|
||||
$(info using vmnet: $(call find_include,vmnet.framework/Headers/vmnet))
|
||||
|
||||
23
scp.c
23
scp.c
@ -7438,6 +7438,9 @@ if (1) {
|
||||
fprintf (st, "\n curl tool: %s", curlversion);
|
||||
setenv ("SIM_CURL_CMD_AVAILABLE", "TRUE", 1);
|
||||
}
|
||||
#if !defined(_WIN32)
|
||||
fprintf (st, "\n %s as root", _sim_running_as_root () ? "Running" : "Not running");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
if ((!strcmp (os_type, "Unknown")) && (getenv ("OSTYPE")))
|
||||
@ -16904,6 +16907,26 @@ if (sim_rand_seed < 0)
|
||||
return (sim_rand_seed - 1);
|
||||
}
|
||||
|
||||
t_bool _sim_running_as_root (void)
|
||||
{
|
||||
FILE *f = fopen("/dev/mem", "r");
|
||||
char response[64] = "";
|
||||
|
||||
if (f != NULL) {
|
||||
fclose(f);
|
||||
return TRUE;
|
||||
}
|
||||
#if !defined(_WIN32)
|
||||
f = popen("id -u", "r");
|
||||
if (f == NULL)
|
||||
return FALSE;
|
||||
if (fgets(response, sizeof(response), f))
|
||||
sim_trim_endspc (response);
|
||||
pclose(f);
|
||||
#endif
|
||||
return (0 == strcmp(response, "0"));
|
||||
}
|
||||
|
||||
|
||||
typedef struct MFILE {
|
||||
char *buf;
|
||||
|
||||
476
sim_ether.c
476
sim_ether.c
@ -816,26 +816,6 @@ fields.pseudo_hash = eth_crc32 (eth_crc32 (0x6ba7b815, sysid, sizeof(sysid)), ta
|
||||
memcpy (uuid_buf, (void *)&fields, 16);
|
||||
}
|
||||
|
||||
static ETH_BOOL _eth_running_as_root (void)
|
||||
{
|
||||
FILE *f = fopen("/dev/mem", "r");
|
||||
char response[64] = "";
|
||||
|
||||
if (f != NULL) {
|
||||
fclose(f);
|
||||
return TRUE;
|
||||
}
|
||||
#if !defined(_WIN32)
|
||||
f = popen("id -u", "r");
|
||||
if (f == NULL)
|
||||
return FALSE;
|
||||
if (fgets(response, sizeof(response), f))
|
||||
sim_trim_endspc (response);
|
||||
pclose(f);
|
||||
#endif
|
||||
return (0 == strcmp(response, "0"));
|
||||
}
|
||||
|
||||
#if defined (USE_NETWORK) || defined (USE_SHARED)
|
||||
|
||||
#ifdef HAVE_VMNET_NETWORK
|
||||
@ -1036,8 +1016,6 @@ t_stat eth_show (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
|
||||
}
|
||||
} while (end != NULL);
|
||||
}
|
||||
if ((NULL != strstr(list[0].name, "tap:")) && (!_eth_running_as_root()))
|
||||
fprintf(st, "You probably need to run as root\n");
|
||||
}
|
||||
}
|
||||
if (1) {
|
||||
@ -1069,6 +1047,17 @@ t_stat eth_show (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
|
||||
eth_show_dev (st, eth_open_devices[i]);
|
||||
}
|
||||
}
|
||||
if (((NULL != strstr(list[0].name, "tap:")) ||
|
||||
(NULL != strstr(list[0].name, "nat:")) ||
|
||||
(NULL != strstr(list[0].name, "udp:"))) ||
|
||||
#if defined(_WIN32)
|
||||
FALSE)
|
||||
fprintf(st, "You probably need to install npcap\n");
|
||||
#else
|
||||
((list[0].eth_api == ETH_API_VMNET) &&
|
||||
(!_sim_running_as_root())))
|
||||
fprintf(st, "You probably need to run as root\n");
|
||||
#endif
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@ -1295,29 +1284,31 @@ if (1) {
|
||||
continue;
|
||||
if (sim_isspace(line[0])) {
|
||||
c = strchr(line, ':');
|
||||
if (strstr(line, "IPv4 Address") || strstr(line, "IP Address")) {
|
||||
char *c = strchr(line, ':');
|
||||
strlcat(dev->info, "Host IPv4 Address", sizeof(dev->info));
|
||||
strlcat(dev->info, c, sizeof(dev->info));
|
||||
}
|
||||
if (strstr(line, "Subnet Mask")) {
|
||||
unsigned int byt1, byt2, byt3, byt4;
|
||||
int netmask;
|
||||
char cidr[20];
|
||||
|
||||
sscanf(c, ": %u.%u.%u.%u", &byt1, &byt2, &byt3, &byt4);
|
||||
netmask = (byt1 << 24) | (byt2 << 16) | (byt3 << 8) | byt4;
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (0 == (netmask & (1 << (31 - i))))
|
||||
break;
|
||||
if (dev != NULL) {
|
||||
if (strstr(line, "IPv4 Address") || strstr(line, "IP Address")) {
|
||||
char *c = strchr(line, ':');
|
||||
strlcat(dev->info, "Host IPv4 Address", sizeof(dev->info));
|
||||
strlcat(dev->info, c, sizeof(dev->info));
|
||||
}
|
||||
if (strstr(line, "Subnet Mask")) {
|
||||
unsigned int byt1, byt2, byt3, byt4;
|
||||
int netmask;
|
||||
char cidr[20];
|
||||
|
||||
sscanf(c, ": %u.%u.%u.%u", &byt1, &byt2, &byt3, &byt4);
|
||||
netmask = (byt1 << 24) | (byt2 << 16) | (byt3 << 8) | byt4;
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (0 == (netmask & (1 << (31 - i))))
|
||||
break;
|
||||
}
|
||||
snprintf(cidr, sizeof(cidr), "/%d", i);
|
||||
strlcat(dev->info, cidr, sizeof(dev->info));
|
||||
}
|
||||
if (strstr(line, "Media State")) {
|
||||
if (dev->info[0] != '\0')
|
||||
strlcat(dev->info, "\n", sizeof(dev->info));
|
||||
strlcat(dev->info, "MediaState: disconnected", sizeof(dev->info));
|
||||
}
|
||||
snprintf(cidr, sizeof(cidr), "/%d", i);
|
||||
strlcat(dev->info, cidr, sizeof(dev->info));
|
||||
}
|
||||
if (strstr(line, "Media State")) {
|
||||
if (dev->info[0] != '\0')
|
||||
strlcat(dev->info, "\n", sizeof(dev->info));
|
||||
strlcat(dev->info, "MediaState: disconnected", sizeof(dev->info));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@ -1412,7 +1403,10 @@ const char *eth_capabilities(void)
|
||||
#endif
|
||||
strlcat (capabilities, "Ethernet Packet transports", sizeof (capabilities));
|
||||
#if defined (HAVE_VMNET_NETWORK)
|
||||
strlcat (capabilities, ":PCAP(vmnet):TAP(vmnet)", sizeof (capabilities));
|
||||
strlcat (capabilities, ":PCAP(vmnet)", sizeof (capabilities));
|
||||
#if defined(USE_VMNET_HOST_AS_TAP)
|
||||
strlcat (capabilities, ":TAP(vmnet)", sizeof (capabilities));
|
||||
#endif
|
||||
#if defined(USE_VMNET_SHARED_AS_NAT)
|
||||
strlcat (capabilities, ":NAT(vmnet)", sizeof (capabilities));
|
||||
#endif
|
||||
@ -1420,7 +1414,7 @@ const char *eth_capabilities(void)
|
||||
#if defined (HAVE_PCAP_NETWORK)
|
||||
strlcat (capabilities, ":PCAP", sizeof (capabilities));
|
||||
#endif
|
||||
#if defined (HAVE_TAP_NETWORK)
|
||||
#if defined (HAVE_TAP_NETWORK) && !defined (USE_VMNET_HOST_AS_TAP)
|
||||
strlcat (capabilities, ":TAP", sizeof (capabilities));
|
||||
#endif
|
||||
#if defined (HAVE_VDE_NETWORK)
|
||||
@ -1512,12 +1506,14 @@ if (1) {
|
||||
}
|
||||
xpc_release(interface_list);
|
||||
|
||||
#if defined(USE_VMNET_HOST_AS_TAP)
|
||||
if (used < max) {
|
||||
sprintf(list[used].name, "%s", "tap:{optional-tap-parameters}");
|
||||
sprintf(list[used].desc, "%s", "Integrated host-only network (vmnet) support");
|
||||
list[used].eth_api = ETH_API_VMNET;
|
||||
++used;
|
||||
}
|
||||
#endif
|
||||
#if defined(USE_VMNET_SHARED_AS_NAT)
|
||||
if (used < max) {
|
||||
sprintf(list[used].name, "%s", "nat:{optional-nat-parameters}");
|
||||
@ -2150,7 +2146,7 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, const char *devname, int set_on, c
|
||||
"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[] = {
|
||||
"ipconfig getsummary %.*s 2>/dev/null | grep 'LinkStatusActive' 2>/dev/null | awk '{ print $3 }'",
|
||||
"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[] = {
|
||||
"ip -4 link show %.*s 2>/dev/null | grep 'NO-CARRIER' 2>/dev/null | grep 'state DOWN' 2>/dev/null",
|
||||
@ -2283,6 +2279,49 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, const char *devname, int set_on, c
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((Info != NULL) && (NULL == strstr(Info, "LinkType"))) {
|
||||
char command[64] = "networksetup -listallhardwareports";
|
||||
char tool[CBUFSIZE];
|
||||
FILE *f;
|
||||
ETH_LIST *dev = NULL;
|
||||
|
||||
get_glyph_nc (command, tool, 0);
|
||||
if (sim_get_tool_path (tool)[0]) {
|
||||
if (NULL != (f = popen(command, "r"))) {
|
||||
char port_type[128];
|
||||
char line[128];
|
||||
|
||||
memset(line, 0, sizeof(line));
|
||||
memset(port_type, 0, sizeof(port_type));
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
sim_trim_endspc (line);
|
||||
if (line[0] == '\0')
|
||||
continue;
|
||||
if (memcmp(line, "Hardware Port: ", 15) == 0) {
|
||||
strlcpy(port_type, line + 15, sizeof(port_type));
|
||||
continue;
|
||||
}
|
||||
if ((strcmp(port_type, "Ethernet") != 0) && (strcmp(port_type, "Wi-Fi") != 0))
|
||||
continue;
|
||||
if (memcmp(line, "Device: ", 8) == 0) {
|
||||
if (strcmp(devname, line + 8) == 0) {
|
||||
if (Info[0] != '\0')
|
||||
strlcat(Info, "\n", ETH_DEV_INFO_MAX);
|
||||
strlcat(Info, "LinkType: ", ETH_DEV_INFO_MAX);
|
||||
if (strcmp(port_type, "Wi-Fi") == 0)
|
||||
strlcat(Info, "WiFi", ETH_DEV_INFO_MAX);
|
||||
else
|
||||
strlcat(Info, "Ethernet", ETH_DEV_INFO_MAX);
|
||||
break;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
}
|
||||
pclose(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If the link type is still undetermined, then assume that device */
|
||||
/* names starting with "wl" are WiFi otherwise they are Ethernet */
|
||||
if ((Info != NULL) && (NULL == strstr(Info, "LinkType"))) {
|
||||
@ -2294,7 +2333,7 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, const char *devname, int set_on, c
|
||||
else
|
||||
strlcat(Info, "Ethernet", ETH_DEV_INFO_MAX);
|
||||
}
|
||||
for (i=0; LinkStatuspatterns[i] && (Info != NULL) && (NULL == strstr(Info, "LinkStatus")); ++i) {
|
||||
for (i=0; LinkStatuspatterns[i] && (Info != NULL) && (NULL == strstr(Info, "MediaState")); ++i) {
|
||||
snprintf(command, sizeof(command), LinkStatuspatterns[i], (int)(sizeof(command) - (2 + strlen(LinkStatuspatterns[i]))), devname);
|
||||
get_glyph_nc (command, tool, 0);
|
||||
if (sim_get_tool_path (tool)[0]) {
|
||||
@ -2302,27 +2341,19 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, const char *devname, int set_on, c
|
||||
while (NULL == strstr(Info, "MediaState")) {
|
||||
if (fgets(result, sizeof(result), f)) {
|
||||
sim_trim_endspc(result);
|
||||
if (Info[0] != '\0')
|
||||
strlcat(Info, "\n", ETH_DEV_INFO_MAX);
|
||||
strlcat(Info, "MediaState: ", ETH_DEV_INFO_MAX);
|
||||
if (0 == strcasecmp(result, "TRUE"))
|
||||
strlcat(Info, "connected", ETH_DEV_INFO_MAX);
|
||||
else
|
||||
strlcat(Info, "disconnected", ETH_DEV_INFO_MAX);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (Info[0] != '\0')
|
||||
strlcat(Info, "\n", ETH_DEV_INFO_MAX);
|
||||
strlcat(Info, "MediaState: disconnected", ETH_DEV_INFO_MAX);
|
||||
break;
|
||||
if (result[0]) {
|
||||
if (Info[0] != '\0')
|
||||
strlcat(Info, "\n", ETH_DEV_INFO_MAX);
|
||||
strlcat(Info, result, ETH_DEV_INFO_MAX);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pclose(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i=0; LinkStatusDownpatterns[i] && (Info != NULL) && (NULL == strstr(Info, "LinkStatus")); ++i) {
|
||||
for (i=0; LinkStatusDownpatterns[i] && (Info != NULL) && (NULL == strstr(Info, "MediaState")); ++i) {
|
||||
snprintf(command, sizeof(command), LinkStatusDownpatterns[i], (int)(sizeof(command) - (2 + strlen(LinkStatusDownpatterns[i]))), devname);
|
||||
get_glyph_nc (command, tool, 0);
|
||||
if (sim_get_tool_path (tool)[0]) {
|
||||
@ -2853,149 +2884,7 @@ if (0 == strncmp("nat:", savname, 4)) {
|
||||
#endif /* defined(HAVE_SLIRP_NETWORK) */
|
||||
}
|
||||
#endif /* !defined(USE_VMNET_SHARED_AS_NAT) */
|
||||
/* Setting parameters on a vmnet SHARED interface doesn't actually */
|
||||
/* work as described in the documentation. If, in the future, it */
|
||||
/* does, and the network block can actually be specified along with */
|
||||
/* configuring inbound UDP and TCP port mapping, this can be enabled */
|
||||
/* along with implementing any currently missing pieces. */
|
||||
#if defined(HAVE_VMNET_NETWORK)
|
||||
xpc_object_t if_desc;
|
||||
dispatch_queue_t vmn_queue;
|
||||
interface_ref vmn_interface;
|
||||
char gbuf[CBUFSIZE];
|
||||
char *hostaddr = NULL;
|
||||
char *endaddr = NULL;
|
||||
char *netmask = NULL;
|
||||
|
||||
if_desc = xpc_dictionary_create(NULL, NULL, 0);
|
||||
#if defined(USE_VMNET_SHARED_AS_NAT)
|
||||
if (0 == strncasecmp(savname, "nat:", 4)) {
|
||||
NAT nat;
|
||||
int err = 0;
|
||||
|
||||
memset(&nat, 0, sizeof(NAT));
|
||||
xpc_dictionary_set_uint64(if_desc, vmnet_operation_mode_key, VMNET_SHARED_MODE);
|
||||
/* First, start with the original NAT default */
|
||||
sim_nat_parse_args (&nat, "GATEWAY=10.0.2.2,MASKLEN=24,DHCP=10.0.2.15", ETH_API_VMNET, (char *)errbuf, sizeof(errbuf));
|
||||
err = sim_nat_parse_args (&nat, &savname[4], ETH_API_VMNET, (char *)errbuf, sizeof(errbuf));
|
||||
if (err == 0) {
|
||||
if (nat.vdhcp_start.s_addr != INADDR_ANY)
|
||||
hostaddr = strdup (inet_ntoa (nat.vdhcp_start));
|
||||
if (nat.vdhcp_end.s_addr != INADDR_ANY)
|
||||
endaddr = strdup (inet_ntoa (nat.vdhcp_end));
|
||||
if (nat.vnetmask.s_addr != INADDR_ANY)
|
||||
netmask = strdup (inet_ntoa (nat.vnetmask));
|
||||
if (hostaddr)
|
||||
xpc_dictionary_set_string(if_desc, vmnet_start_address_key, hostaddr);
|
||||
if (endaddr)
|
||||
xpc_dictionary_set_string(if_desc, vmnet_end_address_key, endaddr);
|
||||
if (netmask)
|
||||
xpc_dictionary_set_string(if_desc, vmnet_host_subnet_mask_key, netmask);
|
||||
xpc_dictionary_set_bool(if_desc, vmnet_enable_isolation_key, TRUE);
|
||||
}
|
||||
// Need NAT parameter parsing, TCP and UDP port allowances and setup
|
||||
}
|
||||
else {
|
||||
#else /* !defined(USE_VMNET_SHARED_AS_NAT) */
|
||||
if (1) {
|
||||
#endif /* !defined(USE_VMNET_SHARED_AS_NAT) */
|
||||
if (0 == strncasecmp(savname, "tap:", 4)) {
|
||||
const char *tptr = savname + 4;
|
||||
unsigned char net_uuid[16];
|
||||
NAT nat;
|
||||
int err = 0;
|
||||
|
||||
memset(&nat, 0, sizeof(nat));
|
||||
xpc_dictionary_set_uint64(if_desc, vmnet_operation_mode_key, VMNET_HOST_MODE);
|
||||
tptr = get_glyph_nc (tptr, gbuf, ',');
|
||||
_eth_tap_uuid (gbuf, net_uuid);
|
||||
xpc_dictionary_set_uuid(if_desc, vmnet_network_identifier_key, net_uuid);
|
||||
if ((tptr != NULL) && (*tptr != '\0')) {
|
||||
err = sim_nat_parse_args (&nat, tptr, ETH_API_VMNET, (char *)errbuf, sizeof(errbuf));
|
||||
if (err != 0) {
|
||||
xpc_release(if_desc);
|
||||
snprintf (errbuf, errbuf_size, "Error parsing vmnet tap: device parameters");
|
||||
return SCPE_OPENERR;
|
||||
}
|
||||
if (nat.vgateway.s_addr != INADDR_ANY)
|
||||
hostaddr = strdup (inet_ntoa (nat.vgateway));
|
||||
if (nat.vnetmask.s_addr != INADDR_NONE)
|
||||
netmask = strdup (inet_ntoa (nat.vnetmask));
|
||||
if (((hostaddr != NULL) && (netmask == NULL)) ||
|
||||
((hostaddr == NULL) && (netmask != NULL))){
|
||||
free(hostaddr);
|
||||
free(endaddr);
|
||||
free(netmask);
|
||||
xpc_release(if_desc);
|
||||
snprintf (errbuf, errbuf_size, "Both the HOSTIP and MASKLEN must be specified together vmnet host (tap:) device");
|
||||
return SCPE_OPENERR;
|
||||
}
|
||||
if (hostaddr)
|
||||
xpc_dictionary_set_string(if_desc, vmnet_host_ip_address_key, hostaddr);
|
||||
if (netmask)
|
||||
xpc_dictionary_set_string(if_desc, vmnet_host_subnet_mask_key, netmask);
|
||||
}
|
||||
}
|
||||
else { // Bridged, so check if we've got a reasonable device name
|
||||
xpc_object_t interface_list = vmnet_copy_shared_interface_list();
|
||||
int i, interface_count = xpc_array_get_count(interface_list);
|
||||
|
||||
for (i=0; i<interface_count; i++) {
|
||||
xpc_object_t element = xpc_array_get_value(interface_list, i);
|
||||
|
||||
if (0 == strcmp(savname, xpc_string_get_string_ptr(element)))
|
||||
break;
|
||||
}
|
||||
if (i == interface_count) { /* Not found? */
|
||||
free(hostaddr);
|
||||
free(endaddr);
|
||||
free(netmask);
|
||||
xpc_release(if_desc);
|
||||
snprintf (errbuf, errbuf_size, "You must specify either an appropriate vmnet bridged interface or a tap:");
|
||||
return SCPE_OPENERR;
|
||||
}
|
||||
xpc_dictionary_set_uint64(if_desc, vmnet_operation_mode_key, VMNET_BRIDGED_MODE);
|
||||
xpc_dictionary_set_string(if_desc, vmnet_shared_interface_name_key, savname);
|
||||
}
|
||||
}
|
||||
|
||||
vmn_queue = dispatch_get_global_queue(QOS_CLASS_UTILITY, 0);
|
||||
|
||||
_open_port_vmnet_cb_finished = dispatch_semaphore_create(0);
|
||||
_open_port_opaque = opaque;
|
||||
|
||||
vmn_interface = vmnet_start_interface(if_desc, vmn_queue, ^(vmnet_return_t status, xpc_object_t params)
|
||||
{
|
||||
_open_port_vmnet_status = status;
|
||||
if (status == VMNET_SUCCESS) {
|
||||
/* The logical device (bridge or otherwise) vmnet provides has its own MAC address which */
|
||||
/* becomes the host system's address from the simulator's point of view */
|
||||
if (SCPE_OK == eth_mac_scan (&((ETH_DEV*)_open_port_opaque)->host_nic_phy_hw_addr, xpc_dictionary_get_string(params, vmnet_mac_address_key)))
|
||||
((ETH_DEV*)_open_port_opaque)->have_host_nic_phy_addr = 1;
|
||||
}
|
||||
dispatch_semaphore_signal(_open_port_vmnet_cb_finished);
|
||||
});
|
||||
|
||||
dispatch_semaphore_wait(_open_port_vmnet_cb_finished, DISPATCH_TIME_FOREVER);
|
||||
dispatch_release(_open_port_vmnet_cb_finished);
|
||||
_open_port_vmnet_cb_finished = NULL;
|
||||
free(hostaddr);
|
||||
free(endaddr);
|
||||
free(netmask);
|
||||
xpc_release(if_desc);
|
||||
|
||||
if (_open_port_vmnet_status != VMNET_SUCCESS) {
|
||||
if (!_eth_running_as_root())
|
||||
snprintf (errbuf, errbuf_size, "Failed to create vmnet connection for %s - %s. You may need to run as root", savname, _vmnet_status_string(_open_port_vmnet_status));
|
||||
else
|
||||
snprintf (errbuf, errbuf_size, "Failed to create vmnet connection for %s - %s.", savname, _vmnet_status_string(_open_port_vmnet_status));
|
||||
return SCPE_OPENERR;
|
||||
}
|
||||
|
||||
*eth_api = ETH_API_VMNET;
|
||||
*handle = (void *)vmn_interface; /* Flag used to indicated open */
|
||||
return SCPE_OK;
|
||||
#else /* !defined(HAVE_VMNET_NETWORK) */
|
||||
#if !defined(USE_VMNET_HOST_AS_TAP)
|
||||
if (0 == strncmp("tap:", savname, 4)) {
|
||||
int tun = -1; /* TUN/TAP Socket */
|
||||
int on = 1;
|
||||
@ -3076,7 +2965,7 @@ if (0 == strncmp("tap:", savname, 4)) {
|
||||
close(s);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif /* defined (__APPLE__) */
|
||||
}
|
||||
else
|
||||
strlcpy(errbuf, strerror(errno), errbuf_size);
|
||||
@ -3085,16 +2974,166 @@ if (0 == strncmp("tap:", savname, 4)) {
|
||||
tun = -1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#else /* !(defined(HAVE_BSDTUNTAP) && defined(HAVE_TAP_NETWORK)) */
|
||||
strlcpy(errbuf, "No support for tap: devices", errbuf_size);
|
||||
#endif /* !defined(__linux) && !defined(HAVE_BSDTUNTAP) */
|
||||
if (0 == errbuf[0]) {
|
||||
*eth_api = ETH_API_TAP;
|
||||
*handle = (void *)1; /* Flag used to indicated open */
|
||||
return SCPE_OK;
|
||||
#endif /* !(defined(HAVE_BSDTUNTAP) && defined(HAVE_TAP_NETWORK)) */
|
||||
}
|
||||
#endif /* !defined(USE_VMNET_HOST_AS_TAP) */
|
||||
/* Setting parameters on a vmnet SHARED interface doesn't actually */
|
||||
/* work as described in the documentation. If, in the future, it */
|
||||
/* does, and the network block can actually be specified along with */
|
||||
/* configuring inbound UDP and TCP port mapping, this can be enabled */
|
||||
/* along with implementing any then currently missing pieces. */
|
||||
#if defined(HAVE_VMNET_NETWORK)
|
||||
xpc_object_t if_desc;
|
||||
dispatch_queue_t vmn_queue;
|
||||
interface_ref vmn_interface;
|
||||
char gbuf[CBUFSIZE];
|
||||
char *hostaddr = NULL;
|
||||
char *endaddr = NULL;
|
||||
char *netmask = NULL;
|
||||
|
||||
if_desc = xpc_dictionary_create(NULL, NULL, 0);
|
||||
#if defined(USE_VMNET_SHARED_AS_NAT)
|
||||
if (0 == strncmp(savname, "nat:", 4)) {
|
||||
NAT nat;
|
||||
int err = 0;
|
||||
|
||||
memset(&nat, 0, sizeof(NAT));
|
||||
xpc_dictionary_set_uint64(if_desc, vmnet_operation_mode_key, VMNET_SHARED_MODE);
|
||||
/* First, start with the original NAT default */
|
||||
sim_nat_parse_args (&nat, "GATEWAY=10.0.2.2,MASKLEN=24,DHCP=10.0.2.15", ETH_API_VMNET, (char *)errbuf, sizeof(errbuf));
|
||||
err = sim_nat_parse_args (&nat, &savname[4], ETH_API_VMNET, (char *)errbuf, sizeof(errbuf));
|
||||
if (err == 0) {
|
||||
if (nat.vdhcp_start.s_addr != INADDR_ANY)
|
||||
hostaddr = strdup (inet_ntoa (nat.vdhcp_start));
|
||||
if (nat.vdhcp_end.s_addr != INADDR_ANY)
|
||||
endaddr = strdup (inet_ntoa (nat.vdhcp_end));
|
||||
if (nat.vnetmask.s_addr != INADDR_ANY)
|
||||
netmask = strdup (inet_ntoa (nat.vnetmask));
|
||||
if (hostaddr)
|
||||
xpc_dictionary_set_string(if_desc, vmnet_start_address_key, hostaddr);
|
||||
if (endaddr)
|
||||
xpc_dictionary_set_string(if_desc, vmnet_end_address_key, endaddr);
|
||||
if (netmask)
|
||||
xpc_dictionary_set_string(if_desc, vmnet_host_subnet_mask_key, netmask);
|
||||
xpc_dictionary_set_bool(if_desc, vmnet_enable_isolation_key, TRUE);
|
||||
}
|
||||
// Need NAT parameter parsing, TCP and UDP port allowances and setup
|
||||
}
|
||||
#endif /* defined(USE_VMNET_SHARED_AS_NAT) */
|
||||
#if defined(USE_VMNET_HOST_AS_TAP)
|
||||
if (0 == strncmp(savname, "tap:", 4)) {
|
||||
const char *tptr = savname + 4;
|
||||
unsigned char net_uuid[16];
|
||||
NAT nat;
|
||||
int err = 0;
|
||||
|
||||
memset(&nat, 0, sizeof(nat));
|
||||
xpc_dictionary_set_uint64(if_desc, vmnet_operation_mode_key, VMNET_HOST_MODE);
|
||||
tptr = get_glyph_nc (tptr, gbuf, ',');
|
||||
_eth_tap_uuid (gbuf, net_uuid);
|
||||
xpc_dictionary_set_uuid(if_desc, vmnet_network_identifier_key, net_uuid);
|
||||
if ((tptr != NULL) && (*tptr != '\0')) {
|
||||
err = sim_nat_parse_args (&nat, tptr, ETH_API_VMNET, (char *)errbuf, sizeof(errbuf));
|
||||
if (err != 0) {
|
||||
xpc_release(if_desc);
|
||||
snprintf (errbuf, errbuf_size, "Error parsing vmnet tap: device parameters");
|
||||
return SCPE_OPENERR;
|
||||
}
|
||||
if (nat.vgateway.s_addr != INADDR_ANY)
|
||||
hostaddr = strdup (inet_ntoa (nat.vgateway));
|
||||
if (nat.vnetmask.s_addr != INADDR_NONE)
|
||||
netmask = strdup (inet_ntoa (nat.vnetmask));
|
||||
if (((hostaddr != NULL) && (netmask == NULL)) ||
|
||||
((hostaddr == NULL) && (netmask != NULL))){
|
||||
free(hostaddr);
|
||||
free(endaddr);
|
||||
free(netmask);
|
||||
xpc_release(if_desc);
|
||||
snprintf (errbuf, errbuf_size, "Both the HOSTIP and MASKLEN must be specified together vmnet host (tap:) device");
|
||||
return SCPE_OPENERR;
|
||||
}
|
||||
if (hostaddr)
|
||||
xpc_dictionary_set_string(if_desc, vmnet_host_ip_address_key, hostaddr);
|
||||
if (netmask)
|
||||
xpc_dictionary_set_string(if_desc, vmnet_host_subnet_mask_key, netmask);
|
||||
}
|
||||
}
|
||||
#else /* !defined(USE_VMNET_HOST_AS_TAP) */
|
||||
if (0 == strncmp(savname, "tap:", 4)) {
|
||||
free(hostaddr);
|
||||
free(endaddr);
|
||||
free(netmask);
|
||||
strlcpy(errbuf, "No support for tap: devices", errbuf_size);
|
||||
return SCPE_OPENERR;
|
||||
}
|
||||
#endif /* !defined(USE_VMNET_HOST_AS_TAP) */
|
||||
if ((0 != strncmp(savname, "nat:", 4)) &&
|
||||
(0 != strncmp(savname, "tap:", 4))) {
|
||||
/* Try bridged, so check if we've got a reasonable device name */
|
||||
xpc_object_t interface_list = vmnet_copy_shared_interface_list();
|
||||
int i, interface_count = xpc_array_get_count(interface_list);
|
||||
|
||||
for (i=0; i<interface_count; i++) {
|
||||
xpc_object_t element = xpc_array_get_value(interface_list, i);
|
||||
|
||||
if (0 == strcmp(savname, xpc_string_get_string_ptr(element)))
|
||||
break;
|
||||
}
|
||||
if (i == interface_count) { /* Matching interface not found? */
|
||||
free(hostaddr);
|
||||
free(endaddr);
|
||||
free(netmask);
|
||||
xpc_release(if_desc);
|
||||
#if defined(USE_VMNET_HOST_AS_TAP)
|
||||
snprintf (errbuf, errbuf_size, "%s is not a valid network specification. You must specify either an appropriate vmnet bridged interface or a tap:", savname);
|
||||
#else /* !defined(USE_VMNET_HOST_AS_TAP) */
|
||||
snprintf (errbuf, errbuf_size, "%s is not a valid network specification. You must specify an appropriate vmnet bridged interface", savname);
|
||||
#endif /* !defined(USE_VMNET_HOST_AS_TAP) */
|
||||
return SCPE_OPENERR;
|
||||
}
|
||||
xpc_dictionary_set_uint64(if_desc, vmnet_operation_mode_key, VMNET_BRIDGED_MODE);
|
||||
xpc_dictionary_set_string(if_desc, vmnet_shared_interface_name_key, savname);
|
||||
}
|
||||
|
||||
vmn_queue = dispatch_get_global_queue(QOS_CLASS_UTILITY, 0);
|
||||
|
||||
_open_port_vmnet_cb_finished = dispatch_semaphore_create(0);
|
||||
_open_port_opaque = opaque;
|
||||
|
||||
vmn_interface = vmnet_start_interface(if_desc, vmn_queue, ^(vmnet_return_t status, xpc_object_t params)
|
||||
{
|
||||
_open_port_vmnet_status = status;
|
||||
if (status == VMNET_SUCCESS) {
|
||||
/* The logical device (bridge or otherwise) vmnet provides has its own MAC address which */
|
||||
/* becomes the host system's address from the simulator's point of view */
|
||||
if (SCPE_OK == eth_mac_scan (&((ETH_DEV*)_open_port_opaque)->host_nic_phy_hw_addr, xpc_dictionary_get_string(params, vmnet_mac_address_key)))
|
||||
((ETH_DEV*)_open_port_opaque)->have_host_nic_phy_addr = 1;
|
||||
}
|
||||
dispatch_semaphore_signal(_open_port_vmnet_cb_finished);
|
||||
});
|
||||
|
||||
dispatch_semaphore_wait(_open_port_vmnet_cb_finished, DISPATCH_TIME_FOREVER);
|
||||
dispatch_release(_open_port_vmnet_cb_finished);
|
||||
_open_port_vmnet_cb_finished = NULL;
|
||||
free(hostaddr);
|
||||
free(endaddr);
|
||||
free(netmask);
|
||||
xpc_release(if_desc);
|
||||
|
||||
if (_open_port_vmnet_status != VMNET_SUCCESS) {
|
||||
if (!_sim_running_as_root())
|
||||
snprintf (errbuf, errbuf_size, "Failed to create vmnet connection for %s - %s. You may need to run as root", savname, _vmnet_status_string(_open_port_vmnet_status));
|
||||
else
|
||||
snprintf (errbuf, errbuf_size, "Failed to create vmnet connection for %s - %s.", savname, _vmnet_status_string(_open_port_vmnet_status));
|
||||
return SCPE_OPENERR;
|
||||
}
|
||||
|
||||
*eth_api = ETH_API_VMNET;
|
||||
*handle = (void *)vmn_interface; /* Flag used to indicated open */
|
||||
return SCPE_OK;
|
||||
#else /* !defined(HAVE_VMNET_NETWORK) */
|
||||
if (0 == strncmp("vde:", savname, 4)) {
|
||||
#if defined(HAVE_VDE_NETWORK)
|
||||
if (eth_vde_network_available) {
|
||||
@ -3453,7 +3492,16 @@ static char version[300] = "";
|
||||
if (version[0] != '\0')
|
||||
return version;
|
||||
#if defined(HAVE_VMNET_NETWORK)
|
||||
strlcat (version, "PCAP(vmnet - bridged), TAP(vmnet - host)", sizeof (version));
|
||||
strlcat (version, "PCAP(vmnet - bridged)", sizeof (version));
|
||||
#if defined(USE_VMNET_HOST_AS_TAP)
|
||||
strlcat (version, ", TAP(vmnet - host)", sizeof (version));
|
||||
#else /* !defined(USE_VMNET_HOST_AS_TAP) */
|
||||
#if defined(HAVE_TAP_NETWORK)
|
||||
if (version[0] != '\0')
|
||||
strlcat (version, ", ", sizeof (version));
|
||||
strlcat (version, "TAP", sizeof (version));
|
||||
#endif
|
||||
#endif /* !defined(USE_VMNET_HOST_AS_TAP) */
|
||||
#if defined(USE_VMNET_SHARED_AS_NAT)
|
||||
strlcat (version, ", NAT(vmnet - shared), UDP", sizeof (version));
|
||||
#else /* !defined(USE_VMNET_SHARED_AS_NAT) */
|
||||
|
||||
@ -150,9 +150,12 @@ extern "C" {
|
||||
/* Generally avoid pcap APIs when running with vmnet.framework */
|
||||
#if defined(HAVE_VMNET_NETWORK)
|
||||
#define DONT_USE_PCAP_FINDALLDEVS 1
|
||||
#if !defined(DONT_USE_VMNET_HOST)
|
||||
#define USE_VMNET_HOST_AS_TAP 1
|
||||
#if defined(HAVE_TAP_NETWORK)
|
||||
#undef HAVE_TAP_NETWORK
|
||||
#endif
|
||||
#endif
|
||||
#if defined(HAVE_VDE_NETWORK)
|
||||
#undef HAVE_VDE_NETWORK
|
||||
#endif
|
||||
|
||||
@ -407,6 +407,7 @@ struct SEND {
|
||||
/* Private SCP only APIs */
|
||||
|
||||
t_stat _sim_os_putchar (int32 out);
|
||||
t_bool _sim_running_as_root (void);
|
||||
|
||||
|
||||
#endif /* defined(SIM_SCP_PRIVATE_DONT_REPEAT) */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user