1
0
mirror of https://github.com/simh/simh.git synced 2026-01-30 05:25:16 +00:00

ETHER: Add vmnet support for macOS Catalina 10.15.7 through Big Sur 11.7.10

This commit is contained in:
Mark Pizzolato
2025-08-14 08:55:49 -10:00
parent df31a5b7f9
commit caea0c0970
6 changed files with 297 additions and 215 deletions

View File

@@ -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) */