1
0
mirror of https://github.com/open-simh/simh.git synced 2026-01-25 19:57:36 +00:00

all VAX, PDP11: Add initial NAT based ethernet connectivity via SLiRP.

This should work on all byte addressable host systems using GCC/clang to build.

The QEMU slirp code has been pried out of QEMU and stubs have been created to solve where the current slirp is entangled with the QEMU code.  Ths slirp/simh directory contains all the necessary include and glue files to make this useful.  Everything in the slirp directory is unmodified QEMU code.
This commit is contained in:
Mark Pizzolato
2015-10-15 12:59:32 -07:00
parent e4cf98c4c0
commit 86d1e36f29
80 changed files with 17025 additions and 95 deletions

View File

@@ -150,6 +150,9 @@
specified at open time. This functionality is only
available on *nix platforms since the vde api isn't
available on Windows.
HAVE_SLIRP_NETWORK- Specifies that support for SLiRP networking should be
included. This can be leveraged to provide User Mode
IP NAT connectivity for simulators.
NEED_PCAP_SENDPACKET
- Specifies that you are using an older version of libpcap
@@ -884,7 +887,7 @@ void eth_show_dev (FILE* st, ETH_DEV* dev)
const char *eth_capabilities(void)
{
return "Ethernet Packet transport"
return "Ethernet Packet transports"
#if defined (HAVE_PCAP_NETWORK)
":PCAP"
#endif
@@ -893,6 +896,9 @@ const char *eth_capabilities(void)
#endif
#if defined (HAVE_VDE_NETWORK)
":VDE"
#endif
#if defined (HAVE_SLIRP_NETWORK)
":NAT"
#endif
":UDP";
}
@@ -938,6 +944,10 @@ typedef void * pcap_t; /* Pseudo Type to avoid compiler errors */
#include <libvdeplug.h>
#endif /* HAVE_VDE_NETWORK */
#ifdef HAVE_SLIRP_NETWORK
#include "sim_slirp.h"
#endif /* HAVE_SLIRP_NETWORK */
/* Allows windows to look up user-defined adapter names */
#if defined(_WIN32)
#include <winreg.h>
@@ -1495,6 +1505,17 @@ _eth_write(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine);
static void
_eth_error(ETH_DEV* dev, const char* where);
#if defined(HAVE_SLIRP_NETWORK)
static void _slirp_callback (void *opaque, const unsigned char *buf, int len)
{
struct pcap_pkthdr header;
memset(&header, 0, sizeof(header));
header.caplen = header.len = len;
_eth_callback((u_char *)opaque, &header, buf);
}
#endif
#if defined (USE_READER_THREAD)
#include <pthread.h>
@@ -1524,6 +1545,7 @@ switch (dev->eth_api) {
case ETH_API_TAP:
case ETH_API_VDE:
case ETH_API_UDP:
case ETH_API_NAT:
do_select = 1;
select_fd = dev->fd_handle;
break;
@@ -1532,8 +1554,8 @@ switch (dev->eth_api) {
sim_debug(dev->dbit, dev->dptr, "Reader Thread Starting\n");
/* Boost Priority for this I/O thread vs the CPU instruction execution
thread which in general won't be readily yielding the processor when
this thread needs to run */
thread which, in general, won't be readily yielding the processor
when this thread needs to run */
pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority);
++sched_priority.sched_priority;
pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
@@ -1544,22 +1566,31 @@ while (dev->handle) {
if (WAIT_OBJECT_0 == WaitForSingleObject (hWait, 250))
sel_ret = 1;
}
if (dev->eth_api == ETH_API_UDP)
if ((dev->eth_api == ETH_API_UDP) || (dev->eth_api == ETH_API_NAT))
#endif /* _WIN32 */
if (1) {
fd_set setl;
struct timeval timeout;
if (do_select) {
FD_ZERO(&setl);
FD_SET(select_fd, &setl);
timeout.tv_sec = 0;
timeout.tv_usec = 250*1000;
sel_ret = select(1+select_fd, &setl, NULL, NULL, &timeout);
#ifdef HAVE_SLIRP_NETWORK
if (dev->eth_api == ETH_API_NAT) {
sel_ret = sim_slirp_select ((SLIRP*)dev->handle, 250);
}
else
#endif
{
fd_set setl;
struct timeval timeout;
FD_ZERO(&setl);
FD_SET(select_fd, &setl);
timeout.tv_sec = 0;
timeout.tv_usec = 250*1000;
sel_ret = select(1+select_fd, &setl, NULL, NULL, &timeout);
}
}
else
sel_ret = 1;
if (sel_ret < 0 && errno != EINTR) break;
if (sel_ret < 0 && errno != EINTR)
break;
}
if (sel_ret > 0) {
if (!dev->handle)
@@ -1617,6 +1648,11 @@ while (dev->handle) {
}
break;
#endif /* HAVE_VDE_NETWORK */
#ifdef HAVE_SLIRP_NETWORK
case ETH_API_NAT:
sim_slirp_dispatch ((SLIRP*)dev->handle);
break;
#endif /* HAVE_SLIRP_NETWORK */
case ETH_API_UDP:
if (1) {
struct pcap_pkthdr header;
@@ -1769,7 +1805,7 @@ dev->throttle_mask = (1 << dev->throttle_burst) - 1;
return SCPE_OK;
}
static t_stat _eth_open_port(char *savname, int *eth_api, void **handle, SOCKET *fd_handle, char errbuf[PCAP_ERRBUF_SIZE], char *bpf_filter)
static t_stat _eth_open_port(char *savname, int *eth_api, void **handle, SOCKET *fd_handle, char errbuf[PCAP_ERRBUF_SIZE], char *bpf_filter, void *opaque)
{
int bufsz = (BUFSIZ < ETH_MAX_PACKET) ? ETH_MAX_PACKET : BUFSIZ;
@@ -1789,7 +1825,7 @@ if (0 == strncmp("tap:", savname, 4)) {
#if defined(HAVE_TAP_NETWORK)
if (!strcmp(savname, "tap:tapN")) {
sim_printf ("Eth: Must specify actual tap device name (i.e. tap:tap0)\r\n");
return SCPE_OPENERR;
return SCPE_OPENERR | SCPE_NOMESSAGE;
}
#endif
#if (defined(__linux) || defined(__linux__)) && defined(HAVE_TAP_NETWORK)
@@ -1865,7 +1901,7 @@ if (0 == strncmp("tap:", savname, 4)) {
*handle = (void *)1; /* Flag used to indicated open */
}
}
else
else { /* !tap: */
if (0 == strncmp("vde:", savname, 4)) {
#if defined(HAVE_VDE_NETWORK)
struct vde_open_args voa;
@@ -1873,7 +1909,7 @@ else
memset(&voa, 0, sizeof(voa));
if (!strcmp(savname, "vde:vdedevice")) {
sim_printf ("Eth: Must specify actual vde device name (i.e. vde:/tmp/switch)\r\n");
return SCPE_OPENERR;
return SCPE_OPENERR | SCPE_NOMESSAGE;
}
if (!(*handle = (void*) vde_open(savname+4, "simh", &voa)))
strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1);
@@ -1885,76 +1921,91 @@ else
strncpy(errbuf, "No support for vde: network devices", PCAP_ERRBUF_SIZE-1);
#endif /* defined(HAVE_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")) {
sim_printf ("Eth: Must specify actual udp host and ports(i.e. udp:1224:somehost.com:2234)\r\n");
return SCPE_OPENERR;
else { /* !vde: */
if (0 == strncmp("nat:", savname, 4)) {
#if defined(HAVE_SLIRP_NETWORK)
if (!(*handle = (void*) sim_slirp_open(savname+4, opaque, &_slirp_callback)))
strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1);
else {
*eth_api = ETH_API_NAT;
*fd_handle = 0;
}
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))) {
sim_printf ("Eth: Must specify different udp localhost ports\r\n");
return SCPE_OPENERR;
}
*fd_handle = sim_connect_sock_ex (localport, hostport, NULL, NULL, SIM_SOCK_OPT_DATAGRAM);
if (INVALID_SOCKET == *fd_handle)
return SCPE_OPENERR;
*eth_api = ETH_API_UDP;
*handle = (void *)1; /* Flag used to indicated open */
#else
strncpy(errbuf, "No support for nat: network devices", PCAP_ERRBUF_SIZE-1);
#endif /* defined(HAVE_SLIRP_NETWORK) */
}
else {
else { /* not nat: */
if (0 == strncmp("udp:", savname, 4)) {
char localport[CBUFSIZE], host[CBUFSIZE], port[CBUFSIZE];
char hostport[2*CBUFSIZE];
if (!strcmp(savname, "udp:sourceport:remotehost:remoteport")) {
sim_printf ("Eth: Must specify actual udp host and ports(i.e. udp:1224:somehost.com:2234)\r\n");
return SCPE_OPENERR | SCPE_NOMESSAGE;
}
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))) {
sim_printf ("Eth: Must specify different udp localhost ports\r\n");
return SCPE_OPENERR | SCPE_NOMESSAGE;
}
*fd_handle = sim_connect_sock_ex (localport, hostport, NULL, NULL, SIM_SOCK_OPT_DATAGRAM);
if (INVALID_SOCKET == *fd_handle)
return SCPE_OPENERR;
*eth_api = ETH_API_UDP;
*handle = (void *)1; /* Flag used to indicated open */
}
else { /* not udp:, so attempt to open the parameter as if it were an explicit device name */
#if defined(HAVE_PCAP_NETWORK)
*handle = (void*) pcap_open_live(savname, bufsz, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
if (!*handle) { /* can't open device */
sim_printf ("Eth: pcap_open_live error - %s\r\n", errbuf);
return SCPE_OPENERR;
}
*eth_api = ETH_API_PCAP;
*handle = (void*) pcap_open_live(savname, bufsz, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
if (!*handle) { /* can't open device */
sim_printf ("Eth: pcap_open_live error - %s\r\n", errbuf);
return SCPE_OPENERR | SCPE_NOMESSAGE;
}
*eth_api = ETH_API_PCAP;
#if !defined(HAS_PCAP_SENDPACKET) && defined (xBSD) && !defined (__APPLE__)
/* Tell the kernel that the header is fully-formed when it gets it.
This is required in order to fake the src address. */
if (1) {
int one = 1;
ioctl(pcap_fileno(*handle), BIOCSHDRCMPLT, &one);
}
/* Tell the kernel that the header is fully-formed when it gets it.
This is required in order to fake the src address. */
if (1) {
int one = 1;
ioctl(pcap_fileno(*handle), BIOCSHDRCMPLT, &one);
}
#endif /* xBSD */
#if defined(_WIN32)
pcap_setmintocopy ((pcap_t*)(*handle), 0);
pcap_setmintocopy ((pcap_t*)(*handle), 0);
#endif
#if !defined (USE_READER_THREAD)
#ifdef USE_SETNONBLOCK
/* set ethernet device non-blocking so pcap_dispatch() doesn't hang */
if (pcap_setnonblock (*handle, 1, errbuf) == -1) {
sim_printf ("Eth: Failed to set non-blocking: %s\r\n", errbuf);
}
/* set ethernet device non-blocking so pcap_dispatch() doesn't hang */
if (pcap_setnonblock (*handle, 1, errbuf) == -1) {
sim_printf ("Eth: Failed to set non-blocking: %s\r\n", errbuf);
}
#endif
#if defined (__APPLE__)
if (1) {
/* Deliver packets immediately, needed for OS X 10.6.2 and later
* (Snow-Leopard).
* See this thread on libpcap and Mac Os X 10.6 Snow Leopard on
* the tcpdump mailinglist: http://seclists.org/tcpdump/2010/q1/110
*/
int v = 1;
ioctl(pcap_fileno(*handle), BIOCIMMEDIATE, &v);
}
if (1) {
/* Deliver packets immediately, needed for OS X 10.6.2 and later
* (Snow-Leopard).
* See this thread on libpcap and Mac Os X 10.6 Snow Leopard on
* the tcpdump mailinglist: http://seclists.org/tcpdump/2010/q1/110
*/
int v = 1;
ioctl(pcap_fileno(*handle), BIOCIMMEDIATE, &v);
}
#endif /* defined (__APPLE__) */
#endif /* !defined (USE_READER_THREAD) */
#else
strncpy (errbuf, "Unknown or unsupported network device", PCAP_ERRBUF_SIZE-1);
strncpy (errbuf, "Unknown or unsupported network device", PCAP_ERRBUF_SIZE-1);
#endif /* defined(HAVE_PCAP_NETWORK) */
}
}
} /* not udp:, so attempt to open the parameter as if it were an explicit device name */
} /* !nat: */
} /* !vde: */
} /* !tap: */
if (errbuf[0])
return SCPE_OPENERR;
@@ -2030,11 +2081,11 @@ else {
}
}
r = _eth_open_port(savname, &dev->eth_api, &dev->handle, &dev->fd_handle, errbuf, NULL);
r = _eth_open_port(savname, &dev->eth_api, &dev->handle, &dev->fd_handle, errbuf, NULL, (void *)dev);
if (errbuf[0]) {
sim_printf ("Eth: open error - %s\r\n", errbuf);
return SCPE_OPENERR;
return SCPE_OPENERR | SCPE_NOMESSAGE;
}
if (r != SCPE_OK)
return r;
@@ -2099,15 +2150,15 @@ switch (eth_api) {
case ETH_API_VDE:
vde_close((VDECONN*)pcap);
break;
#endif
#ifdef HAVE_SLIRP_NETWORK
case ETH_API_NAT:
sim_slirp_close((SLIRP*)pcap);
break;
#endif
case ETH_API_UDP:
sim_close_sock(pcap_fd);
break;
#ifdef USE_SLIRP_NETWORK
case ETH_API_NAT:
vde_close((VDECONN*)pcap);
break;
#endif
}
return SCPE_OK;
}
@@ -2166,11 +2217,23 @@ fprintf (st, "%s attach help\n\n", dptr->name);
fprintf (st, " sim> SHOW ETHERNET\n");
fprintf (st, " libpcap version 1.0.0\n");
fprintf (st, " ETH devices:\n");
fprintf (st, " eth0 en0 (No description available)\n");
fprintf (st, " eth1 tap:tapN (Integrated Tun/Tap support)\n");
fprintf (st, " eth0 en0 (No description available)\n");
#if defined(HAVE_TAP_NETWORK)
fprintf (st, " eth1 tap:tapN (Integrated Tun/Tap support)\n");
#endif
#if defined(HAVE_SLIRP_NETWORK)
fprintf (st, " eth2 vde:device (Integrated VDE support)\n");
#endif
#if defined(HAVE_SLIRP_NETWORK)
fprintf (st, " eth3 nat:{optional-nat-parameters} (Integrated NAT (SLiRP) support)\n");
#endif
fprintf (st, " eth4 udp:sourceport:remotehost:remoteport (Integrated UDP bridge support)\n");
fprintf (st, " sim> ATTACH %s eth0\n\n", dptr->name);
fprintf (st, "or equivalently:\n\n");
fprintf (st, " sim> ATTACH %s en0\n\n", dptr->name);
#if defined(HAVE_SLIRP_NETWORK)
sim_slirp_attach_help (st, dptr, uptr, flag, cptr);
#endif
return SCPE_OK;
}
@@ -2399,7 +2462,7 @@ if (dev->error_needs_reset) {
_eth_close_port(dev->eth_api, (pcap_t *)dev->handle, dev->fd_handle);
sim_os_sleep (ETH_ERROR_REOPEN_PAUSE);
r = _eth_open_port(dev->name, &dev->eth_api, &dev->handle, &dev->fd_handle, errbuf, dev->bpf_filter);
r = _eth_open_port(dev->name, &dev->eth_api, &dev->handle, &dev->fd_handle, errbuf, dev->bpf_filter, (void *)dev);
dev->error_needs_reset = FALSE;
if (r == SCPE_OK)
sim_printf ("%s ReOpened: %s \n", msg, dev->name);
@@ -2473,6 +2536,15 @@ if ((packet->len >= ETH_MIN_PACKET) && (packet->len <= ETH_MAX_PACKET)) {
else
status = 1;
break;
#endif
#ifdef HAVE_SLIRP_NETWORK
case ETH_API_NAT:
status = sim_slirp_send((SLIRP*)dev->handle, (char *)packet->msg, (size_t)packet->len, 0);
if ((status == (int)packet->len) || (status == 0))
status = 0;
else
status = 1;
break;
#endif
case ETH_API_UDP:
status = (((int32)packet->len == sim_write_sock (dev->fd_handle, (char *)packet->msg, (int32)packet->len)) ? 0 : -1);
@@ -3086,6 +3158,7 @@ switch (dev->eth_api) {
case ETH_API_TAP:
case ETH_API_VDE:
case ETH_API_UDP:
case ETH_API_NAT:
bpf_used = 0;
to_me = 0;
eth_packet_trace (dev, data, header->len, "received");
@@ -3130,7 +3203,7 @@ if ((LOOPBACK_SELF_FRAME(dev->physical_addr, data)) ||
#ifdef USE_READER_THREAD
pthread_mutex_unlock (&dev->self_lock);
#endif
}
}
if (bpf_used ? to_me : (to_me && !from_me)) {
if (header->len > ETH_MIN_JUMBO_FRAME) {
@@ -3623,6 +3696,13 @@ if (used < max) {
++used;
}
#endif
#ifdef HAVE_SLIRP_NETWORK
if (used < max) {
sprintf(list[used].name, "%s", "nat:{optional-nat-parameters}");
sprintf(list[used].desc, "%s", "Integrated NAT (SLiRP) support");
++used;
}
#endif
if (used < max) {
sprintf(list[used].name, "%s", "udp:sourceport:remotehost:remoteport");
@@ -3630,14 +3710,6 @@ if (used < max) {
++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;
}
@@ -3731,5 +3803,9 @@ fprintf(st, " Peak Write Queue Size: %d\n", dev->write_queue_peak);
#endif
if (dev->bpf_filter)
fprintf(st, " BPF Filter: %s\n", dev->bpf_filter);
#if defined(HAVE_SLIRP_NETWORK)
if (dev->eth_api == ETH_API_NAT)
sim_slirp_show ((SLIRP *)dev->handle, st);
#endif
}
#endif /* USE_NETWORK */