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:
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) */
|
||||
|
||||
Reference in New Issue
Block a user