ETHER,VAX,PDP11: Added UDP as a link type for Ethernet packet connectivity.

This will allow a single simulator to directly connect to HECnet systems without needing an external bridge program.
This commit is contained in:
Mark Pizzolato 2013-12-05 11:58:58 -08:00
parent c1aa85d944
commit 834e986eaf
5 changed files with 210 additions and 44 deletions

View file

@ -51,6 +51,8 @@ A remote console session will close when an EOF character is entered (i.e. ^D or
when connected to serial ports). when connected to serial ports).
DHU11 (device VH) on Unibus systems now has 16 ports per multiplexer. DHU11 (device VH) on Unibus systems now has 16 ports per multiplexer.
XQ devices (DEQNA, DELQA and DELQA-T) are bootable on Qbus PDP11 simulators XQ devices (DEQNA, DELQA and DELQA-T) are bootable on Qbus PDP11 simulators
XQ and XU devices (DEQNA, DELQA, DELQA-T, DEUNA and DELQA) devices can now
directly communicate to a remote device via UDP (i.e. a built-in HECnet bridge).
MicroVAX 3900 and MicroVAX II have SET CPU AUTOBOOT option MicroVAX 3900 and MicroVAX II have SET CPU AUTOBOOT option
MicroVAX 3900 has a SET CPU MODEL=(MicroVAX|VAXServer) command to change between system types MicroVAX 3900 has a SET CPU MODEL=(MicroVAX|VAXServer) command to change between system types
MicroVAX I has a SET CPU MODEL=(MicroVAX|VAXSTATION) command to change between system types MicroVAX I has a SET CPU MODEL=(MicroVAX|VAXSTATION) command to change between system types

View file

@ -1410,6 +1410,8 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, char *devname)
{ {
memset(&dev->host_nic_phy_hw_addr, 0, sizeof(dev->host_nic_phy_hw_addr)); memset(&dev->host_nic_phy_hw_addr, 0, sizeof(dev->host_nic_phy_hw_addr));
dev->have_host_nic_phy_addr = 0; dev->have_host_nic_phy_addr = 0;
if (dev->eth_api != ETH_API_PCAP)
return;
#if defined(_WIN32) || defined(__CYGWIN__) #if defined(_WIN32) || defined(__CYGWIN__)
if (!pcap_mac_if_win32(devname, dev->host_nic_phy_hw_addr)) if (!pcap_mac_if_win32(devname, dev->host_nic_phy_hw_addr))
dev->have_host_nic_phy_addr = 1; dev->have_host_nic_phy_addr = 1;
@ -1426,8 +1428,6 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, char *devname)
"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]", "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]",
NULL}; NULL};
if (0 == strncmp("vde:", devname, 4))
return;
memset(command, 0, sizeof(command)); memset(command, 0, sizeof(command));
for (i=0; patterns[i] && (0 == dev->have_host_nic_phy_addr); ++i) { for (i=0; patterns[i] && (0 == dev->have_host_nic_phy_addr); ++i) {
snprintf(command, sizeof(command)-1, "ifconfig %s | %s >NIC.hwaddr", devname, patterns[i]); snprintf(command, sizeof(command)-1, "ifconfig %s | %s >NIC.hwaddr", devname, patterns[i]);
@ -1484,12 +1484,12 @@ ETH_DEV* volatile dev = (ETH_DEV*)arg;
int status = 0; int status = 0;
int sched_policy; int sched_policy;
struct sched_param sched_priority; struct sched_param sched_priority;
#if defined (_WIN32)
HANDLE hWait = pcap_getevent ((pcap_t*)dev->handle);
#else
int sel_ret; int sel_ret;
int do_select = 0; int do_select = 0;
int select_fd = 0; SOCKET select_fd = 0;
#if defined (_WIN32)
HANDLE hWait = (dev->eth_api == ETH_API_PCAP) ? pcap_getevent ((pcap_t*)dev->handle) : NULL;
#endif
switch (dev->eth_api) { switch (dev->eth_api) {
case ETH_API_PCAP: case ETH_API_PCAP:
@ -1500,11 +1500,11 @@ switch (dev->eth_api) {
break; break;
case ETH_API_TAP: case ETH_API_TAP:
case ETH_API_VDE: case ETH_API_VDE:
case ETH_API_UDP:
do_select = 1; do_select = 1;
select_fd = dev->fd_handle; select_fd = dev->fd_handle;
break; break;
} }
#endif
sim_debug(dev->dbit, dev->dptr, "Reader Thread Starting\n"); sim_debug(dev->dbit, dev->dptr, "Reader Thread Starting\n");
@ -1515,10 +1515,15 @@ pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority);
++sched_priority.sched_priority; ++sched_priority.sched_priority;
pthread_setschedparam (pthread_self(), sched_policy, &sched_priority); pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
while (dev->handle) { while (dev->fd_handle) {
#if defined (_WIN32) #if defined (_WIN32)
if (WAIT_OBJECT_0 == WaitForSingleObject (hWait, 250)) { if (dev->eth_api == ETH_API_PCAP) {
#else if (WAIT_OBJECT_0 == WaitForSingleObject (hWait, 250))
sel_ret = 1;
}
if (dev->eth_api == ETH_API_UDP)
#endif /* _WIN32 */
if (1) {
fd_set setl; fd_set setl;
struct timeval timeout; struct timeval timeout;
@ -1532,9 +1537,9 @@ while (dev->handle) {
else else
sel_ret = 1; sel_ret = 1;
if (sel_ret < 0 && errno != EINTR) break; if (sel_ret < 0 && errno != EINTR) break;
}
if (sel_ret > 0) { if (sel_ret > 0) {
#endif /* _WIN32 */ if (!dev->fd_handle)
if (!dev->handle)
break; break;
/* dispatch read request queue available packets */ /* dispatch read request queue available packets */
switch (dev->eth_api) { switch (dev->eth_api) {
@ -1579,6 +1584,23 @@ while (dev->handle) {
} }
break; break;
#endif /* USE_VDE_NETWORK */ #endif /* USE_VDE_NETWORK */
case ETH_API_UDP:
if (1) {
struct pcap_pkthdr header;
int len;
u_char buf[ETH_MAX_JUMBO_FRAME];
memset(&header, 0, sizeof(header));
len = (int)sim_read_sock (select_fd, (char *)buf, (int32)sizeof(buf));
if (len > 0) {
status = 1;
header.caplen = header.len = len;
_eth_callback((u_char *)dev, &header, buf);
}
else
status = 0;
}
break;
} }
if ((status > 0) && (dev->asynch_io)) { if ((status > 0) && (dev->asynch_io)) {
int wakeup_needed; int wakeup_needed;
@ -1616,7 +1638,7 @@ 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); pthread_mutex_lock (&dev->writer_lock);
while (dev->handle) { while (dev->fd_handle) {
pthread_cond_wait (&dev->writer_cond, &dev->writer_lock); pthread_cond_wait (&dev->writer_cond, &dev->writer_lock);
while (NULL != (request = dev->write_requests)) { while (NULL != (request = dev->write_requests)) {
/* Pull buffer off request list */ /* Pull buffer off request list */
@ -1819,7 +1841,37 @@ else
} }
#else #else
strncpy(errbuf, "No support for vde: network devices", sizeof(errbuf)-1); strncpy(errbuf, "No support for vde: network devices", sizeof(errbuf)-1);
#endif /* !defined(__linux) && !defined(USE_BSDTUNTAP) */ #endif /* defined(USE_VDE_NETWORK) */
}
else {
if (0 == strncmp("udp:", savname, 4)) {
char localport[CBUFSIZE], host[CBUFSIZE], port[CBUFSIZE];
char hostport[2*CBUFSIZE];
if (!strcmp(savname, "udp:sourceport:remotehost:remoteport")) {
msg = "Eth: Must specify actual udp host and ports(i.e. udp:1224:somehost.com:2234)\r\n";
printf (msg, errbuf);
if (sim_log) fprintf (sim_log, msg, errbuf);
return SCPE_OPENERR;
}
if (SCPE_OK != sim_parse_addr_ex (savname+4, host, sizeof(host), "localhost", port, sizeof(port), localport, sizeof(localport), NULL))
return SCPE_OPENERR;
if (localport[0] == '\0')
strcpy (localport, port);
sprintf (hostport, "%s:%s", host, port);
if ((SCPE_OK == sim_parse_addr (hostport, NULL, 0, NULL, NULL, 0, NULL, "localhost")) &&
(0 == strcmp (localport, port))) {
msg = "Eth: Must specify different udp localhost ports\r\n";
printf (msg, errbuf);
if (sim_log) fprintf (sim_log, msg, errbuf);
return SCPE_OPENERR;
}
dev->fd_handle = sim_connect_sock_ex (localport, hostport, NULL, NULL, TRUE);
if (INVALID_SOCKET == dev->fd_handle)
return SCPE_OPENERR;
dev->eth_api = ETH_API_UDP;
} }
else { else {
dev->handle = (void*) pcap_open_live(savname, bufsz, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf); dev->handle = (void*) pcap_open_live(savname, bufsz, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
@ -1831,6 +1883,7 @@ else
} }
dev->eth_api = ETH_API_PCAP; dev->eth_api = ETH_API_PCAP;
} }
}
if (errbuf[0]) { if (errbuf[0]) {
msg = "Eth: open error - %s\r\n"; msg = "Eth: open error - %s\r\n";
printf (msg, errbuf); printf (msg, errbuf);
@ -1866,6 +1919,7 @@ if (1) {
pthread_attr_t attr; pthread_attr_t attr;
#if defined(_WIN32) #if defined(_WIN32)
if (dev->eth_api == ETH_API_PCAP)
pcap_setmintocopy (dev->handle, 0); pcap_setmintocopy (dev->handle, 0);
#endif #endif
ethq_init (&dev->read_queue, 200); /* initialize FIFO queue */ ethq_init (&dev->read_queue, 200); /* initialize FIFO queue */
@ -1918,7 +1972,7 @@ t_stat eth_close(ETH_DEV* dev)
{ {
char* msg = "Eth: closed %s\r\n"; char* msg = "Eth: closed %s\r\n";
pcap_t *pcap; pcap_t *pcap;
int pcap_fd; SOCKET pcap_fd;
/* make sure device exists */ /* make sure device exists */
if (!dev) return SCPE_UNATT; if (!dev) return SCPE_UNATT;
@ -1965,6 +2019,14 @@ switch (dev->eth_api) {
case ETH_API_VDE: case ETH_API_VDE:
vde_close((VDECONN*)pcap); vde_close((VDECONN*)pcap);
break; break;
#endif
case ETH_API_UDP:
sim_close_sock(pcap_fd, TRUE);
break;
#ifdef USE_SLIRP_NETWORK
case ETH_API_NAT:
vde_close((VDECONN*)pcap);
break;
#endif #endif
} }
printf (msg, dev->name); printf (msg, dev->name);
@ -2178,6 +2240,9 @@ if ((packet->len >= ETH_MIN_PACKET) && (packet->len <= ETH_MAX_PACKET)) {
status = 1; status = 1;
break; break;
#endif #endif
case ETH_API_UDP:
status = (((int32)packet->len == sim_write_sock (dev->fd_handle, (char *)packet->msg, (int32)packet->len)) ? 0 : -1);
break;
} }
++dev->packets_sent; /* basic bookkeeping */ ++dev->packets_sent; /* basic bookkeeping */
/* On error, correct loopback bookkeeping */ /* On error, correct loopback bookkeeping */
@ -2721,6 +2786,7 @@ switch (dev->eth_api) {
#endif /* USE_BPF */ #endif /* USE_BPF */
case ETH_API_TAP: case ETH_API_TAP:
case ETH_API_VDE: case ETH_API_VDE:
case ETH_API_UDP:
bpf_used = 0; bpf_used = 0;
to_me = 0; to_me = 0;
eth_packet_trace (dev, data, header->len, "received"); eth_packet_trace (dev, data, header->len, "received");
@ -2902,6 +2968,23 @@ do {
} }
break; break;
#endif /* USE_VDE_NETWORK */ #endif /* USE_VDE_NETWORK */
case ETH_API_UDP:
if (1) {
struct pcap_pkthdr header;
int len;
u_char buf[ETH_MAX_JUMBO_FRAME];
memset(&header, 0, sizeof(header));
len = (int)sim_read_sock (dev->fd_handle, buf, (int32)sizeof(buf));
if (len > 0) {
status = 1;
header.caplen = header.len = len;
_eth_callback((u_char *)dev, &header, buf);
}
else
status = 0;
}
break;
} }
} while ((status) && (0 == packet->len)); } while ((status) && (0 == packet->len));
@ -3225,6 +3308,20 @@ if (used < max) {
} }
#endif #endif
if (used < max) {
sprintf(list[used].name, "%s", "udp:sourceport:remotehost:remoteport");
sprintf(list[used].desc, "%s", "Integrated UDP bridge support");
++used;
}
#ifdef USE_SLIRP_NETWORK
if (used < max) {
sprintf(list[used].name, "%s", "nat:device");
sprintf(list[used].desc, "%s", "Integrated User Mode NAT support");
++used;
}
#endif
return used; return used;
} }

View file

@ -67,6 +67,7 @@
#define SIM_ETHER_H #define SIM_ETHER_H
#include "sim_defs.h" #include "sim_defs.h"
#include "sim_sock.h"
/* make common BSD code a bit easier to read in this file */ /* make common BSD code a bit easier to read in this file */
/* OS/X seems to define and compile using one of these BSD types */ /* OS/X seems to define and compile using one of these BSD types */
@ -212,11 +213,13 @@ typedef struct eth_item ETH_ITEM;
struct eth_device { struct eth_device {
char* name; /* name of ethernet device */ char* name; /* name of ethernet device */
void* handle; /* handle of implementation-specific device */ void* handle; /* handle of implementation-specific device */
int fd_handle; /* fd to kernel device (where needed) */ SOCKET fd_handle; /* fd to kernel device (where needed) */
int eth_api; /* Designator for which API is 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_PCAP 0 /* Pcap API in use */
#define ETH_API_TAP 1 /* tun/tap API in use */ #define ETH_API_TAP 1 /* tun/tap API in use */
#define ETH_API_VDE 2 /* VDE API in use */ #define ETH_API_VDE 2 /* VDE API in use */
#define ETH_API_UDP 3 /* UDP API in use */
#define ETH_API_NAT 4 /* NAT (SLiRP) API in use */
ETH_PCALLBACK read_callback; /* read callback function */ ETH_PCALLBACK read_callback; /* read callback function */
ETH_PCALLBACK write_callback; /* write callback function */ ETH_PCALLBACK write_callback; /* write callback function */
ETH_PACK* read_packet; /* read packet */ ETH_PACK* read_packet; /* read packet */

View file

@ -551,12 +551,19 @@ char *hostp, *portp;
char *endc; char *endc;
unsigned long portval; unsigned long portval;
if ((cptr == NULL) || (*cptr == 0))
return SCPE_ARG;
if ((host != NULL) && (host_len != 0)) if ((host != NULL) && (host_len != 0))
memset (host, 0, host_len); memset (host, 0, host_len);
if ((port != NULL) && (port_len != 0)) if ((port != NULL) && (port_len != 0))
memset (port, 0, port_len); memset (port, 0, port_len);
if ((cptr == NULL) || (*cptr == 0)) {
if (((default_host == NULL) || (*default_host == 0)) && ((default_port == NULL) || (*default_port == 0)))
return SCPE_ARG;
if ((strlen(default_host) >= host_len) || (strlen(default_port) >= port_len))
return SCPE_ARG; /* no room */
strcpy (host, default_host);
strcpy (port, default_port);
return SCPE_OK;
}
gbuf[sizeof(gbuf)-1] = '\0'; gbuf[sizeof(gbuf)-1] = '\0';
strncpy (gbuf, cptr, sizeof(gbuf)-1); strncpy (gbuf, cptr, sizeof(gbuf)-1);
hostp = gbuf; /* default addr */ hostp = gbuf; /* default addr */
@ -622,7 +629,7 @@ if (host) { /* host wanted? */
} }
} }
if (validate_addr) { if (validate_addr) {
struct addrinfo *ai_host, *ai_validate, *ai; struct addrinfo *ai_host, *ai_validate, *ai, *aiv;
t_stat status; t_stat status;
if (hostp == NULL) if (hostp == NULL)
@ -635,13 +642,15 @@ if (validate_addr) {
} }
status = SCPE_ARG; status = SCPE_ARG;
for (ai = ai_host; ai != NULL; ai = ai->ai_next) { for (ai = ai_host; ai != NULL; ai = ai->ai_next) {
if ((ai->ai_addrlen == ai_validate->ai_addrlen) && for (aiv = ai_validate; aiv != NULL; aiv = aiv->ai_next) {
(ai->ai_family == ai_validate->ai_family) && if ((ai->ai_addrlen == aiv->ai_addrlen) &&
(0 == memcmp (ai->ai_addr, ai_validate->ai_addr, ai->ai_addrlen))) { (ai->ai_family == aiv->ai_family) &&
(0 == memcmp (ai->ai_addr, aiv->ai_addr, ai->ai_addrlen))) {
status = SCPE_OK; status = SCPE_OK;
break; break;
} }
} }
}
if (status != SCPE_OK) { if (status != SCPE_OK) {
/* be generous and allow successful validations against variations of localhost addresses */ /* be generous and allow successful validations against variations of localhost addresses */
if (((0 == strcmp("127.0.0.1", hostp)) && if (((0 == strcmp("127.0.0.1", hostp)) &&
@ -657,6 +666,60 @@ if (validate_addr) {
return SCPE_OK; return SCPE_OK;
} }
/* sim_parse_addr_ex localport:host:port
Presumption is that the input, if it doesn't contain a ':' character is a port specifier.
If the host field contains one or more colon characters (i.e. it is an IPv6 address),
the IPv6 address MUST be enclosed in square bracket characters (i.e. Domain Literal format)
llll:w.x.y.z:rrrr
llll:name.domain.com:rrrr
llll::rrrr
rrrr
w.x.y.z:rrrr
[w.x.y.z]:rrrr
name.domain.com:rrrr
Inputs:
cptr = pointer to input string
default_host
= optional pointer to default host if none specified
host_len = length of host buffer
default_port
= optional pointer to default port if none specified
port_len = length of port buffer
Outputs:
host = pointer to buffer for IP address (may be NULL), 0 = none
port = pointer to buffer for IP port (may be NULL), 0 = none
localport
= pointer to buffer for local IP port (may be NULL), 0 = none
result = status (SCPE_OK on complete success or SCPE_ARG if
parsing can't happen due to bad syntax, a value is
out of range, a result can't fit into a result buffer,
a service name doesn't exist, or a validation name
doesn't match the parsed host)
*/
t_stat sim_parse_addr_ex (const char *cptr, char *host, size_t hostlen, const char *default_host, char *port, size_t port_len, char *localport, size_t localport_len, const char *default_port)
{
char *hostp;
if ((localport != NULL) && (localport_len != 0))
memset (localport, 0, localport_len);
hostp = strchr (cptr, ':');
if ((hostp != NULL) && ((hostp[1] == '[') || (NULL != strchr (hostp+1, ':')))) {
if ((localport != NULL) && (localport_len != 0)) {
localport_len -= 1;
if (localport_len > (size_t)(hostp-cptr))
localport_len = (size_t)(hostp-cptr);
memcpy (localport, cptr, localport_len);
}
return sim_parse_addr (hostp+1, host, hostlen, default_host, port, port_len, default_port, NULL);
}
return sim_parse_addr (cptr, host, hostlen, default_host, port, port_len, default_port, NULL);
}
void sim_init_sock (void) void sim_init_sock (void)
{ {
#if defined (_WIN32) #if defined (_WIN32)

View file

@ -102,6 +102,7 @@
#endif #endif
t_stat sim_parse_addr (const char *cptr, char *host, size_t hostlen, const char *default_host, char *port, size_t port_len, const char *default_port, const char *validate_addr); t_stat sim_parse_addr (const char *cptr, char *host, size_t hostlen, const char *default_host, char *port, size_t port_len, const char *default_port, const char *validate_addr);
t_stat sim_parse_addr_ex (const char *cptr, char *host, size_t hostlen, const char *default_host, char *port, size_t port_len, char *localport, size_t local_port_len, const char *default_port);
SOCKET sim_master_sock (const char *hostport, t_stat *parse_status); SOCKET sim_master_sock (const char *hostport, t_stat *parse_status);
SOCKET sim_connect_sock (const char *hostport, const char *default_host, const char *default_port); SOCKET sim_connect_sock (const char *hostport, const char *default_host, const char *default_port);
SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, t_bool datagram); SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, t_bool datagram);