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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
202
sim_ether.c
202
sim_ether.c
@@ -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 (ð_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;
|
||||
|
||||
20
sim_ether.h
20
sim_ether.h
@@ -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
|
||||
|
||||
194
sim_sock.c
194
sim_sock.c
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user