1
0
mirror of https://github.com/simh/simh.git synced 2026-03-02 17:55:17 +00:00

ETHER, CARD, SOCK: Include shared components from V4 codebase

This commit is contained in:
Mark Pizzolato
2022-05-16 03:10:18 -07:00
parent 8c31bb08e3
commit 9b2899cfef
6 changed files with 335 additions and 95 deletions

View File

@@ -1470,7 +1470,7 @@ return SCPE_OK;
#include <setjmp.h>
t_stat sim_card_test (DEVICE *dptr)
t_stat sim_card_test (DEVICE *dptr, const char *cptr)
{
t_stat stat = SCPE_OK;
#if defined(USE_SIM_CARD) && defined(SIM_CARD_API) && (SIM_MAJOR > 3)
@@ -1536,7 +1536,7 @@ t_stat sim_card_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, cons
return SCPE_OK;
}
t_stat sim_card_test (DEVICE *dptr)
t_stat sim_card_test (DEVICE *dptr, const char *cptr)
{
return SCPE_OK;
}

View File

@@ -145,7 +145,7 @@ extern const char sim_ascii_to_six[128]; /* Map 7 bit ASCII to BCD */
extern const uint8 sim_parity_table[64]; /* 64 entry odd parity table */
/* Unit test routine */
extern t_stat sim_card_test (DEVICE *dptr);
extern t_stat sim_card_test (DEVICE *dptr, const char *cptr);
#ifdef __cplusplus
}

View File

@@ -383,6 +383,9 @@
/* Internal routine - forward declaration */
static int _eth_get_system_id (char *buf, size_t buf_size);
static void eth_get_nic_hw_addr(ETH_DEV* dev, const char *devname, int set_on);
static const unsigned char framer_oui[3] = { 0xaa, 0x00, 0x03 };
/*============================================================================*/
/* OS-independant ethernet routines */
@@ -780,13 +783,11 @@ return eth_show (st, uptr, val, NULL);
}
#if defined (USE_NETWORK) || defined (USE_SHARED)
/* Internal routine - forward declaration */
static int _eth_devices (int max, ETH_LIST* dev); /* get ethernet devices on host */
static const char* _eth_getname(int number, char* name, char *desc)
{
ETH_LIST list[ETH_MAX_DEVICE];
int count = _eth_devices(ETH_MAX_DEVICE, list);
int count = eth_devices(ETH_MAX_DEVICE, list, FALSE);
if ((number < 0) || (count <= number))
return NULL;
@@ -803,7 +804,7 @@ static const char* _eth_getname(int number, char* name, char *desc)
const char* eth_getname_bydesc(const char* desc, char* name, char *ndesc)
{
ETH_LIST list[ETH_MAX_DEVICE];
int count = _eth_devices(ETH_MAX_DEVICE, list);
int count = eth_devices(ETH_MAX_DEVICE, list, FALSE);
int i;
size_t j=strlen(desc);
@@ -829,7 +830,7 @@ const char* eth_getname_bydesc(const char* desc, char* name, char *ndesc)
char* eth_getname_byname(const char* name, char* temp, char *desc)
{
ETH_LIST list[ETH_MAX_DEVICE];
int count = _eth_devices(ETH_MAX_DEVICE, list);
int count = eth_devices(ETH_MAX_DEVICE, list, FALSE);
size_t n;
int i, found;
@@ -849,7 +850,7 @@ char* eth_getname_byname(const char* name, char* temp, char *desc)
char* eth_getdesc_byname(char* name, char* temp)
{
ETH_LIST list[ETH_MAX_DEVICE];
int count = _eth_devices(ETH_MAX_DEVICE, list);
int count = eth_devices(ETH_MAX_DEVICE, list, FALSE);
size_t n;
int i, found;
@@ -868,7 +869,7 @@ char* eth_getdesc_byname(char* name, char* temp)
static ETH_DEV **eth_open_devices = NULL;
static int eth_open_device_count = 0;
static char* (*p_pcap_lib_version) (void);
static char *(*p_pcap_lib_version) (void);
static void _eth_add_to_open_list (ETH_DEV* dev)
{
@@ -894,7 +895,7 @@ t_stat eth_show (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
ETH_LIST list[ETH_MAX_DEVICE];
int number;
number = _eth_devices(ETH_MAX_DEVICE, list);
number = eth_devices(ETH_MAX_DEVICE, list, FALSE);
fprintf(st, "ETH devices:\n");
if (number == -1)
fprintf(st, " network support not available in simulator\n");
@@ -965,6 +966,8 @@ t_stat eth_filter_hash (ETH_DEV* dev, int addr_count, ETH_MAC* const addresses,
{return SCPE_NOFNC;}
const char *eth_version (void)
{return NULL;}
int eth_devices(int max, ETH_LIST* list, ETH_BOOL framers)
{return 0;}
void eth_show_dev (FILE* st, ETH_DEV* dev)
{}
t_stat eth_show (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
@@ -975,7 +978,7 @@ t_stat eth_show (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
}
static int _eth_get_system_id (char *buf, size_t buf_size)
{memset (buf, 0, buf_size); return 0;}
t_stat sim_ether_test (DEVICE *dptr)
t_stat sim_ether_test (DEVICE *dptr, const char *cptr)
{return SCPE_OK;}
#else /* endif unimplemented */
@@ -1046,12 +1049,13 @@ typedef void * pcap_t; /* Pseudo Type to avoid compiler errors */
*/
static int eth_host_pcap_devices(int used, int max, ETH_LIST* list)
{
pcap_t* conn = NULL;
int i, j, datalink = 0;
int i;
for (i=0; i<used; ++i) {
/* Cull any non-ethernet interface types */
#if defined(HAVE_PCAP_NETWORK)
int j, datalink = 0;
pcap_t* conn = NULL;
char errbuf[PCAP_ERRBUF_SIZE];
conn = pcap_open_live(list[i].name, ETH_MAX_PACKET, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
@@ -1111,13 +1115,14 @@ for (i=0; i<used; i++) {
return used;
}
static int _eth_devices(int max, ETH_LIST* list)
int eth_devices(int max, ETH_LIST* list, ETH_BOOL framers)
{
int used = 0;
char errbuf[PCAP_ERRBUF_SIZE] = "";
#ifndef DONT_USE_PCAP_FINDALLDEVS
pcap_if_t* alldevs;
pcap_if_t* dev;
ETH_DEV edev;
memset(list, 0, max*sizeof(*list));
errbuf[0] = '\0';
@@ -1128,7 +1133,11 @@ if (pcap_findalldevs(&alldevs, errbuf) == -1) {
}
else {
/* copy device list into the passed structure */
for (used=0, dev=alldevs; dev && (used < max); dev=dev->next, ++used) {
for (used=0, dev=alldevs; dev && (used < max); dev=dev->next) {
edev.eth_api = ETH_API_PCAP;
eth_get_nic_hw_addr (&edev, dev->name, 0);
if ((memcmp (edev.host_nic_phy_hw_addr, framer_oui, 3) == 0) != framers)
continue;
if ((dev->flags & PCAP_IF_LOOPBACK) || (!strcmp("any", dev->name)))
continue;
strlcpy(list[used].name, dev->name, sizeof(list[used].name));
@@ -1136,6 +1145,7 @@ else {
strlcpy(list[used].desc, dev->description, sizeof(list[used].desc));
else
strlcpy(list[used].desc, "No description available", sizeof(list[used].desc));
++used;
}
/* free device list */
@@ -1151,6 +1161,9 @@ if ((used == 0) && (errbuf[0])) {
sim_printf ("Eth: pcap_findalldevs warning: %s\n", errbuf);
}
if (framers)
return used; /* don't add pseudo-ethernet devices */
#ifdef HAVE_TAP_NETWORK
if (used < max) {
#if defined(__OpenBSD__)
@@ -1224,11 +1237,11 @@ extern "C" {
#include <winreg.h>
#endif
#ifdef HAVE_DLOPEN
#ifdef SIM_HAVE_DLOPEN
#include <dlfcn.h>
#endif
#if defined(USE_SHARED) && (defined(_WIN32) || defined(HAVE_DLOPEN))
#if defined(USE_SHARED) && (defined(_WIN32) || defined(SIM_HAVE_DLOPEN))
/* Dynamic DLL loading technique and modified source comes from
Etherial/WireShark capture_pcap.c */
@@ -1248,7 +1261,7 @@ static const char* lib_name =
#elif defined(__APPLE__)
"/usr/lib/libpcap.A.dylib";
#else
"libpcap." __STR(HAVE_DLOPEN);
"libpcap." __STR(SIM_HAVE_DLOPEN);
#endif
static char no_pcap[PCAP_ERRBUF_SIZE] =
@@ -1257,7 +1270,7 @@ static char no_pcap[PCAP_ERRBUF_SIZE] =
#elif defined(__APPLE__)
"/usr/lib/libpcap.A.dylib failed to load, install libpcap to use pcap networking";
#else
"libpcap." __STR(HAVE_DLOPEN) " failed to load, install libpcap to use pcap networking";
"libpcap." __STR(SIM_HAVE_DLOPEN) " failed to load, install libpcap to use pcap networking";
#endif
#undef __STR
#undef __STR_QUOTE
@@ -1528,7 +1541,7 @@ int pcap_setnonblock(pcap_t* a, int nonblock, char *errbuf) {
return 0;
}
}
#endif /* defined(USE_SHARED) && (defined(_WIN32) || defined(HAVE_DLOPEN)) */
#endif /* defined(USE_SHARED) && (defined(_WIN32) || defined(SIM_HAVE_DLOPEN)) */
/* Some platforms have always had pcap_sendpacket */
#if defined(_WIN32) || defined(__VMS)
@@ -1735,7 +1748,14 @@ static int pcap_mac_if_vms(const char *AdapterName, unsigned char MACAddress[6])
}
#endif /* defined (__VMS) && !defined(__VAX) */
static void eth_get_nic_hw_addr(ETH_DEV* dev, const char *devname)
#if SIM_MAJOR != 4
static const char *sim_get_tool_path (const char *tool)
{
return tool;
}
#endif
static void eth_get_nic_hw_addr(ETH_DEV* dev, const char *devname, int set_on)
{
memset(&dev->host_nic_phy_hw_addr, 0, sizeof(dev->host_nic_phy_hw_addr));
dev->have_host_nic_phy_addr = 0;
@@ -1752,47 +1772,63 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, const char *devname)
char command[1024];
FILE *f;
int i;
char tool[CBUFSIZE];
const char *turnon[] = {
"ip link set dev %.*s up 2>/dev/null",
"ifconfig %.*s up 2>/dev/null",
NULL};
const char *patterns[] = {
"grep [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]",
"ip link show %.*s 2>/dev/null | grep [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]",
"ip link show %.*s 2>/dev/null | 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]",
"ifconfig %.*s 2>/dev/null | grep [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]",
"ifconfig %.*s 2>/dev/null | 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};
memset(command, 0, sizeof(command));
/* try to force an otherwise unused interface to be turned on */
snprintf(command, sizeof(command)-1, "ifconfig %.*s up", (int)(sizeof(command) - 14), devname);
if (system(command)) {};
for (i=0; patterns[i] && (0 == dev->have_host_nic_phy_addr); ++i) {
snprintf(command, sizeof(command)-1, "ifconfig %.*s | %s >NIC.hwaddr", (int)(sizeof(command) - (26 + strlen(patterns[i]))), devname, patterns[i]);
if (system(command)) {};
if (NULL != (f = fopen("NIC.hwaddr", "r"))) {
while (0 == dev->have_host_nic_phy_addr) {
if (fgets(command, sizeof(command)-1, f)) {
char *p1, *p2;
p1 = strchr(command, ':');
while (p1) {
p2 = strchr(p1+1, ':');
if (p2 <= p1+3) {
unsigned int mac_bytes[6];
if (6 == sscanf(p1-2, "%02x:%02x:%02x:%02x:%02x:%02x", &mac_bytes[0], &mac_bytes[1], &mac_bytes[2], &mac_bytes[3], &mac_bytes[4], &mac_bytes[5])) {
dev->host_nic_phy_hw_addr[0] = mac_bytes[0];
dev->host_nic_phy_hw_addr[1] = mac_bytes[1];
dev->host_nic_phy_hw_addr[2] = mac_bytes[2];
dev->host_nic_phy_hw_addr[3] = mac_bytes[3];
dev->host_nic_phy_hw_addr[4] = mac_bytes[4];
dev->host_nic_phy_hw_addr[5] = mac_bytes[5];
dev->have_host_nic_phy_addr = 1;
}
break;
}
p1 = p2;
}
}
else
break;
if (set_on) {
/* try to force an otherwise unused interface to be turned on */
for (i=0; turnon[i]; ++i) {
snprintf(command, sizeof(command), turnon[i], (int)(sizeof(command) - (2 + strlen(patterns[i]))), devname);
get_glyph_nc (command, tool, 0);
if (sim_get_tool_path (tool)[0]) {
if (NULL != (f = popen(command, "r")))
pclose(f);
}
}
}
for (i=0; patterns[i] && (0 == dev->have_host_nic_phy_addr); ++i) {
snprintf(command, sizeof(command), patterns[i], (int)(sizeof(command) - (2 + strlen(patterns[i]))), devname);
get_glyph_nc (command, tool, 0);
if (sim_get_tool_path (tool)[0]) {
if (NULL != (f = popen(command, "r"))) {
while (0 == dev->have_host_nic_phy_addr) {
if (fgets(command, sizeof(command)-1, f)) {
char *p1, *p2;
p1 = strchr(command, ':');
while (p1) {
p2 = strchr(p1+1, ':');
if (p2 <= p1+3) {
unsigned int mac_bytes[6];
if (6 == sscanf(p1-2, "%02x:%02x:%02x:%02x:%02x:%02x", &mac_bytes[0], &mac_bytes[1], &mac_bytes[2], &mac_bytes[3], &mac_bytes[4], &mac_bytes[5])) {
dev->host_nic_phy_hw_addr[0] = mac_bytes[0];
dev->host_nic_phy_hw_addr[1] = mac_bytes[1];
dev->host_nic_phy_hw_addr[2] = mac_bytes[2];
dev->host_nic_phy_hw_addr[3] = mac_bytes[3];
dev->host_nic_phy_hw_addr[4] = mac_bytes[4];
dev->host_nic_phy_hw_addr[5] = mac_bytes[5];
dev->have_host_nic_phy_addr = 1;
}
break;
}
p1 = p2;
}
}
else
break;
}
pclose(f);
}
fclose(f);
(void)remove("NIC.hwaddr");
}
}
}
@@ -2379,8 +2415,7 @@ else { /* !tap: */
char command[1024];
/* try to force an otherwise unused interface to be turned on */
memset(command, 0, sizeof(command));
snprintf(command, sizeof(command)-1, "ifconfig %s up", savname);
snprintf(command, sizeof(command), (sim_get_tool_path ("ifconfig")[0] != '\0') ? "ifconfig %s up" : "ip link set dev %s up", savname);
if (system(command)) {};
errbuf[0] = '\0';
*handle = (void*) pcap_open_live(savname, bufsz, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
@@ -2486,12 +2521,13 @@ if (bufsz < ETH_MAX_JUMBO_FRAME)
/* initialize device */
eth_zero(dev);
/* translate name of type "ethX" to real device name */
if ((strlen(name) == 4)
/* translate name of type "eth<num>" to real device name */
if ((strlen(name) == 4 || strlen(name) == 5)
&& (tolower(name[0]) == 'e')
&& (tolower(name[1]) == 't')
&& (tolower(name[2]) == 'h')
&& isdigit(name[3])
&& (strlen(name) == 4 || isdigit(name[4]))
) {
num = atoi(&name[3]);
savname = _eth_getname(num, temp, desc);
@@ -2531,7 +2567,7 @@ if (!strcmp (desc, "No description available"))
sim_messagef (SCPE_OK, "Eth: opened OS device %s%s%s\n", savname, desc[0] ? " - " : "", desc);
/* get the NIC's hardware MAC address */
eth_get_nic_hw_addr(dev, savname);
eth_get_nic_hw_addr(dev, savname, 1);
/* save name of device */
dev->name = (char *)malloc(strlen(savname)+1);
@@ -4000,15 +4036,24 @@ return SCPE_OK;
t_stat eth_filter(ETH_DEV* dev, int addr_count, ETH_MAC* const addresses,
ETH_BOOL all_multicast, ETH_BOOL promiscuous)
{
return eth_filter_hash(dev, addr_count, addresses,
all_multicast, promiscuous,
NULL);
return eth_filter_hash_ex(dev, addr_count, addresses,
all_multicast, promiscuous, FALSE,
NULL);
}
t_stat eth_filter_hash(ETH_DEV* dev, int addr_count, ETH_MAC* const addresses,
ETH_BOOL all_multicast, ETH_BOOL promiscuous,
ETH_MULTIHASH* const hash)
{
return eth_filter_hash_ex(dev, addr_count, addresses,
all_multicast, promiscuous, TRUE,
hash);
}
t_stat eth_filter_hash_ex(ETH_DEV* dev, int addr_count, ETH_MAC* const addresses,
ETH_BOOL all_multicast, ETH_BOOL promiscuous,
ETH_BOOL match_broadcast, ETH_MULTIHASH* const hash)
{
int i;
char buf[116+66*ETH_FILTER_MAX];
char mac[20];
@@ -4021,7 +4066,7 @@ struct bpf_program bpf;
if (!dev) return SCPE_UNATT;
/* filter count OK? */
if ((addr_count < 0) || (addr_count > ETH_FILTER_MAX))
if ((addr_count < 0) || ((addr_count + (match_broadcast ? 1 : 0)) > ETH_FILTER_MAX))
return SCPE_ARG;
else
if (!addresses && (addr_count != 0))
@@ -4036,6 +4081,11 @@ if (dev->reflections == -1)
for (i = 0; i < addr_count; i++)
memcpy(dev->filter_address[i], addresses[i], sizeof(ETH_MAC));
dev->addr_count = addr_count;
if (match_broadcast) {
memset(&dev->filter_address[addr_count], 0xFF, sizeof(ETH_MAC));
++addr_count;
}
dev->addr_count = addr_count;
/* store other flags */
dev->all_multicast = all_multicast;
@@ -4205,6 +4255,26 @@ fprintf(st, " Read Queue: High: %d\n", dev->read_queue.high);
fprintf(st, " Read Queue: Loss: %d\n", dev->read_queue.loss);
fprintf(st, " Peak Write Queue Size: %d\n", dev->write_queue_peak);
#endif
if (dev->error_needs_reset)
fprintf(st, " In Error Needs Reset: True\n");
if (dev->error_reopen_count)
fprintf(st, " Error Reopen Count: %d\n", (int)dev->error_reopen_count);
if (1) {
int i, count = 0;
ETH_MAC zeros = {0, 0, 0, 0, 0, 0};
char buffer[20];
for (i = 0; i < ETH_FILTER_MAX; i++) {
if (memcmp(zeros, &dev->filter_address[i], sizeof(ETH_MAC))) {
eth_mac_fmt(&dev->filter_address[i], buffer);
fprintf(st, " MAC Filter[%2d]: %s\n", count++, buffer);
}
}
}
if (dev->all_multicast)
fprintf(st, " All Multicast mode: Enabled\n");
if (dev->promiscuous)
fprintf(st, " Promiscuous mode: Enabled\n");
if (dev->bpf_filter)
fprintf(st, " BPF Filter: %s\n", dev->bpf_filter);
#if defined(HAVE_SLIRP_NETWORK)
@@ -4320,7 +4390,7 @@ int bpf_compile_skip_count = 0;
memset (&eth_tst, 0, sizeof(eth_tst));
eth_device_count = _eth_devices(ETH_MAX_DEVICE, eth_list);
eth_device_count = eth_devices(ETH_MAX_DEVICE, eth_list, FALSE);
eth_opened = 0;
for (eth_num=0; eth_num<eth_device_count; eth_num++) {
char eth_name[32];
@@ -4409,7 +4479,7 @@ return (errors == 0) ? SCPE_OK : SCPE_IERR;
#include <setjmp.h>
t_stat sim_ether_test (DEVICE *dptr)
t_stat sim_ether_test (DEVICE *dptr, const char *cptr)
{
t_stat stat = SCPE_OK;
SIM_TEST_INIT;

View File

@@ -124,8 +124,8 @@ extern "C" {
#if defined(USE_NETWORK) && defined(USE_SHARED)
#undef USE_SHARED
#endif
/* USE_SHARED only works on Windows or if HAVE_DLOPEN */
#if defined(USE_SHARED) && !defined(_WIN32) && !defined(HAVE_DLOPEN)
/* USE_SHARED only works on Windows or if SIM_HAVE_DLOPEN */
#if defined(USE_SHARED) && !defined(_WIN32) && !defined(SIM_HAVE_DLOPEN)
#undef USE_SHARED
#endif
@@ -232,6 +232,8 @@ struct eth_queue {
struct eth_item* item;
};
typedef unsigned char ETH_MAC[6];
struct eth_list {
char name[ETH_DEV_NAME_MAX];
char desc[ETH_DEV_DESC_MAX];
@@ -239,7 +241,6 @@ struct eth_list {
};
typedef int ETH_BOOL;
typedef unsigned char ETH_MAC[6];
typedef unsigned char ETH_MULTIHASH[8];
typedef struct eth_packet ETH_PACK;
typedef void (*ETH_PCALLBACK)(int status);
@@ -342,11 +343,17 @@ t_stat eth_filter (ETH_DEV* dev, int addr_count, /* set filter on incomin
ETH_MAC* const addresses,
ETH_BOOL all_multicast,
ETH_BOOL promiscuous);
t_stat eth_filter_hash (ETH_DEV* dev, int addr_count, /* set filter on incoming packets with AUTODIN II based hash */
t_stat eth_filter_hash (ETH_DEV* dev, int addr_count, /* set filter on incoming packets with hash */
ETH_MAC* const addresses,
ETH_BOOL all_multicast,
ETH_BOOL promiscuous,
ETH_MULTIHASH* const hash);
ETH_MULTIHASH* const hash); /* AUTODIN II based 8 byte imperfect hash */
t_stat eth_filter_hash_ex (ETH_DEV* dev, int addr_count,/* set filter on incoming packets with hash */
ETH_MAC* const addresses,
ETH_BOOL all_multicast,
ETH_BOOL promiscuous,
ETH_BOOL match_broadcast,
ETH_MULTIHASH* const hash); /* AUTODIN II based 8 byte imperfect hash */
t_stat eth_check_address_conflict (ETH_DEV* dev,
ETH_MAC* const address);
const char *eth_version (void); /* Version of dynamically loaded library (pcap) */
@@ -362,6 +369,7 @@ t_stat eth_show (FILE* st, UNIT* uptr, /* show ethernet devices
int32 val, CONST void* desc);
t_stat eth_show_devices (FILE* st, DEVICE *dptr, /* show ethernet devices */
UNIT* uptr, int32 val, CONST char* desc);
int eth_devices (int max, ETH_LIST* dev, ETH_BOOL framers); /* get ethernet devices on host */
void eth_show_dev (FILE*st, ETH_DEV* dev); /* show ethernet device state */
void eth_mac_fmt (ETH_MAC* const add, char* buffer); /* format ethernet mac address */
@@ -379,7 +387,7 @@ void ethq_insert_data(ETH_QUE* que, int32 type, /* insert item into FIFO
size_t crc_len, const uint8 *crc_data, int32 status);
t_stat ethq_destroy(ETH_QUE* que); /* release FIFO queue */
const char *eth_capabilities(void);
t_stat sim_ether_test (DEVICE *dptr); /* unit test routine */
t_stat sim_ether_test (DEVICE *dptr, const char *cptr); /* unit test routine */
#if !defined(SIM_TEST_INIT) /* Need stubs for test APIs */
#define SIM_TEST_INIT

View File

@@ -55,7 +55,7 @@ extern "C" {
#include <ws2tcpip.h>
#endif
#ifdef HAVE_DLOPEN
#ifdef SIM_HAVE_DLOPEN
#include <dlfcn.h>
#endif
@@ -501,27 +501,38 @@ int load_ws2(void) {
/* OS independent routines
sim_parse_addr parse a hostname/ipaddress from port and apply defaults and
optionally validate an address match
sim_parse_addr parse a hostname/ipaddress from port and apply defaults
and optionally validate an address match
sim_addr_acl_check parse a hostname/ipaddress (possibly in CIDR form) and
test against an acl
*/
/* sim_parse_addr 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)
Presumption is that the cptr 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)
Inputs:
cptr = pointer to input string
default_host
= optional pointer to default host if none specified
host = optional pointer to host buffer
host_len = length of host buffer
default_port
= optional pointer to default port if none specified
default_host = optional pointer to default host if none specified
in cptr
port = optional pointer to port buffer
port_len = length of port buffer
default_port = optional pointer to default port if none specified
in cptr
validate_addr = optional name/addr which is checked to be equivalent
to the host result of parsing the other input. This
address would usually be returned by sim_accept_conn.
The validate_addr can also be a CIDR address specifier
which will match against the provided host.
If the validate_addr is provided with cptr as NULL,
the validate_addr is parsed for reasonableness and
the result returned with 0 indicating a reasonable
value and -1 indicating a parsing error.
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
@@ -532,7 +543,9 @@ int load_ws2(void) {
doesn't match the parsed host)
*/
int sim_parse_addr (const char *cptr, char *host, size_t host_len, const char *default_host, char *port, size_t port_len, const char *default_port, const char *validate_addr)
int sim_parse_addr (const char *cptr, char *host, size_t host_len, const char *default_host,
char *port, size_t port_len, const char *default_port,
const char *validate_addr)
{
char gbuf[CBUFSIZE], default_pbuf[CBUFSIZE];
const char *hostp;
@@ -545,7 +558,8 @@ if ((host != NULL) && (host_len != 0))
if ((port != NULL) && (port_len != 0))
memset (port, 0, port_len);
if ((cptr == NULL) || (*cptr == 0)) {
if (((default_host == NULL) || (*default_host == 0)) || ((default_port == NULL) || (*default_port == 0)))
if (((default_host == NULL) || (*default_host == 0)) ||
((default_port == NULL) || (*default_port == 0)))
return -1;
if ((host == NULL) || (port == NULL))
return -1; /* no place */
@@ -572,7 +586,7 @@ else { /* No colon in input */
portp = gbuf; /* Input is the port specifier */
hostp = (const char *)default_host; /* host is defaulted if provided */
}
if (portp != NULL) {
if ((portp != NULL) && (*portp != '\0')) {
portval = strtoul(portp, &endc, 10);
if ((*endc == '\0') && ((portval == 0) || (portval > 65535)))
return -1; /* numeric value too big */
@@ -590,7 +604,7 @@ if (port) /* port wanted? */
else
strcpy (port, portp);
}
if (hostp != NULL) {
if ((hostp != NULL) && (*hostp != '\0')) {
if (']' == hostp[strlen(hostp)-1]) {
if ('[' != hostp[0])
return -1; /* invalid domain literal */
@@ -626,16 +640,15 @@ if (validate_addr) {
struct addrinfo *ai_host, *ai_validate, *ai, *aiv;
int status;
if (hostp == NULL)
return -1;
if (p_getaddrinfo(hostp, NULL, NULL, &ai_host))
if ((hostp == NULL) ||
(0 != p_getaddrinfo(hostp, NULL, NULL, &ai_host)))
return -1;
if (p_getaddrinfo(validate_addr, NULL, NULL, &ai_validate)) {
p_freeaddrinfo (ai_host);
return -1;
}
status = -1;
for (ai = ai_host; ai != NULL; ai = ai->ai_next) {
for (ai = ai_host; (ai != NULL) && (status == -1); ai = ai->ai_next) {
for (aiv = ai_validate; aiv != NULL; aiv = aiv->ai_next) {
if ((ai->ai_addrlen == aiv->ai_addrlen) &&
(ai->ai_family == aiv->ai_family) &&
@@ -660,6 +673,151 @@ if (validate_addr) {
return 0;
}
/* sim_addr_acl_check host:port,acl
parse a hostname/ipaddress (possibly in CIDR form) and
test against an acl
Inputs:
validate_addr = This address would usually be returned by
sim_accept_conn. The validate_addr can also be a
CIDR address specifier and in that mode, acl should
be NULL so that we're just validating the syntax
of what will likely become an entry in an acl list.
If the validate_addr is provided with cptr as NULL,
the validate_addr is parsed for reasonableness and
the result returned with 0 indicating a reasonable
value and -1 indicating a parsing error.
acl = pointer to acl string which is comprised of comma
separated entries each which may have a + or -
prefix that indicated a permit or deny status when
the entry matches. Each entry may specify a CIDR
form match criteria.
Outputs:
result = status (0 on complete success or -1 if
parsing can't happen due to bad syntax, a value is
out of range or the validate_addr matches a reject
entry in the acl or it is not mentioned at all in
the acl.
*/
int sim_addr_acl_check (const char *validate_addr, const char *acl)
{
int status = -1;
int done = 0;
struct addrinfo *ai_validate;
unsigned long bits = 0;
const char *c;
char *c1, v_cpy[256];
if (validate_addr == NULL)
return status;
c = strchr (validate_addr, '/');
if (c != NULL) {
bits = strtoul (c + 1, &c1, 10);
if ((bits == 0) || (bits > 128) || (*c1 != '\0'))
return status;
if ((size_t)(c - validate_addr) > sizeof (v_cpy) - 1)
return status;
memcpy (v_cpy, validate_addr, c - validate_addr); /* Copy everything before the / */
v_cpy[1 + c - validate_addr] = '\0'; /* NUL terminate the result */
validate_addr = v_cpy; /* Use the original string minus the prefix specifier */
}
if (p_getaddrinfo(validate_addr, NULL, NULL, &ai_validate))
return status;
if (acl == NULL) { /* Just checking validate_addr syntax? */
status = 0;
if ((ai_validate->ai_family == AF_INET) && (bits > 32))
status = -1;
p_freeaddrinfo (ai_validate);
return status;
}
status = -1;
while ((*acl != '\0') && !done) {
struct addrinfo *ai_rule, *ai, *aiv;
int permit;
unsigned long bits = 0;
const char *cc;
char *c,*c1, rule[260];
permit = (*acl == '+');
cc = strchr (acl, ',');
if (cc != NULL) {
if ((size_t)(cc - acl) > sizeof (rule))
break; /* Too big - error */
memcpy (rule, acl + 1, cc - (acl + 1));
rule[cc - (acl + 1)] = '\0';
}
else {
if (strlen (acl) > sizeof (rule))
break; /* Too big - error */
strcpy (rule, acl + 1);
}
acl += strlen (rule) + 1 + (cc != NULL);
c = strchr (rule, '/');
if (c != NULL) {
bits = strtoul (c + 1, &c1, 10);
if ((bits == 0) || (bits > 128) || (*c1 != '\0'))
break;
*c = '\0';
}
if (p_getaddrinfo(rule, NULL, NULL, &ai_rule))
break;
for (ai = ai_rule; (ai != NULL) && (done == 0); ai = ai->ai_next) {
for (aiv = ai_validate; aiv != NULL; aiv = aiv->ai_next) {
if ((ai->ai_addrlen == aiv->ai_addrlen) &&
(ai->ai_family == aiv->ai_family)) {
unsigned int bit, addr_bits;
unsigned char *da, *dav;
if (ai->ai_family == AF_INET) {
da = (unsigned char *)&((struct sockaddr_in *)ai->ai_addr)->sin_addr;
dav = (unsigned char *)&((struct sockaddr_in *)aiv->ai_addr)->sin_addr;
addr_bits = 32;
}
#if !defined(AF_INET6)
else {
done = 1;
break;
}
#else
else {
if (ai->ai_family == AF_INET6) {
da = (unsigned char *)&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
dav = (unsigned char *)&((struct sockaddr_in6 *)aiv->ai_addr)->sin6_addr;
addr_bits = 128;
}
else {
done = 1;
break;
}
}
#endif
if (bits == 0) /* Bits not specified? */
bits = addr_bits; /* Use them all */
for (bit=0; (bit < bits) && (bit < addr_bits); bit++) {
unsigned int bitmask = 1 << (7 - (bit & 7));
if ((da[bit>>3] & bitmask) != (dav[bit>>3] & bitmask))
break;
}
if (bit == bits) { /* All desired bits matched? */
done = 1;
status = permit ? 0 : -1;
break;
}
}
}
}
p_freeaddrinfo (ai_rule);
}
p_freeaddrinfo (ai_validate);
return status;
}
/* sim_parse_addr_ex localport:host:port
Presumption is that the input, if it doesn't contain a ':' character is a port specifier.

View File

@@ -111,8 +111,12 @@ extern "C" {
#define sim_printf printf
#endif
int 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);
int 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);
int 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);
int 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);
int sim_addr_acl_check (const char *validate_addr, const char *acl);
#define SIM_SOCK_OPT_REUSEADDR 0x0001
#define SIM_SOCK_OPT_DATAGRAM 0x0002
#define SIM_SOCK_OPT_NODELAY 0x0004