From 19db1d2c7b195cfbaf14eeea5c90401b170b791b Mon Sep 17 00:00:00 2001 From: Adrien Moulin Date: Sun, 21 Aug 2022 16:55:47 +0200 Subject: [PATCH 1/3] Network overhaul : support for multiple NICs, performance improvement - Add support for multiple NICs - Switch from polling to an event loop for the host networking to avoid latency and locking issues --- src/86box.c | 7 +- src/config.c | 169 ++++++--- src/include/86box/net_dp8390.h | 2 + src/include/86box/net_event.h | 22 ++ src/include/86box/network.h | 94 +++-- src/network/CMakeLists.txt | 2 +- src/network/net_3c503.c | 6 +- src/network/net_dp8390.c | 12 +- src/network/net_event.c | 76 ++++ src/network/net_ne2000.c | 6 +- src/network/net_pcap.c | 539 ++++++++++++++++------------ src/network/net_pcnet.c | 12 +- src/network/net_plip.c | 15 +- src/network/net_slirp.c | 625 +++++++++++++++++---------------- src/network/net_wd8003.c | 6 +- src/network/network.c | 531 ++++++++++++---------------- src/qt/qt_machinestatus.cpp | 1 + src/qt/qt_settingsnetwork.cpp | 152 ++++---- src/qt/qt_settingsnetwork.hpp | 10 +- src/qt/qt_settingsnetwork.ui | 343 +++++++++++++++--- src/win/Makefile.mingw | 2 +- 21 files changed, 1557 insertions(+), 1075 deletions(-) create mode 100644 src/include/86box/net_event.h create mode 100644 src/network/net_event.c diff --git a/src/86box.c b/src/86box.c index 85845b050..3e1bd6e3c 100644 --- a/src/86box.c +++ b/src/86box.c @@ -60,7 +60,6 @@ #include <86box/device.h> #include <86box/pit.h> #include <86box/random.h> -#include <86box/timer.h> #include <86box/nvr.h> #include <86box/machine.h> #include <86box/bugger.h> @@ -85,6 +84,7 @@ #include <86box/mo.h> #include <86box/scsi_disk.h> #include <86box/cdrom_image.h> +#include <86box/thread.h> #include <86box/network.h> #include <86box/sound.h> #include <86box/midi.h> @@ -93,7 +93,6 @@ #include <86box/ui.h> #include <86box/path.h> #include <86box/plat.h> -#include <86box/thread.h> #include <86box/version.h> #include <86box/gdbstub.h> #include <86box/machine_status.h> @@ -951,8 +950,6 @@ pc_reset_hard_close(void) /* Close all the memory mappings. */ mem_close(); - network_timer_stop(); - /* Turn off timer processing to avoid potential segmentation faults. */ timer_close(); @@ -1173,8 +1170,6 @@ pc_close(thread_t *ptr) /* Close all the memory mappings. */ mem_close(); - network_timer_stop(); - /* Turn off timer processing to avoid potential segmentation faults. */ timer_close(); diff --git a/src/config.c b/src/config.c index 79fd7433b..b0c73e0d0 100644 --- a/src/config.c +++ b/src/config.c @@ -55,6 +55,7 @@ #include <86box/gameport.h> #include <86box/machine.h> #include <86box/mouse.h> +#include <86box/thread.h> #include <86box/network.h> #include <86box/scsi.h> #include <86box/scsi_device.h> @@ -1131,45 +1132,89 @@ load_network(void) { char *cat = "Network"; char *p; + char temp[512]; + int c = 0, min = 0; - p = config_get_string(cat, "net_type", NULL); - if (p != NULL) { - if (!strcmp(p, "pcap") || !strcmp(p, "1")) - network_type = NET_TYPE_PCAP; - else if (!strcmp(p, "slirp") || !strcmp(p, "2")) - network_type = NET_TYPE_SLIRP; - else - network_type = NET_TYPE_NONE; - } else - network_type = NET_TYPE_NONE; - - memset(network_host, '\0', sizeof(network_host)); - p = config_get_string(cat, "net_host_device", NULL); - if (p == NULL) { - p = config_get_string(cat, "net_host_device", NULL); - if (p != NULL) - config_delete_var(cat, "net_host_device"); - } - if (p != NULL) { - if ((network_dev_to_id(p) == -1) || (network_ndev == 1)) { - if ((network_ndev == 1) && strcmp(network_host, "none")) { - ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2094, (wchar_t *) IDS_2129); - } else if (network_dev_to_id(p) == -1) { - ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2095, (wchar_t *) IDS_2129); - } - - strcpy(network_host, "none"); - } else { - strncpy(network_host, p, sizeof(network_host) - 1); - } - } else - strcpy(network_host, "none"); - + /* Handle legacy configuration which supported only one NIC */ p = config_get_string(cat, "net_card", NULL); - if (p != NULL) - network_card = network_card_get_from_internal_name(p); - else - network_card = 0; + if (p != NULL) { + net_cards_conf[c].device_num = network_card_get_from_internal_name(p); + + p = config_get_string(cat, "net_type", NULL); + if (p != NULL) { + if (!strcmp(p, "pcap") || !strcmp(p, "1")) + net_cards_conf[c].net_type = NET_TYPE_PCAP; + else if (!strcmp(p, "slirp") || !strcmp(p, "2")) + net_cards_conf[c].net_type = NET_TYPE_SLIRP; + else + net_cards_conf[c].net_type = NET_TYPE_NONE; + } else { + net_cards_conf[c].net_type = NET_TYPE_NONE; + } + + p = config_get_string(cat, "net_host_device", NULL); + if (p != NULL) { + if ((network_dev_to_id(p) == -1) || (network_ndev == 1)) { + if (network_ndev == 1) { + ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2094, (wchar_t *) IDS_2129); + } else if (network_dev_to_id(p) == -1) { + ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2095, (wchar_t *) IDS_2129); + } + strcpy(net_cards_conf[c].host_dev_name, "none"); + } else { + strncpy(net_cards_conf[c].host_dev_name, p, sizeof(net_cards_conf[c].host_dev_name) - 1); + } + } else { + strcpy(net_cards_conf[c].host_dev_name, "none"); + } + + min++; + } + + config_delete_var(cat, "net_card"); + config_delete_var(cat, "net_type"); + config_delete_var(cat, "net_host_device"); + + for (c = min; c < NET_CARD_MAX; c++) { + sprintf(temp, "net_%02i_card", c + 1); + p = config_get_string(cat, temp, NULL); + if (p != NULL) { + net_cards_conf[c].device_num = network_card_get_from_internal_name(p); + } else { + net_cards_conf[c].device_num = 0; + } + + sprintf(temp, "net_%02i_net_type", c + 1); + p = config_get_string(cat, temp, NULL); + if (p != NULL) { + if (!strcmp(p, "pcap") || !strcmp(p, "1")) { + net_cards_conf[c].net_type = NET_TYPE_PCAP; + } else if (!strcmp(p, "slirp") || !strcmp(p, "2")) { + net_cards_conf[c].net_type = NET_TYPE_SLIRP; + } else { + net_cards_conf[c].net_type = NET_TYPE_NONE; + } + } else { + net_cards_conf[c].net_type = NET_TYPE_NONE; + } + + sprintf(temp, "net_%02i_host_device", c + 1); + p = config_get_string(cat, temp, NULL); + if (p != NULL) { + if ((network_dev_to_id(p) == -1) || (network_ndev == 1)) { + if (network_ndev == 1) { + ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2094, (wchar_t *) IDS_2129); + } else if (network_dev_to_id(p) == -1) { + ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2095, (wchar_t *) IDS_2129); + } + strcpy(net_cards_conf[c].host_dev_name, "none"); + } else { + strncpy(net_cards_conf[c].host_dev_name, p, sizeof(net_cards_conf[c].host_dev_name) - 1); + } + } else { + strcpy(net_cards_conf[c].host_dev_name, "none"); + } + } } /* Load "Ports" section. */ @@ -2688,30 +2733,42 @@ save_sound(void) static void save_network(void) { + int c = 0; + char temp[512]; char *cat = "Network"; - if (network_type == NET_TYPE_NONE) - config_delete_var(cat, "net_type"); - else - config_set_string(cat, "net_type", - (network_type == NET_TYPE_SLIRP) ? "slirp" : "pcap"); + config_delete_var(cat, "net_type"); + config_delete_var(cat, "net_host_device"); + config_delete_var(cat, "net_card"); - if (network_host[0] != '\0') { - if (!strcmp(network_host, "none")) - config_delete_var(cat, "net_host_device"); - else - config_set_string(cat, "net_host_device", network_host); - } else { - /* config_set_string(cat, "net_host_device", "none"); */ - config_delete_var(cat, "net_host_device"); + for (c = 0; c < NET_CARD_MAX; c++) { + sprintf(temp, "net_%02i_card", c + 1); + if (net_cards_conf[c].device_num == 0) { + config_delete_var(cat, temp); + } else { + config_set_string(cat, temp, network_card_get_internal_name(net_cards_conf[c].device_num)); + } + + sprintf(temp, "net_%02i_net_type", c + 1); + if (net_cards_conf[c].net_type == NET_TYPE_NONE) { + config_delete_var(cat, temp); + } else { + config_set_string(cat, temp, + (net_cards_conf[c].net_type == NET_TYPE_SLIRP) ? "slirp" : "pcap"); + } + + sprintf(temp, "net_%02i_host_device", c + 1); + if (net_cards_conf[c].host_dev_name[0] != '\0') { + if (!strcmp(net_cards_conf[c].host_dev_name, "none")) + config_delete_var(cat, temp); + else + config_set_string(cat, temp, net_cards_conf[c].host_dev_name); + } else { + /* config_set_string(cat, temp, "none"); */ + config_delete_var(cat, temp); + } } - if (network_card == 0) - config_delete_var(cat, "net_card"); - else - config_set_string(cat, "net_card", - network_card_get_internal_name(network_card)); - delete_section_if_empty(cat); } diff --git a/src/include/86box/net_dp8390.h b/src/include/86box/net_dp8390.h index 027bce576..264febc93 100644 --- a/src/include/86box/net_dp8390.h +++ b/src/include/86box/net_dp8390.h @@ -184,11 +184,13 @@ typedef struct { int tx_timer_active; void *priv; + netcard_t *card; void (*interrupt)(void *priv, int set); } dp8390_t; extern const device_t dp8390_device; +extern int dp3890_inst; extern uint32_t dp8390_chipmem_read(dp8390_t *dev, uint32_t addr, unsigned int len); diff --git a/src/include/86box/net_event.h b/src/include/86box/net_event.h new file mode 100644 index 000000000..61eaad166 --- /dev/null +++ b/src/include/86box/net_event.h @@ -0,0 +1,22 @@ +#ifndef EMU_NET_EVENT_H +#define EMU_NET_EVENT_H + +typedef struct { +#ifdef _WIN32 + HANDLE handle; +#else + int fds[2]; +#endif +} net_evt_t; + +extern void net_event_init(net_evt_t *event); +extern void net_event_set(net_evt_t *event); +extern void net_event_clear(net_evt_t *event); +extern void net_event_close(net_evt_t *event); +#ifdef _WIN32 +extern HANDLE net_event_get_handle(net_evt_t *event); +#else +extern int net_event_get_fd(net_evt_t *event); +#endif + +#endif \ No newline at end of file diff --git a/src/include/86box/network.h b/src/include/86box/network.h index 8e23e671f..f38db801a 100644 --- a/src/include/86box/network.h +++ b/src/include/86box/network.h @@ -52,8 +52,12 @@ /* Network provider types. */ #define NET_TYPE_NONE 0 /* networking disabled */ -#define NET_TYPE_PCAP 1 /* use the (Win)Pcap API */ -#define NET_TYPE_SLIRP 2 /* use the SLiRP port forwarder */ +#define NET_TYPE_SLIRP 1 /* use the SLiRP port forwarder */ +#define NET_TYPE_PCAP 2 /* use the (Win)Pcap API */ + +#define NET_MAX_FRAME 1518 +#define NET_QUEUE_LEN 8 +#define NET_CARD_MAX 4 /* Supported network cards. */ enum { @@ -64,6 +68,20 @@ enum { RTL8029AS }; +enum { + NET_QUEUE_RX, + NET_QUEUE_TX_VM, + NET_QUEUE_TX_HOST +}; + +typedef struct { + int device_num; + int net_type; + char host_dev_name[128]; +} netcard_conf_t; + +extern netcard_conf_t net_cards_conf[NET_CARD_MAX]; +extern int net_card_current; typedef int (*NETRXCB)(void *, uint8_t *, int); typedef int (*NETWAITCB)(void *); @@ -71,21 +89,44 @@ typedef int (*NETSETLINKSTATE)(void *); typedef struct netpkt { - void *priv; - uint8_t data[65536]; /* Maximum length + 1 to round up to the nearest power of 2. */ + uint8_t *data; int len; - - struct netpkt *prev, *next; + uint64_t tsc; } netpkt_t; typedef struct { - const device_t *device; - void *priv; - int (*poll)(void *); - NETRXCB rx; - NETWAITCB wait; - NETSETLINKSTATE set_link_state; -} netcard_t; + netpkt_t packets[NET_QUEUE_LEN]; + int size; + int head; + int tail; +} netqueue_t; + +typedef struct _netcard_t netcard_t; + +typedef struct netdrv_t { + void (*notify_in)(void *priv); + void *(*init)(const netcard_t *card, const uint8_t *mac_addr, void *priv); + void (*close)(void *priv); + void *priv; +} netdrv_t; + +extern const netdrv_t net_pcap_drv; +extern const netdrv_t net_slirp_drv; + +struct _netcard_t { + const device_t *device; + void *card_drv; + struct netdrv_t host_drv; + int (*poll)(void *); + NETRXCB rx; + NETWAITCB wait; + NETSETLINKSTATE set_link_state; + netqueue_t queues[3]; + netpkt_t queued_pkt; + mutex_t *tx_mutex; + mutex_t *rx_mutex; + pc_timer_t timer; +}; typedef struct { char device[128]; @@ -100,31 +141,19 @@ extern "C" { /* Global variables. */ extern int nic_do_log; /* config */ extern int network_ndev; -extern int network_rx_pause; extern netdev_t network_devs[32]; /* Function prototypes. */ -extern void network_wait(uint8_t wait); - extern void network_init(void); -extern void network_attach(void *, uint8_t *, NETRXCB, NETWAITCB, NETSETLINKSTATE); +extern netcard_t *network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETWAITCB wait, NETSETLINKSTATE set_link_state); +extern void netcard_close(netcard_t *card); extern void network_close(void); extern void network_reset(void); extern int network_available(void); -extern void network_tx(uint8_t *, int); -extern int network_tx_queue_check(void); +extern void network_tx(netcard_t *card, uint8_t *, int); extern int net_pcap_prepare(netdev_t *); -extern int net_pcap_init(void); -extern int net_pcap_reset(const netcard_t *, uint8_t *); -extern void net_pcap_close(void); -extern void net_pcap_in(uint8_t *, int); - -extern int net_slirp_init(void); -extern int net_slirp_reset(const netcard_t *, uint8_t *); -extern void net_slirp_close(void); -extern void net_slirp_in(uint8_t *, int); extern int network_dev_to_id(char *); extern int network_card_available(int); @@ -133,13 +162,8 @@ extern char *network_card_get_internal_name(int); extern int network_card_get_from_internal_name(char *); extern const device_t *network_card_getdevice(int); -extern void network_set_wait(int wait); -extern int network_get_wait(void); - -extern void network_timer_stop(void); - -extern void network_queue_put(int tx, void *priv, uint8_t *data, int len); - +extern int network_tx_pop(netcard_t *card, netpkt_t *out_pkt); +extern int network_rx_put(netcard_t *card, uint8_t *bufp, int len); #ifdef __cplusplus } #endif diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index e5a03a8ce..ffd5d03a7 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -14,7 +14,7 @@ # add_library(net OBJECT network.c net_pcap.c net_slirp.c net_dp8390.c net_3c503.c - net_ne2000.c net_pcnet.c net_wd8003.c net_plip.c) + net_ne2000.c net_pcnet.c net_wd8003.c net_plip.c net_event.c) option(SLIRP_EXTERNAL "Link against the system-provided libslirp library" OFF) mark_as_advanced(SLIRP_EXTERNAL) diff --git a/src/network/net_3c503.c b/src/network/net_3c503.c index bb2ed1628..d54a00593 100644 --- a/src/network/net_3c503.c +++ b/src/network/net_3c503.c @@ -55,6 +55,8 @@ #include <86box/mem.h> #include <86box/random.h> #include <86box/device.h> +#include <86box/thread.h> +#include <86box/timer.h> #include <86box/network.h> #include <86box/net_dp8390.h> #include <86box/net_3c503.h> @@ -592,7 +594,7 @@ threec503_nic_init(const device_t *info) dev->maclocal[5] = (mac & 0xff); } - dev->dp8390 = device_add(&dp8390_device); + dev->dp8390 = device_add_inst(&dp8390_device, dp3890_inst++); dev->dp8390->priv = dev; dev->dp8390->interrupt = threec503_interrupt; dp8390_set_defaults(dev->dp8390, DP8390_FLAG_CHECK_CR | DP8390_FLAG_CLEAR_IRQ); @@ -617,7 +619,7 @@ threec503_nic_init(const device_t *info) dev->regs.gacfr = 0x09; /* Start with RAM mapping enabled. */ /* Attach ourselves to the network module. */ - network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL, NULL); + dev->dp8390->card = network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL, NULL); return(dev); } diff --git a/src/network/net_dp8390.c b/src/network/net_dp8390.c index a5f26b69f..c9908f883 100644 --- a/src/network/net_dp8390.c +++ b/src/network/net_dp8390.c @@ -25,6 +25,8 @@ #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> +#include <86box/thread.h> +#include <86box/timer.h> #include <86box/network.h> #include <86box/net_dp8390.h> @@ -33,6 +35,7 @@ static void dp8390_tx(dp8390_t *dev, uint32_t val); static int dp8390_rx_common(void *priv, uint8_t *buf, int io_len); int dp8390_rx(void *priv, uint8_t *buf, int io_len); +int dp3890_inst = 0; #ifdef ENABLE_DP8390_LOG int dp8390_do_log = ENABLE_DP8390_LOG; @@ -225,7 +228,7 @@ dp8390_write_cr(dp8390_t *dev, uint32_t val) /* Send the packet to the system driver */ dev->CR.tx_packet = 1; - network_tx(&dev->mem[(dev->tx_page_start * 256) - dev->mem_start], dev->tx_bytes); + network_tx(dev->card, &dev->mem[(dev->tx_page_start * 256) - dev->mem_start], dev->tx_bytes); /* some more debug */ #ifdef ENABLE_DP8390_LOG @@ -1099,13 +1102,14 @@ dp8390_close(void *priv) { dp8390_t *dp8390 = (dp8390_t *) priv; - /* Make sure the platform layer is shut down. */ - network_close(); - if (dp8390) { if (dp8390->mem) free(dp8390->mem); + if (dp8390->card) { + netcard_close(dp8390->card); + } + free(dp8390); } } diff --git a/src/network/net_event.c b/src/network/net_event.c new file mode 100644 index 000000000..e7b09d723 --- /dev/null +++ b/src/network/net_event.c @@ -0,0 +1,76 @@ +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#else +#include +#include +#endif + +#include <86box/net_event.h> + + +#ifndef _WIN32 +static void setup_fd(int fd) +{ + fcntl(fd, F_SETFD, FD_CLOEXEC); + fcntl(fd, F_SETFL, O_NONBLOCK); +} +#endif + +void +net_event_init(net_evt_t *event) +{ +#ifdef _WIN32 + event->handle = CreateEvent(NULL, FALSE, FALSE, NULL); +#else + (void)pipe(event->fds); + setup_fd(event->fds[0]); + setup_fd(event->fds[1]); +#endif +} + +void +net_event_set(net_evt_t *event) +{ +#ifdef _WIN32 + SetEvent(event->handle); +#else + (void)write(event->fds[1], "a", 1); +#endif +} + +void +net_event_clear(net_evt_t *event) +{ +#ifdef _WIN32 + /* Do nothing on WIN32 since we use an auto-reset event */ +#else + char dummy[1]; + (void)read(event->fds[0], &dummy, sizeof(dummy)); +#endif +} + +void +net_event_close(net_evt_t *event) +{ +#ifdef _WIN32 + CloseHandle(event->handle); +#else + close(event->fds[0]); + close(event->fds[1]); +#endif +} + +#ifdef _WIN32 +HANDLE +net_event_get_handle(net_evt_t *event) +{ + return event->handle; +} +#else +int +net_event_get_fd(net_evt_t *event) +{ + return event->fds[0]; +} +#endif \ No newline at end of file diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index 5c0a7ba61..960f7cdbf 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -61,6 +61,8 @@ #include <86box/pic.h> #include <86box/random.h> #include <86box/device.h> +#include <86box/thread.h> +#include <86box/timer.h> #include <86box/network.h> #include <86box/net_dp8390.h> #include <86box/net_ne2000.h> @@ -973,7 +975,7 @@ nic_init(const device_t *info) dev->maclocal[5] = (mac & 0xff); } - dev->dp8390 = device_add(&dp8390_device); + dev->dp8390 = device_add_inst(&dp8390_device, dp3890_inst++); dev->dp8390->priv = dev; dev->dp8390->interrupt = nic_interrupt; @@ -1120,7 +1122,7 @@ nic_init(const device_t *info) nic_reset(dev); /* Attach ourselves to the network module. */ - network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL, NULL); + dev->dp8390->card = network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL, NULL); nelog(1, "%s: %s attached IO=0x%X IRQ=%d\n", dev->name, dev->is_pci?"PCI":"ISA", dev->base_address, dev->base_irq); diff --git a/src/network/net_pcap.c b/src/network/net_pcap.c index c76b62581..d695d4992 100644 --- a/src/network/net_pcap.c +++ b/src/network/net_pcap.c @@ -50,15 +50,38 @@ #include #include #include +#include +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#else +#include +#include +#include +#include +#endif + #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> #include <86box/plat.h> #include <86box/plat_dynld.h> #include <86box/thread.h> +#include <86box/timer.h> #include <86box/network.h> +#include <86box/net_event.h> +enum { + NET_EVENT_STOP = 0, + NET_EVENT_TX, + NET_EVENT_RX, + NET_EVENT_MAX +}; +#ifdef __APPLE__ +#include +#else typedef int bpf_int32; typedef unsigned int bpf_u_int32; @@ -66,33 +89,28 @@ typedef unsigned int bpf_u_int32; * The instruction data structure. */ struct bpf_insn { - unsigned short code; - unsigned char jt; - unsigned char jf; - bpf_u_int32 k; + unsigned short code; + unsigned char jt; + unsigned char jf; + bpf_u_int32 k; }; /* * Structure for "pcap_compile()", "pcap_setfilter()", etc.. */ struct bpf_program { - unsigned int bf_len; - struct bpf_insn *bf_insns; + unsigned int bf_len; + struct bpf_insn *bf_insns; }; -typedef struct pcap_if pcap_if_t; +typedef struct pcap_if pcap_if_t; -typedef struct net_timeval { - long tv_sec; - long tv_usec; -} net_timeval; - -#define PCAP_ERRBUF_SIZE 256 +#define PCAP_ERRBUF_SIZE 256 struct pcap_pkthdr { - struct net_timeval ts; - bpf_u_int32 caplen; - bpf_u_int32 len; + struct timeval ts; + bpf_u_int32 caplen; + bpf_u_int32 len; }; struct pcap_if { @@ -100,49 +118,79 @@ struct pcap_if { char *name; char *description; void *addresses; - unsigned int flags; + bpf_u_int32 flags; }; +#endif +typedef struct { + void *pcap; /* handle to pcap lib instance */ + netcard_t *card; /* netcard linked to us */ + thread_t *poll_tid; + net_evt_t tx_event; + net_evt_t stop_event; + netpkt_t pkt; + uint8_t mac_addr[6]; +} net_pcap_t; -static volatile void *pcap_handle; /* handle to WinPcap DLL */ -static volatile void *pcap; /* handle to WinPcap library */ -static volatile thread_t *poll_tid; -static const netcard_t *poll_card; /* netcard linked to us */ -static event_t *poll_state; +typedef struct { + char *intf_name; + uint8_t *mac_addr; +} net_pcap_params_t; +static volatile void *libpcap_handle; /* handle to WinPcap DLL */ /* Pointers to the real functions. */ static const char *(*f_pcap_lib_version)(void); -static int (*f_pcap_findalldevs)(pcap_if_t **,char *); -static void (*f_pcap_freealldevs)(void *); -static void *(*f_pcap_open_live)(const char *,int,int,int,char *); -static int (*f_pcap_compile)(void *,void *, - const char *,int,bpf_u_int32); -static int (*f_pcap_setfilter)(void *,void *); +static int (*f_pcap_findalldevs)(pcap_if_t **,char *); +static void (*f_pcap_freealldevs)(void *); +static void *(*f_pcap_open_live)(const char *,int,int,int,char *); +static int (*f_pcap_compile)(void *,void *, const char *,int,bpf_u_int32); +static int (*f_pcap_setfilter)(void *,void *); static const unsigned char - *(*f_pcap_next)(void *,void *); -static int (*f_pcap_sendpacket)(void *,const unsigned char *,int); -static void (*f_pcap_close)(void *); -static int (*f_pcap_setnonblock)(void*, int, char*); -static dllimp_t pcap_imports[] = { - { "pcap_lib_version", &f_pcap_lib_version }, - { "pcap_findalldevs", &f_pcap_findalldevs }, - { "pcap_freealldevs", &f_pcap_freealldevs }, - { "pcap_open_live", &f_pcap_open_live }, - { "pcap_compile", &f_pcap_compile }, - { "pcap_setfilter", &f_pcap_setfilter }, - { "pcap_next", &f_pcap_next }, - { "pcap_sendpacket", &f_pcap_sendpacket }, - { "pcap_close", &f_pcap_close }, - { "pcap_setnonblock", &f_pcap_setnonblock }, - { NULL, NULL }, -}; + *(*f_pcap_next)(void *,void *); +static int (*f_pcap_sendpacket)(void *,const unsigned char *,int); +static void (*f_pcap_close)(void *); +static int (*f_pcap_setnonblock)(void*, int, char*); +static int (*f_pcap_set_immediate_mode)(void *, int); +static int (*f_pcap_set_promisc)(void *, int); +static int (*f_pcap_set_snaplen)(void *, int); +static void *(*f_pcap_create)(const char *, char*); +static int (*f_pcap_activate)(void *); +static void *(*f_pcap_geterr)(void *); +#ifdef _WIN32 +static HANDLE (*f_pcap_getevent)(void *); +#else +static int (*f_pcap_get_selectable_fd)(void *); +#endif +static dllimp_t pcap_imports[] = { + { "pcap_lib_version", &f_pcap_lib_version }, + { "pcap_findalldevs", &f_pcap_findalldevs }, + { "pcap_freealldevs", &f_pcap_freealldevs }, + { "pcap_open_live", &f_pcap_open_live }, + { "pcap_compile", &f_pcap_compile }, + { "pcap_setfilter", &f_pcap_setfilter }, + { "pcap_next", &f_pcap_next }, + { "pcap_sendpacket", &f_pcap_sendpacket }, + { "pcap_close", &f_pcap_close }, + { "pcap_setnonblock", &f_pcap_setnonblock }, + { "pcap_set_immediate_mode", &f_pcap_set_immediate_mode}, + { "pcap_set_promisc", &f_pcap_set_promisc }, + { "pcap_set_snaplen", &f_pcap_set_snaplen }, + { "pcap_create", &f_pcap_create }, + { "pcap_activate", &f_pcap_activate }, + { "pcap_geterr", &f_pcap_geterr }, +#ifdef _WIN32 + { "pcap_getevent", &f_pcap_getevent }, +#else + { "pcap_get_selectable_fd", &f_pcap_get_selectable_fd }, +#endif + { NULL, NULL }, +}; #ifdef ENABLE_PCAP_LOG int pcap_do_log = ENABLE_PCAP_LOG; - static void pcap_log(const char *fmt, ...) { @@ -159,76 +207,118 @@ pcap_log(const char *fmt, ...) #endif -/* Handle the receiving of frames from the channel. */ static void -poll_thread(void *arg) +net_pcap_read_packet(net_pcap_t *pcap) { - uint8_t *mac = (uint8_t *)arg; - uint8_t *data = NULL; struct pcap_pkthdr h; - uint32_t mac_cmp32[2]; - uint16_t mac_cmp16[2]; - event_t *evt; - int tx; - pcap_log("PCAP: polling started.\n"); - thread_set_event(poll_state); + uint8_t *data = (uint8_t *) f_pcap_next((void *) pcap->pcap, &h); + if (!data) + return; - /* Create a waitable event. */ - pcap_log("PCAP: Creating event...\n"); - evt = thread_create_event(); - - /* As long as the channel is open.. */ - while (pcap != NULL) { - /* Request ownership of the device. */ - network_wait(1); - - if (pcap == NULL) { - network_wait(0); - break; - } - - if (network_get_wait() || (poll_card->set_link_state && poll_card->set_link_state(poll_card->priv)) || (poll_card->wait && poll_card->wait(poll_card->priv))) - data = NULL; - else - data = (uint8_t *)f_pcap_next((void *)pcap, &h); - if (data != NULL) { - /* Received MAC. */ - mac_cmp32[0] = *(uint32_t *)(data+6); - mac_cmp16[0] = *(uint16_t *)(data+10); - - /* Local MAC. */ - mac_cmp32[1] = *(uint32_t *)mac; - mac_cmp16[1] = *(uint16_t *)(mac+4); - if ((mac_cmp32[0] != mac_cmp32[1]) || - (mac_cmp16[0] != mac_cmp16[1])) - network_queue_put(0, poll_card->priv, data, h.caplen); - else { - /* Mark as invalid packet. */ - data = NULL; - } - } - - /* Wait for the next packet to arrive - network_do_tx() is called from there. */ - tx = network_tx_queue_check(); - - /* Release ownership of the device. */ - network_wait(0); - - /* If we did not get anything, wait a while. */ - if (!tx) - thread_wait_event(evt, 10); - } - - /* No longer needed. */ - if (evt != NULL) - thread_destroy_event(evt); - - pcap_log("PCAP: polling stopped.\n"); - if (poll_state != NULL) - thread_set_event(poll_state); + network_rx_put(pcap->card, data, h.caplen); } +/* Send a packet to the Pcap interface. */ +void +net_pcap_in(void *pcap, uint8_t *bufp, int len) +{ + if (pcap == NULL) + return; + + f_pcap_sendpacket((void *)pcap, bufp, len); +} + +void +net_pcap_in_available(void *priv) +{ + net_pcap_t *pcap = (net_pcap_t *)priv; + net_event_set(&pcap->tx_event); +} + +#ifdef _WIN32 +static void +net_pcap_thread(void *priv) +{ + net_pcap_t *pcap = (net_pcap_t*)priv; + + pcap_log("PCAP: polling started.\n"); + + HANDLE events[NET_EVENT_MAX]; + events[NET_EVENT_STOP] = net_event_get_handle(&pcap->stop_event); + events[NET_EVENT_TX] = net_event_get_handle(&pcap->tx_event); + events[NET_EVENT_RX] = f_pcap_getevent((void *)pcap->pcap); + + bool run = true; + + while (run) { + int ret = WaitForMultipleObjects(NET_EVENT_MAX, events, FALSE, INFINITE); + + switch (ret - WAIT_OBJECT_0) { + case NET_EVENT_STOP: + net_event_clear(&pcap->stop_event); + run = false; + break; + + case NET_EVENT_TX: + net_event_clear(&pcap->tx_event); + while (network_tx_pop(pcap->card, &pcap->pkt)) { + net_pcap_in(pcap->pcap, pcap->pkt.data, pcap->pkt.len); + } + break; + + case NET_EVENT_RX: + net_pcap_read_packet(pcap); + break; + } + } + + pcap_log("PCAP: polling stopped.\n"); +} +#else +static void +net_pcap_thread(void *priv) +{ + net_pcap_t *pcap = (net_pcap_t*)priv; + + pcap_log("PCAP: polling started.\n"); + + struct pollfd pfd[NET_EVENT_MAX]; + pfd[NET_EVENT_STOP].fd = net_event_get_fd(&pcap->stop_event); + pfd[NET_EVENT_STOP].events = POLLIN | POLLPRI; + + pfd[NET_EVENT_TX].fd = net_event_get_fd(&pcap->tx_event); + pfd[NET_EVENT_TX].events = POLLIN | POLLPRI; + + pfd[NET_EVENT_RX].fd = f_pcap_get_selectable_fd((void *) pcap->pcap); + pfd[NET_EVENT_RX].events = POLLIN | POLLPRI; + + /* As long as the channel is open.. */ + while (1) { + poll(pfd, NET_EVENT_MAX, -1); + + if (pfd[NET_EVENT_STOP].revents & POLLIN) { + net_event_clear(&pcap->stop_event); + break; + } + + if (pfd[NET_EVENT_TX].revents & POLLIN) { + net_event_clear(&pcap->tx_event); + + if (network_tx_pop(pcap->card, &pcap->pkt)) { + net_pcap_in(pcap->pcap, pcap->pkt.data, pcap->pkt.len); + } + } + + if (pfd[NET_EVENT_RX].revents & POLLIN) { + net_pcap_read_packet(pcap); + } + + } + + pcap_log("PCAP: polling stopped.\n"); +} +#endif /* * Prepare the (Win)Pcap module for use. @@ -244,18 +334,18 @@ net_pcap_prepare(netdev_t *list) pcap_if_t *devlist, *dev; int i = 0; - /* Local variables. */ - pcap = NULL; - /* Try loading the DLL. */ #ifdef _WIN32 - pcap_handle = dynld_module("wpcap.dll", pcap_imports); + libpcap_handle = dynld_module("wpcap.dll", pcap_imports); #elif defined __APPLE__ - pcap_handle = dynld_module("libpcap.dylib", pcap_imports); + libpcap_handle = dynld_module("libpcap.dylib", pcap_imports); #else - pcap_handle = dynld_module("libpcap.so", pcap_imports); + libpcap_handle = dynld_module("libpcap.so", pcap_imports); #endif - if (pcap_handle == NULL) return(-1); + if (libpcap_handle == NULL) { + pcap_log("PCAP: error loading pcap module\n"); + return(-1); + } /* Retrieve the device list from the local machine */ if (f_pcap_findalldevs(&devlist, errbuf) == -1) { @@ -292,141 +382,132 @@ net_pcap_prepare(netdev_t *list) /* * Initialize (Win)Pcap for use. * - * This is called on every 'cycle' of the emulator, - * if and as long the NetworkType is set to PCAP, - * and also as long as we have a NetCard defined. - */ -int -net_pcap_init(void) -{ - char errbuf[PCAP_ERRBUF_SIZE]; - char *str; - - /* Did we already load the library? */ - if (pcap_handle == NULL) - return(-1); - - /* Get the PCAP library name and version. */ - strcpy(errbuf, f_pcap_lib_version()); - str = strchr(errbuf, '('); - if (str != NULL) *(str-1) = '\0'; - pcap_log("PCAP: initializing, %s\n", errbuf); - - /* Get the value of our capture interface. */ - if ((network_host[0] == '\0') || !strcmp(network_host, "none")) { - pcap_log("PCAP: no interface configured!\n"); - return(-1); - } - - poll_tid = NULL; - poll_state = NULL; - poll_card = NULL; - - return(0); -} - - -/* Close up shop. */ -void -net_pcap_close(void) -{ - void *pc; - - if (pcap == NULL) return; - - pcap_log("PCAP: closing.\n"); - - /* Tell the polling thread to shut down. */ - pc = (void *)pcap; pcap = NULL; - - /* Tell the thread to terminate. */ - if (poll_tid != NULL) { - /* Wait for the thread to finish. */ - pcap_log("PCAP: waiting for thread to end...\n"); - thread_wait_event(poll_state, -1); - pcap_log("PCAP: thread ended\n"); - thread_destroy_event(poll_state); - - poll_tid = NULL; - poll_state = NULL; - poll_card = NULL; - } - - /* OK, now shut down Pcap itself. */ - f_pcap_close(pc); - pcap = NULL; -} - - -/* - * Reset (Win)Pcap and activate it. - * - * This is called on every 'cycle' of the emulator, - * if and as long the NetworkType is set to PCAP, - * and also as long as we have a NetCard defined. - * * We already know we have PCAP available, as this * is called when the network activates itself and * tries to attach to the network module. */ -int -net_pcap_reset(const netcard_t *card, uint8_t *mac) +void * +net_pcap_init(const netcard_t *card, const uint8_t *mac_addr, void *priv) { - char errbuf[PCAP_ERRBUF_SIZE]; + char errbuf[PCAP_ERRBUF_SIZE]; + char *str; char filter_exp[255]; struct bpf_program fp; - /* Open a PCAP live channel. */ - if ((pcap = f_pcap_open_live(network_host, /* interface name */ - 1518, /* max packet size */ - 1, /* promiscuous mode? */ - 10, /* timeout in msec */ - errbuf)) == NULL) { /* error buffer */ - pcap_log(" Unable to open device: %s!\n", network_host); - return(-1); + char *intf_name = (char*)priv; + + /* Did we already load the library? */ + if (libpcap_handle == NULL) { + pcap_log("PCAP: net_pcap_init without handle.\n"); + return NULL; } - if (f_pcap_setnonblock((void*)pcap, 1, errbuf) != 0) + + /* Get the PCAP library name and version. */ + strcpy(errbuf, f_pcap_lib_version()); + str = strchr(errbuf, '('); + if (str != NULL) + *(str - 1) = '\0'; + pcap_log("PCAP: initializing, %s\n", errbuf); + + /* Get the value of our capture interface. */ + if ((intf_name[0] == '\0') || !strcmp(intf_name, "none")) { + pcap_log("PCAP: no interface configured!\n"); + return NULL; + } + + pcap_log("PCAP: interface: %s\n", intf_name); + + net_pcap_t *pcap = calloc(1, sizeof(net_pcap_t)); + pcap->card = (netcard_t *)card; + memcpy(pcap->mac_addr, mac_addr, sizeof(pcap->mac_addr)); + + if ((pcap->pcap = f_pcap_create(intf_name, errbuf)) == NULL) { + pcap_log(" Unable to open device: %s!\n", intf_name); + free(pcap); + return NULL; + } + + if (f_pcap_setnonblock((void *) pcap->pcap, 1, errbuf) != 0) pcap_log("PCAP: failed nonblock %s\n", errbuf); - pcap_log("PCAP: interface: %s\n", network_host); + if (f_pcap_set_immediate_mode((void *) pcap->pcap, 1) != 0) + pcap_log("PCAP: error setting immediate mode\n"); + + if (f_pcap_set_promisc((void *) pcap->pcap, 1) != 0) + pcap_log("PCAP: error enabling promiscuous mode\n"); + + if (f_pcap_set_snaplen((void *) pcap->pcap, NET_MAX_FRAME) != 0) + pcap_log("PCAP: error setting snaplen\n"); + + if (f_pcap_activate((void *) pcap->pcap) != 0) { + pcap_log("PCAP: failed pcap_activate"); + f_pcap_close((void *) pcap->pcap); + free(pcap); + return NULL; + } /* Create a MAC address based packet filter. */ pcap_log("PCAP: installing filter for MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); sprintf(filter_exp, - "( ((ether dst ff:ff:ff:ff:ff:ff) or (ether dst %02x:%02x:%02x:%02x:%02x:%02x)) and not (ether src %02x:%02x:%02x:%02x:%02x:%02x) )", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - if (f_pcap_compile((void *)pcap, &fp, filter_exp, 0, 0xffffffff) != -1) { - if (f_pcap_setfilter((void *)pcap, &fp) != 0) { - pcap_log("PCAP: error installing filter (%s) !\n", filter_exp); - f_pcap_close((void *)pcap); - return(-1); - } + "( ((ether dst ff:ff:ff:ff:ff:ff) or (ether dst %02x:%02x:%02x:%02x:%02x:%02x)) and not (ether src %02x:%02x:%02x:%02x:%02x:%02x) )", + mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5], + mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); + if (f_pcap_compile((void *) pcap->pcap, &fp, filter_exp, 0, 0xffffffff) != -1) { + if (f_pcap_setfilter((void *) pcap->pcap, &fp) != 0) { + pcap_log("PCAP: error installing filter (%s) !\n", filter_exp); + f_pcap_close((void *) pcap->pcap); + free(pcap); + return NULL; + } } else { - pcap_log("PCAP: could not compile filter (%s) !\n", filter_exp); - f_pcap_close((void *)pcap); - return(-1); + pcap_log("PCAP: could not compile filter (%s) : %s!\n", filter_exp, f_pcap_geterr((void*)pcap->pcap)); + f_pcap_close((void *) pcap->pcap); + free(pcap); + return NULL; } - /* Save the callback info. */ - poll_card = card; + pcap->pkt.data = calloc(1, NET_MAX_FRAME); + net_event_init(&pcap->tx_event); + net_event_init(&pcap->stop_event); + pcap->poll_tid = thread_create(net_pcap_thread, pcap); - pcap_log("PCAP: starting thread..\n"); - poll_state = thread_create_event(); - poll_tid = thread_create(poll_thread, mac); - thread_wait_event(poll_state, -1); - - return(0); + return pcap; } - -/* Send a packet to the Pcap interface. */ +/* Close up shop. */ void -net_pcap_in(uint8_t *bufp, int len) +net_pcap_close(void *priv) { - if (pcap == NULL) - return; + if (!priv) + return; - f_pcap_sendpacket((void *)pcap, bufp, len); + net_pcap_t *pcap = (net_pcap_t *)priv; + + pcap_log("PCAP: closing.\n"); + + /* Tell the thread to terminate. */ + net_event_set(&pcap->stop_event); + + /* Wait for the thread to finish. */ + pcap_log("PCAP: waiting for thread to end...\n"); + thread_wait(pcap->poll_tid); + pcap_log("PCAP: thread ended\n"); + + free(pcap->pkt.data); + + /* OK, now shut down Pcap itself. */ + f_pcap_close((void*)pcap->pcap); + + net_event_close(&pcap->tx_event); + net_event_close(&pcap->stop_event); + + free(pcap); } + +const netdrv_t net_pcap_drv = { + &net_pcap_in_available, + &net_pcap_init, + &net_pcap_close, + NULL +}; diff --git a/src/network/net_pcnet.c b/src/network/net_pcnet.c index b4c56af53..25ced4679 100644 --- a/src/network/net_pcnet.c +++ b/src/network/net_pcnet.c @@ -41,6 +41,8 @@ #include <86box/random.h> #include <86box/device.h> #include <86box/isapnp.h> +#include <86box/timer.h> +#include <86box/thread.h> #include <86box/network.h> #include <86box/net_pcnet.h> #include <86box/bswap.h> @@ -259,6 +261,7 @@ typedef struct { int transfer_size; uint8_t maclocal[6]; /* configured MAC (local) address */ pc_timer_t timer, timer_soft_int, timer_restore; + netcard_t *netcard; } nic_t; /** @todo All structs: big endian? */ @@ -1528,7 +1531,7 @@ pcnetAsyncTransmit(nic_t *dev) pcnetReceiveNoSync(dev, dev->abLoopBuf, dev->xmit_pos); } else { pcnetlog(3, "%s: pcnetAsyncTransmit: transmit loopbuf stp and enp, xmit pos = %d\n", dev->name, dev->xmit_pos); - network_tx(dev->abLoopBuf, dev->xmit_pos); + network_tx(dev->netcard, dev->abLoopBuf, dev->xmit_pos); } } else if (cb == 4096) { /* The Windows NT4 pcnet driver sometimes marks the first @@ -1639,7 +1642,7 @@ pcnetAsyncTransmit(nic_t *dev) pcnetReceiveNoSync(dev, dev->abLoopBuf, dev->xmit_pos); } else { pcnetlog(3, "%s: pcnetAsyncTransmit: transmit loopbuf enp\n", dev->name); - network_tx(dev->abLoopBuf, dev->xmit_pos); + network_tx(dev->netcard, dev->abLoopBuf, dev->xmit_pos); } /* Write back the TMD, pass it to the host */ @@ -3051,7 +3054,7 @@ pcnet_init(const device_t *info) pcnetHardReset(dev); /* Attach ourselves to the network module. */ - network_attach(dev, dev->aPROM, pcnetReceiveNoSync, pcnetWaitReceiveAvail, pcnetSetLinkState); + dev->netcard = network_attach(dev, dev->aPROM, pcnetReceiveNoSync, pcnetWaitReceiveAvail, pcnetSetLinkState); timer_add(&dev->timer, pcnetPollTimer, dev, 0); @@ -3071,8 +3074,7 @@ pcnet_close(void *priv) pcnetlog(1, "%s: closed\n", dev->name); - /* Make sure the platform layer is shut down. */ - network_close(); + netcard_close(dev->netcard); if (dev) { free(dev); diff --git a/src/network/net_plip.c b/src/network/net_plip.c index 6da355632..cf1a0f9c3 100644 --- a/src/network/net_plip.c +++ b/src/network/net_plip.c @@ -31,6 +31,8 @@ #include <86box/timer.h> #include <86box/pit.h> #include <86box/device.h> +#include <86box/thread.h> +#include <86box/timer.h> #include <86box/network.h> #include <86box/net_plip.h> @@ -70,6 +72,7 @@ typedef struct uint8_t *rx_pkt, rx_checksum, rx_return_state; uint16_t rx_len, rx_ptr; + netcard_t *card; } plip_t; @@ -117,8 +120,6 @@ timeout_timer(void *priv) dev->rx_pkt = NULL; } - network_rx_pause = 0; - timer_disable(&dev->timeout_timer); } @@ -229,7 +230,7 @@ plip_write_data(uint8_t val, void *priv) /* Transmit packet. */ plip_log(2, "PLIP: transmitting %d-byte packet\n", dev->tx_len); - network_tx(dev->tx_pkt, dev->tx_len); + network_tx(dev->card, dev->tx_pkt, dev->tx_len); } else { plip_log(1, "PLIP: checksum error: expected %02X, got %02X\n", dev->tx_checksum_calc, dev->tx_checksum); } @@ -381,7 +382,6 @@ plip_receive_packet(plip_t *dev) } if (!dev->rx_pkt || !dev->rx_len) { /* unpause RX queue if there's no packet to receive */ - network_rx_pause = 0; return; } @@ -432,8 +432,6 @@ plip_rx(void *priv, uint8_t *buf, int io_len) if (!(dev->rx_pkt = malloc(io_len))) /* unlikely */ fatal("PLIP: unable to allocate rx_pkt\n"); - network_rx_pause = 1; /* make sure we don't get any more packets while processing this one */ - /* Copy this packet to our buffer. */ dev->rx_len = io_len; memcpy(dev->rx_pkt, buf, dev->rx_len); @@ -478,7 +476,7 @@ plip_net_init(const device_t *info) } plip_log(1, " (attached to LPT)\n"); - network_attach(instance, instance->mac, plip_rx, NULL, NULL); + instance->card = network_attach(instance, instance->mac, plip_rx, NULL, NULL); return instance; } @@ -487,6 +485,9 @@ plip_net_init(const device_t *info) static void plip_close(void *priv) { + if (instance->card) { + netcard_close(instance->card); + } free(priv); } diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index bc7c68783..90812d17e 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -24,52 +24,51 @@ #include #include #include +#include #include +#include +#include #include #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> #include <86box/plat.h> #include <86box/thread.h> +#include <86box/timer.h> #include <86box/network.h> #include <86box/machine.h> -#include <86box/timer.h> #include <86box/config.h> - - -/* SLiRP can use poll() or select() for socket polling. - poll() is best on *nix but slow and limited on Windows. */ -#ifndef _WIN32 -# define SLIRP_USE_POLL 1 -#endif -#ifdef SLIRP_USE_POLL -# ifdef _WIN32 -# include -# define poll WSAPoll -# else -# include -# endif +#include <86box/video.h> +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#else +#include #endif +#include <86box/net_event.h> +enum { + NET_EVENT_STOP = 0, + NET_EVENT_TX, + NET_EVENT_RX, + NET_EVENT_MAX +}; typedef struct { - Slirp *slirp; - void *mac; - const netcard_t *card; /* netcard attached to us */ - volatile thread_t *poll_tid; - event_t *poll_state; - uint8_t stop; -#ifdef SLIRP_USE_POLL - uint32_t pfd_len, pfd_size; - struct pollfd *pfd; + Slirp *slirp; + uint8_t mac_addr[6]; + netcard_t *card; /* netcard attached to us */ + thread_t *poll_tid; + net_evt_t tx_event; + net_evt_t stop_event; + netpkt_t pkt; +#ifdef _WIN32 + HANDLE sock_event; #else - uint32_t nfds; - fd_set rfds, wfds, xfds; + uint32_t pfd_len, pfd_size; + struct pollfd *pfd; #endif -} slirp_t; - -static slirp_t *slirp; - +} net_slirp_t; #ifdef ENABLE_SLIRP_LOG int slirp_do_log = ENABLE_SLIRP_LOG; @@ -101,7 +100,7 @@ net_slirp_guest_error(const char *msg, void *opaque) static int64_t net_slirp_clock_get_ns(void *opaque) { - return (TIMER_USEC ? (tsc / (TIMER_USEC / 1000)) : 0); + return (int64_t)((double)tsc / cpuclock * 1000000000.0); } @@ -118,13 +117,14 @@ static void net_slirp_timer_free(void *timer, void *opaque) { timer_stop(timer); + free(timer); } static void net_slirp_timer_mod(void *timer, int64_t expire_timer, void *opaque) { - timer_set_delay_u64(timer, expire_timer); + timer_on_auto(timer, expire_timer * 1000); } @@ -154,138 +154,131 @@ net_slirp_notify(void *opaque) ssize_t net_slirp_send_packet(const void *qp, size_t pkt_len, void *opaque) { - slirp_t *slirp = (slirp_t *) opaque; - uint8_t *mac = slirp->mac; + net_slirp_t *slirp = (net_slirp_t *) opaque; + uint8_t *mac = slirp->mac_addr; uint32_t mac_cmp32[2]; uint16_t mac_cmp16[2]; - if (!(slirp->card->set_link_state && slirp->card->set_link_state(slirp->card->priv)) && !(slirp->card->wait && slirp->card->wait(slirp->card->priv))) { - slirp_log("SLiRP: received %d-byte packet\n", pkt_len); + slirp_log("SLiRP: received %d-byte packet\n", pkt_len); - /* Received MAC. */ - mac_cmp32[0] = *(uint32_t *) (((uint8_t *) qp) + 6); - mac_cmp16[0] = *(uint16_t *) (((uint8_t *) qp) + 10); + /* Received MAC. */ + mac_cmp32[0] = *(uint32_t *) (((uint8_t *) qp) + 6); + mac_cmp16[0] = *(uint16_t *) (((uint8_t *) qp) + 10); - /* Local MAC. */ - mac_cmp32[1] = *(uint32_t *) mac; - mac_cmp16[1] = *(uint16_t *) (mac + 4); - if ((mac_cmp32[0] != mac_cmp32[1]) || - (mac_cmp16[0] != mac_cmp16[1])) { - network_queue_put(0, slirp->card->priv, (uint8_t *) qp, pkt_len); - } - - return pkt_len; - } else { - slirp_log("SLiRP: ignored %d-byte packet\n", pkt_len); + /* Local MAC. */ + mac_cmp32[1] = *(uint32_t *) mac; + mac_cmp16[1] = *(uint16_t *) (mac + 4); + if ((mac_cmp32[0] != mac_cmp32[1]) || (mac_cmp16[0] != mac_cmp16[1])) { + network_rx_put(slirp->card, (uint8_t *) qp, pkt_len); } - return 0; + return pkt_len; } +#ifdef _WIN32 static int net_slirp_add_poll(int fd, int events, void *opaque) { - slirp_t *slirp = (slirp_t *) opaque; -#ifdef SLIRP_USE_POLL + net_slirp_t *slirp = (net_slirp_t *) opaque; + long bitmask = 0; + if (events & SLIRP_POLL_IN) + bitmask |= FD_READ | FD_ACCEPT; + if (events & SLIRP_POLL_OUT) + bitmask |= FD_WRITE | FD_CONNECT; + if (events & SLIRP_POLL_HUP) + bitmask |= FD_CLOSE; + if (events & SLIRP_POLL_PRI) + bitmask |= FD_OOB; + + WSAEventSelect(fd, slirp->sock_event, bitmask); + return fd; +} +#else +static int +net_slirp_add_poll(int fd, int events, void *opaque) +{ + net_slirp_t *slirp = (net_slirp_t *) opaque; + if (slirp->pfd_len >= slirp->pfd_size) { - int newsize = slirp->pfd_size + 16; - struct pollfd *new = realloc(slirp->pfd, newsize * sizeof(struct pollfd)); - if (new) { - slirp->pfd = new; - slirp->pfd_size = newsize; - } + int newsize = slirp->pfd_size + 16; + struct pollfd *new = realloc(slirp->pfd, newsize * sizeof(struct pollfd)); + if (new) { + slirp->pfd = new; + slirp->pfd_size = newsize; + } } if ((slirp->pfd_len < slirp->pfd_size)) { - int idx = slirp->pfd_len++; - slirp->pfd[idx].fd = fd; - int pevents = 0; - if (events & SLIRP_POLL_IN) pevents |= POLLIN; - if (events & SLIRP_POLL_OUT) pevents |= POLLOUT; -# ifndef _WIN32 - /* Windows does not support some events. */ - if (events & SLIRP_POLL_ERR) pevents |= POLLERR; - if (events & SLIRP_POLL_PRI) pevents |= POLLPRI; - if (events & SLIRP_POLL_HUP) pevents |= POLLHUP; -# endif - slirp->pfd[idx].events = pevents; - return idx; + int idx = slirp->pfd_len++; + slirp->pfd[idx].fd = fd; + int pevents = 0; + if (events & SLIRP_POLL_IN) + pevents |= POLLIN; + if (events & SLIRP_POLL_OUT) + pevents |= POLLOUT; + if (events & SLIRP_POLL_ERR) + pevents |= POLLERR; + if (events & SLIRP_POLL_PRI) + pevents |= POLLPRI; + if (events & SLIRP_POLL_HUP) + pevents |= POLLHUP; + slirp->pfd[idx].events = pevents; + return idx; } else - return -1; -#else - if (events & SLIRP_POLL_IN) - FD_SET(fd, &slirp->rfds); - if (events & SLIRP_POLL_OUT) - FD_SET(fd, &slirp->wfds); - if (events & SLIRP_POLL_PRI) - FD_SET(fd, &slirp->xfds); - if (fd > slirp->nfds) - slirp->nfds = fd; - return fd; -#endif + return -1; } +#endif - +#ifdef _WIN32 static int net_slirp_get_revents(int idx, void *opaque) { - slirp_t *slirp = (slirp_t *) opaque; + net_slirp_t *slirp = (net_slirp_t *) opaque; int ret = 0; -#ifdef SLIRP_USE_POLL - int events = slirp->pfd[idx].revents; - if (events & POLLIN) ret |= SLIRP_POLL_IN; - if (events & POLLOUT) ret |= SLIRP_POLL_OUT; - if (events & POLLPRI) ret |= SLIRP_POLL_PRI; - if (events & POLLERR) ret |= SLIRP_POLL_ERR; - if (events & POLLHUP) ret |= SLIRP_POLL_HUP; -#else - if (FD_ISSET(idx, &slirp->rfds)) - ret |= SLIRP_POLL_IN; - if (FD_ISSET(idx, &slirp->wfds)) - ret |= SLIRP_POLL_OUT; - if (FD_ISSET(idx, &slirp->xfds)) - ret |= SLIRP_POLL_PRI; -#endif + WSANETWORKEVENTS ev; + if (WSAEnumNetworkEvents(idx, slirp->sock_event, &ev) != 0) { + return ret; + } + +# define WSA_TO_POLL(_wsaev, _pollev) \ + do { \ + if (ev.lNetworkEvents & (_wsaev)) { \ + ret |= (_pollev); \ + if (ev.iErrorCode[_wsaev##_BIT] != 0) { \ + ret |= SLIRP_POLL_ERR; \ + } \ + } \ + } while (0) + + WSA_TO_POLL(FD_READ, SLIRP_POLL_IN); + WSA_TO_POLL(FD_ACCEPT, SLIRP_POLL_IN); + WSA_TO_POLL(FD_WRITE, SLIRP_POLL_OUT); + WSA_TO_POLL(FD_CONNECT, SLIRP_POLL_OUT); + WSA_TO_POLL(FD_OOB, SLIRP_POLL_PRI); + WSA_TO_POLL(FD_CLOSE, SLIRP_POLL_HUP); + return ret; } - - -static void -slirp_tic(slirp_t *slirp) +#else +static int +net_slirp_get_revents(int idx, void *opaque) { - int ret; - uint32_t tmo; - - /* Let SLiRP create a list of all open sockets. */ -#ifdef SLIRP_USE_POLL - tmo = -1; - slirp->pfd_len = 0; -#else - slirp->nfds = -1; - FD_ZERO(&slirp->rfds); - FD_ZERO(&slirp->wfds); - FD_ZERO(&slirp->xfds); -#endif - slirp_pollfds_fill(slirp->slirp, &tmo, net_slirp_add_poll, slirp); - - /* Now wait for something to happen, or at most 'tmo' usec. */ -#ifdef SLIRP_USE_POLL - ret = poll(slirp->pfd, slirp->pfd_len, tmo); -#else - if (tmo < 0) - tmo = 500; - - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = tmo; - - ret = select(slirp->nfds + 1, &slirp->rfds, &slirp->wfds, &slirp->xfds, &tv); -#endif - - /* If something happened, let SLiRP handle it. */ - slirp_pollfds_poll(slirp->slirp, (ret <= 0), net_slirp_get_revents, slirp); + net_slirp_t *slirp = (net_slirp_t *) opaque; + int ret = 0; + int events = slirp->pfd[idx].revents; + if (events & POLLIN) + ret |= SLIRP_POLL_IN; + if (events & POLLOUT) + ret |= SLIRP_POLL_OUT; + if (events & POLLPRI) + ret |= SLIRP_POLL_PRI; + if (events & POLLERR) + ret |= SLIRP_POLL_ERR; + if (events & POLLHUP) + ret |= SLIRP_POLL_HUP; + return ret; } - +#endif static const SlirpCb slirp_cb = { .send_packet = net_slirp_send_packet, @@ -299,176 +292,210 @@ static const SlirpCb slirp_cb = { .notify = net_slirp_notify }; - -/* Handle the receiving of frames. */ +/* Send a packet to the SLiRP interface. */ static void -poll_thread(void *arg) -{ - slirp_t *slirp = (slirp_t *) arg; - event_t *evt; - int tx; - - slirp_log("SLiRP: initializing...\n"); - - /* Set the IP addresses to use. */ - struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */ - struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */ - struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */ - struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */ - struct in_addr dns = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */ - struct in_addr bind = { .s_addr = htonl(0x00000000) }; /* 0.0.0.0 */ - struct in6_addr ipv6_dummy = { 0 }; /* contents don't matter; we're not using IPv6 */ - - /* Initialize SLiRP. */ - slirp->slirp = slirp_init(0, 1, net, mask, host, 0, ipv6_dummy, 0, ipv6_dummy, NULL, NULL, NULL, NULL, dhcp, dns, ipv6_dummy, NULL, NULL, &slirp_cb, arg); - if (!slirp->slirp) { - slirp_log("SLiRP: initialization failed\n"); - return; - } - - /* Set up port forwarding. */ - int udp, external, internal, i = 0; - char *category = "SLiRP Port Forwarding"; - char key[20]; - while (1) { - sprintf(key, "%d_protocol", i); - udp = strcmp(config_get_string(category, key, "tcp"), "udp") == 0; - sprintf(key, "%d_external", i); - external = config_get_int(category, key, 0); - sprintf(key, "%d_internal", i); - internal = config_get_int(category, key, 0); - if ((external <= 0) && (internal <= 0)) - break; - else if (internal <= 0) - internal = external; - else if (external <= 0) - external = internal; - - if (slirp_add_hostfwd(slirp->slirp, udp, bind, external, dhcp, internal) == 0) - pclog("SLiRP: Forwarded %s port external:%d to internal:%d\n", udp ? "UDP" : "TCP", external, internal); - else - pclog("SLiRP: Failed to forward %s port external:%d to internal:%d\n", udp ? "UDP" : "TCP", external, internal); - - i++; - } - - /* Start polling. */ - slirp_log("SLiRP: polling started.\n"); - thread_set_event(slirp->poll_state); - - /* Create a waitable event. */ - evt = thread_create_event(); - - while (!slirp->stop) { - /* Request ownership of the queue. */ - network_wait(1); - - /* Stop processing if asked to. */ - if (slirp->stop) { - network_wait(0); - break; - } - - /* See if there is any work. */ - slirp_tic(slirp); - - /* Wait for the next packet to arrive - network_do_tx() is called from there. */ - tx = network_tx_queue_check(); - - /* Release ownership of the queue. */ - network_wait(0); - - /* If we did not get anything, wait a while. */ - if (!tx) - thread_wait_event(evt, 10); - } - - /* No longer needed. */ - if (evt) - thread_destroy_event(evt); - - slirp_log("SLiRP: polling stopped.\n"); - thread_set_event(slirp->poll_state); - - /* Destroy event here to avoid a crash. */ - slirp_log("SLiRP: thread ended\n"); - thread_destroy_event(slirp->poll_state); - /* Free here instead of immediately freeing the global slirp on the main - thread to avoid a race condition. */ - slirp_cleanup(slirp->slirp); - free(slirp); -} - - -/* Initialize SLiRP for use. */ -int -net_slirp_init(void) -{ - return 0; -} - - -/* Initialize SLiRP for use. */ -int -net_slirp_reset(const netcard_t *card, uint8_t *mac) -{ - slirp_t *new_slirp = malloc(sizeof(slirp_t)); - memset(new_slirp, 0, sizeof(slirp_t)); - new_slirp->mac = mac; - new_slirp->card = card; -#ifdef SLIRP_USE_POLL - new_slirp->pfd_size = 16 * sizeof(struct pollfd); - new_slirp->pfd = malloc(new_slirp->pfd_size); - memset(new_slirp->pfd, 0, new_slirp->pfd_size); -#endif - - /* Save the callback info. */ - slirp = new_slirp; - - slirp_log("SLiRP: creating thread...\n"); - slirp->poll_state = thread_create_event(); - slirp->poll_tid = thread_create(poll_thread, new_slirp); - thread_wait_event(slirp->poll_state, -1); - - return 0; -} - - -void -net_slirp_close(void) +net_slirp_in(net_slirp_t *slirp, uint8_t *pkt, int pkt_len) { if (!slirp) - return; + return; - slirp_log("SLiRP: closing\n"); - - /* Tell the polling thread to shut down. */ - slirp->stop = 1; - - /* Tell the thread to terminate. */ - if (slirp->poll_tid) { - /* Wait for the thread to finish. */ - slirp_log("SLiRP: waiting for thread to end...\n"); - thread_wait_event(slirp->poll_state, -1); - } - - /* Shutdown work is done by the thread on its local copy of slirp. */ - slirp = NULL; -} - - -/* Send a packet to the SLiRP interface. */ -void -net_slirp_in(uint8_t *pkt, int pkt_len) -{ - if (!slirp || !slirp->slirp) - return; - - slirp_log("SLiRP: sending %d-byte packet\n", pkt_len); + slirp_log("SLiRP: sending %d-byte packet to host network\n", pkt_len); slirp_input(slirp->slirp, (const uint8_t *) pkt, pkt_len); } +void +net_slirp_in_available(void *priv) +{ + net_slirp_t *slirp = (net_slirp_t *)priv; + net_event_set(&slirp->tx_event); +} + +#ifdef _WIN32 +static void +net_slirp_thread(void *priv) +{ + net_slirp_t *slirp = (net_slirp_t *) priv; + + /* Start polling. */ + slirp_log("SLiRP: polling started.\n"); + + HANDLE events[3]; + events[NET_EVENT_STOP] = net_event_get_handle(&slirp->stop_event); + events[NET_EVENT_TX] = net_event_get_handle(&slirp->tx_event); + events[NET_EVENT_RX] = slirp->sock_event; + bool run = true; + while (run) { + uint32_t timeout = -1; + slirp_pollfds_fill(slirp->slirp, &timeout, net_slirp_add_poll, slirp); + if (timeout < 0) + timeout = INFINITE; + + int ret = WaitForMultipleObjects(3, events, FALSE, (DWORD)timeout); + switch (ret - WAIT_OBJECT_0) { + case NET_EVENT_STOP: + run = false; + break; + + case NET_EVENT_TX: + while (network_tx_pop(slirp->card, &slirp->pkt)) { + net_slirp_in(slirp, slirp->pkt.data, slirp->pkt.len); + } + break; + + default: + slirp_pollfds_poll(slirp->slirp, ret == WAIT_FAILED, net_slirp_get_revents, slirp); + break; + + } + } + + slirp_log("SLiRP: polling stopped.\n"); +} +#else +/* Handle the receiving of frames. */ +static void +net_slirp_thread(void *priv) +{ + net_slirp_t *slirp = (net_slirp_t *) priv; + + /* Start polling. */ + slirp_log("SLiRP: polling started.\n"); + + while (1) { + uint32_t timeout = -1; + + slirp->pfd_len = 0; + net_slirp_add_poll(net_event_get_fd(&slirp->stop_event), SLIRP_POLL_IN, slirp); + net_slirp_add_poll(net_event_get_fd(&slirp->tx_event), SLIRP_POLL_IN, slirp); + + slirp_pollfds_fill(slirp->slirp, &timeout, net_slirp_add_poll, slirp); + + int ret = poll(slirp->pfd, slirp->pfd_len, timeout); + + slirp_pollfds_poll(slirp->slirp, (ret < 0), net_slirp_get_revents, slirp); + + if (slirp->pfd[NET_EVENT_STOP].revents & POLLIN) { + net_event_clear(&slirp->stop_event); + break; + } + + if (slirp->pfd[NET_EVENT_TX].revents & POLLIN) { + net_event_clear(&slirp->tx_event); + + if (network_tx_pop(slirp->card, &slirp->pkt)) { + net_slirp_in(slirp, slirp->pkt.data, slirp->pkt.len); + } + } + + } + + slirp_log("SLiRP: polling stopped.\n"); +} +#endif + +static int slirp_card_num = 2; + +/* Initialize SLiRP for use. */ +void * +net_slirp_init(const netcard_t *card, const uint8_t *mac_addr, void *priv) +{ + slirp_log("SLiRP: initializing...\n"); + net_slirp_t *slirp = calloc(1, sizeof(net_slirp_t)); + memcpy(slirp->mac_addr, mac_addr, sizeof(slirp->mac_addr)); + slirp->card = (netcard_t*)card; + +#ifndef _WIN32 + slirp->pfd_size = 16 * sizeof(struct pollfd); + slirp->pfd = malloc(slirp->pfd_size); + memset(slirp->pfd, 0, slirp->pfd_size); +#endif + + /* Set the IP addresses to use. */ + struct in_addr net = { .s_addr = htonl(0x0a000000 | (slirp_card_num << 8)) }; /* 10.0.x.0 */ + struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */ + struct in_addr host = { .s_addr = htonl(0x0a000002 | (slirp_card_num << 8)) }; /* 10.0.x.2 */ + struct in_addr dhcp = { .s_addr = htonl(0x0a00000f | (slirp_card_num << 8)) }; /* 10.0.x.15 */ + struct in_addr dns = { .s_addr = htonl(0x0a000003 | (slirp_card_num << 8)) }; /* 10.0.x.3 */ + struct in_addr bind = { .s_addr = htonl(0x00000000 | (slirp_card_num << 8)) }; /* 0.0.0.0 */ + struct in6_addr ipv6_dummy = { 0 }; /* contents don't matter; we're not using IPv6 */ + + /* Initialize SLiRP. */ + slirp->slirp = slirp_init(0, 1, net, mask, host, 0, ipv6_dummy, 0, ipv6_dummy, NULL, NULL, NULL, NULL, dhcp, dns, ipv6_dummy, NULL, NULL, &slirp_cb, slirp); + if (!slirp->slirp) { + slirp_log("SLiRP: initialization failed\n"); + free(slirp); + return NULL; + } + + /* Set up port forwarding. */ + int udp, external, internal, i = 0; + char *category = "SLiRP Port Forwarding"; + char key[20]; + while (1) { + sprintf(key, "%d_protocol", i); + udp = strcmp(config_get_string(category, key, "tcp"), "udp") == 0; + sprintf(key, "%d_external", i); + external = config_get_int(category, key, 0); + sprintf(key, "%d_internal", i); + internal = config_get_int(category, key, 0); + if ((external <= 0) && (internal <= 0)) + break; + else if (internal <= 0) + internal = external; + else if (external <= 0) + external = internal; + + if (slirp_add_hostfwd(slirp->slirp, udp, bind, external, dhcp, internal) == 0) + pclog("SLiRP: Forwarded %s port external:%d to internal:%d\n", udp ? "UDP" : "TCP", external, internal); + else + pclog("SLiRP: Failed to forward %s port external:%d to internal:%d\n", udp ? "UDP" : "TCP", external, internal); + + i++; + } + + slirp->pkt.data = calloc(1, NET_MAX_FRAME); + net_event_init(&slirp->tx_event); + net_event_init(&slirp->stop_event); +#ifdef _WIN32 + slirp->sock_event = CreateEvent(NULL, FALSE, FALSE, NULL); +#endif + slirp_log("SLiRP: creating thread...\n"); + slirp->poll_tid = thread_create(net_slirp_thread, slirp); + + slirp_card_num++; + return slirp; +} + +void +net_slirp_close(void *priv) +{ + if (!priv) + return; + + net_slirp_t *slirp = (net_slirp_t *) priv; + + slirp_log("SLiRP: closing\n"); + /* Tell the polling thread to shut down. */ + net_event_set(&slirp->stop_event); + + /* Wait for the thread to finish. */ + slirp_log("SLiRP: waiting for thread to end...\n"); + thread_wait(slirp->poll_tid); + + net_event_close(&slirp->tx_event); + net_event_close(&slirp->stop_event); + slirp_cleanup(slirp->slirp); + free(slirp->pkt.data); + free(slirp); + slirp_card_num--; +} + +const netdrv_t net_slirp_drv = { + &net_slirp_in_available, + &net_slirp_init, + &net_slirp_close +}; /* Stubs to stand in for the parts of libslirp we skip compiling. */ void ncsi_input(void *slirp, const uint8_t *pkt, int pkt_len) {} diff --git a/src/network/net_wd8003.c b/src/network/net_wd8003.c index 81429fe19..be52a11aa 100644 --- a/src/network/net_wd8003.c +++ b/src/network/net_wd8003.c @@ -58,6 +58,8 @@ #include <86box/pic.h> #include <86box/random.h> #include <86box/device.h> +#include <86box/timer.h> +#include <86box/thread.h> #include <86box/network.h> #include <86box/net_dp8390.h> #include <86box/net_wd8003.h> @@ -696,7 +698,7 @@ wd_init(const device_t *info) dev->ram_addr = device_get_config_hex20("ram_addr"); } - dev->dp8390 = device_add(&dp8390_device); + dev->dp8390 = device_add_inst(&dp8390_device, dp3890_inst++); dev->dp8390->priv = dev; dev->dp8390->interrupt = wd_interrupt; dp8390_set_defaults(dev->dp8390, DP8390_FLAG_CHECK_CR | DP8390_FLAG_CLEAR_IRQ); @@ -786,7 +788,7 @@ wd_init(const device_t *info) mem_mapping_disable(&dev->ram_mapping); /* Attach ourselves to the network module. */ - network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL, NULL); + dev->dp8390->card = network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL, NULL); if (!(dev->board_chip & WE_ID_BUS_MCA)) { wdlog("%s: attached IO=0x%X IRQ=%d, RAM addr=0x%06x\n", dev->name, diff --git a/src/network/network.c b/src/network/network.c index 6a7fbdfa5..714037b4c 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -56,6 +56,7 @@ #include #include #include +#include #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> @@ -63,6 +64,7 @@ #include <86box/plat.h> #include <86box/thread.h> #include <86box/ui.h> +#include <86box/timer.h> #include <86box/network.h> #include <86box/net_3c503.h> #include <86box/net_ne2000.h> @@ -70,6 +72,11 @@ #include <86box/net_plip.h> #include <86box/net_wd8003.h> +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#endif static const device_t net_none_device = { .name = "None", @@ -86,32 +93,32 @@ static const device_t net_none_device = { }; -static netcard_t net_cards[] = { -// clang-format off - { &net_none_device, NULL }, - { &threec503_device, NULL }, - { &pcnet_am79c960_device, NULL }, - { &pcnet_am79c961_device, NULL }, - { &ne1000_device, NULL }, - { &ne2000_device, NULL }, - { &pcnet_am79c960_eb_device, NULL }, - { &rtl8019as_device, NULL }, - { &wd8003e_device, NULL }, - { &wd8003eb_device, NULL }, - { &wd8013ebt_device, NULL }, - { &plip_device, NULL }, - { ðernext_mc_device, NULL }, - { &wd8003eta_device, NULL }, - { &wd8003ea_device, NULL }, - { &wd8013epa_device, NULL }, - { &pcnet_am79c973_device, NULL }, - { &pcnet_am79c970a_device, NULL }, - { &rtl8029as_device, NULL }, - { &pcnet_am79c960_vlb_device, NULL }, - { NULL, NULL } -// clang-format off +static const device_t *net_cards[] = { + &net_none_device, + &threec503_device, + &pcnet_am79c960_device, + &pcnet_am79c961_device, + &ne1000_device, + &ne2000_device, + &pcnet_am79c960_eb_device, + &rtl8019as_device, + &wd8003e_device, + &wd8003eb_device, + &wd8013ebt_device, + &plip_device, + ðernext_mc_device, + &wd8003eta_device, + &wd8003ea_device, + &wd8013epa_device, + &pcnet_am79c973_device, + &pcnet_am79c970a_device, + &rtl8029as_device, + &pcnet_am79c960_vlb_device, + NULL }; +netcard_conf_t net_cards_conf[NET_CARD_MAX]; +int net_card_current = 0; /* Global variables. */ int network_type; @@ -119,20 +126,9 @@ int network_ndev; int network_card; char network_host[522]; netdev_t network_devs[32]; -int network_rx_pause = 0, - network_tx_pause = 0; /* Local variables. */ -static volatile atomic_int net_wait = 0; -static mutex_t *network_mutex; -static uint8_t *network_mac; -static uint8_t network_timer_active = 0; -static pc_timer_t network_rx_queue_timer; -static netpkt_t *first_pkt[3] = { NULL, NULL, NULL }, - *last_pkt[3] = { NULL, NULL, NULL }; -static netpkt_t queued_pkt; - #ifdef ENABLE_NETWORK_LOG int network_do_log = ENABLE_NETWORK_LOG; @@ -191,15 +187,13 @@ network_dump_packet(netpkt_t *pkt) #endif -void -network_wait(uint8_t wait) +#ifdef _WIN32 +static void +network_winsock_clean(void) { - if (wait) - thread_wait_mutex(network_mutex); - else - thread_release_mutex(network_mutex); + WSACleanup(); } - +#endif /* * Initialize the configured network cards. @@ -213,9 +207,11 @@ network_init(void) { int i; - /* Initialize to a known state. */ - network_type = NET_TYPE_NONE; - network_card = 0; +#ifdef _WIN32 + WSADATA Data; + WSAStartup(MAKEWORD(2, 0), &Data); + atexit(network_winsock_clean); +#endif /* Create a first device entry that's always there, as needed by UI. */ strcpy(network_devs[0].device, "none"); @@ -247,156 +243,133 @@ network_init(void) #endif } - -void -network_queue_put(int tx, void *priv, uint8_t *data, int len) -{ - netpkt_t *temp; - - temp = (netpkt_t *) calloc(sizeof(netpkt_t), 1); - temp->priv = priv; - memcpy(temp->data, data, len); - temp->len = len; - temp->prev = last_pkt[tx]; - temp->next = NULL; - - if (last_pkt[tx] != NULL) - last_pkt[tx]->next = temp; - last_pkt[tx] = temp; - - if (first_pkt[tx] == NULL) - first_pkt[tx] = temp; -} - - static void -network_queue_get(int tx, netpkt_t *pkt) +network_queue_init(netqueue_t *queue) { - netpkt_t *temp; - - temp = first_pkt[tx]; - - if (temp == NULL) { - memset(pkt, 0x00, sizeof(netpkt_t)); - return; + queue->size = NET_QUEUE_LEN; + queue->head = queue->tail = 0; + for (int i=0; isize; i++) { + queue->packets[i].data = calloc(1, NET_MAX_FRAME); + queue->packets[i].len = 0; } - memcpy(pkt, temp, sizeof(netpkt_t)); - - first_pkt[tx] = temp->next; - free(temp); - - if (first_pkt[tx] == NULL) - last_pkt[tx] = NULL; } - -static void -network_queue_transmit(int tx) +static bool +network_queue_full(netqueue_t *queue) { - netpkt_t *temp; + return ((queue->head + 1) % queue->size) == queue->tail; +} - temp = first_pkt[tx]; +static bool +network_queue_empty(netqueue_t *queue) +{ + return (queue->head == queue->tail); +} - if (temp == NULL) - return; - - if (temp->len > 0) { - network_dump_packet(temp); - /* Why on earth is this not a function pointer?! */ - switch(network_type) { - case NET_TYPE_PCAP: - net_pcap_in(temp->data, temp->len); - break; - - case NET_TYPE_SLIRP: - net_slirp_in(temp->data, temp->len); - break; - } +int +network_queue_put(netqueue_t *queue, uint8_t *data, int len) +{ + if (len > NET_MAX_FRAME || network_queue_full(queue)) { + return 0; } - first_pkt[tx] = temp->next; - free(temp); - - if (first_pkt[tx] == NULL) - last_pkt[tx] = NULL; + netpkt_t *pkt = &queue->packets[queue->head]; + memcpy(pkt->data, data, len); + pkt->len = len; + queue->head = (queue->head + 1) % queue->size; + return 1; } +static int +network_queue_get(netqueue_t *queue, netpkt_t *dst_pkt) { + if (network_queue_empty(queue)) + return 0; -static void -network_queue_copy(int dest, int src) -{ - netpkt_t *temp, *temp2; + netpkt_t *pkt = &queue->packets[queue->tail]; + memcpy(dst_pkt->data, pkt->data, pkt->len); + dst_pkt->len = pkt->len; + queue->tail = (queue->tail + 1) % queue->size; - temp = first_pkt[src]; - - if (temp == NULL) - return; - - temp2 = (netpkt_t *) calloc(sizeof(netpkt_t), 1); - temp2->priv = temp->priv; - memcpy(temp2->data, temp->data, temp->len); - temp2->len = temp->len; - temp2->prev = last_pkt[dest]; - temp2->next = NULL; - - if (last_pkt[dest] != NULL) - last_pkt[dest]->next = temp2; - last_pkt[dest] = temp2; - - if (first_pkt[dest] == NULL) - first_pkt[dest] = temp2; - - first_pkt[src] = temp->next; - free(temp); - - if (first_pkt[src] == NULL) - last_pkt[src] = NULL; + return 1; } +static int +network_queue_move(netqueue_t *dst_q, netqueue_t *src_q) +{ + if (network_queue_empty(src_q)) + return 0; + + if (network_queue_full(dst_q)) { + return 0; + } + + netpkt_t *src_pkt = &src_q->packets[src_q->tail]; + netpkt_t *dst_pkt = &dst_q->packets[dst_q->head]; + uint8_t *tmp_dat = dst_pkt->data; + + dst_pkt->data = src_pkt->data; + dst_pkt->len = src_pkt->len; + dst_q->head = (dst_q->head + 1) % dst_q->size; + + src_pkt->data = tmp_dat; + src_pkt->len = 0; + src_q->tail = (src_q->tail + 1) % src_q->size; + + return 1; +} static void -network_queue_clear(int tx) +network_queue_clear(netqueue_t *queue) { - netpkt_t *temp = first_pkt[tx], *temp2; - - if (temp == NULL) - return; - - do { - temp2 = temp->next; - free(temp); - temp = temp2; - } while (temp != NULL); - - first_pkt[tx] = last_pkt[tx] = NULL; + for (int i=0; isize; i++) { + free(queue->packets[i].data); + queue->packets[i].len = 0; + } + queue->tail = queue->head = 0; } static void network_rx_queue(void *priv) { - int ret = 1; + netcard_t *card = (netcard_t *)priv; + double timer_period; + int ret = 0; - if (network_rx_pause || !thread_test_mutex(network_mutex)) { - timer_on_auto(&network_rx_queue_timer, 0.762939453125 * 2.0 * 128.0); - return; + bool activity = false; + + if (card->queued_pkt.len == 0) { + thread_wait_mutex(card->rx_mutex); + network_queue_get(&card->queues[NET_QUEUE_RX], &card->queued_pkt); + thread_release_mutex(card->rx_mutex); } - if (queued_pkt.len == 0) - network_queue_get(0, &queued_pkt); - if (queued_pkt.len > 0) { - network_dump_packet(&queued_pkt); - ret = net_cards[network_card].rx(queued_pkt.priv, queued_pkt.data, queued_pkt.len); + if (card->queued_pkt.len > 0) { + network_dump_packet(&card->queued_pkt); + ret = card->rx(card->card_drv, card->queued_pkt.data, card->queued_pkt.len); } - timer_on_auto(&network_rx_queue_timer, 0.762939453125 * 2.0 * ((queued_pkt.len >= 128) ? ((double) queued_pkt.len) : 128.0)); - if (ret) - queued_pkt.len = 0; + + if (ret) { + activity = true; + timer_period = 0.762939453125 * ((card->queued_pkt.len >= 128) ? ((double) card->queued_pkt.len) : 128.0); + card->queued_pkt.len = 0; + } else { + timer_period = 0.762939453125 * 128.0; + } + timer_on_auto(&card->timer, timer_period); /* Transmission. */ - network_queue_copy(1, 2); + thread_wait_mutex(card->tx_mutex); + ret = network_queue_move(&card->queues[NET_QUEUE_TX_HOST], &card->queues[NET_QUEUE_TX_VM]); + thread_release_mutex(card->tx_mutex); + if (ret) { + /* Notify host that a packet is available in the TX queue */ + card->host_drv.notify_in(card->host_drv.priv); + activity = true; + } - network_wait(0); + ui_sb_update_icon(SB_NETWORK, activity); } @@ -407,51 +380,67 @@ network_rx_queue(void *priv) * finished initializing itself, to link itself to the platform support * modules. */ -void -network_attach(void *dev, uint8_t *mac, NETRXCB rx, NETWAITCB wait, NETSETLINKSTATE set_link_state) +netcard_t * +network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETWAITCB wait, NETSETLINKSTATE set_link_state) { - if (network_card == 0) return; + netcard_t *card = calloc(1, sizeof(netcard_t)); + card->queued_pkt.data = calloc(1, NET_MAX_FRAME); + card->card_drv = card_drv; + card->rx = rx; + card->wait = wait; + card->set_link_state = set_link_state; + card->tx_mutex = thread_create_mutex(); + card->rx_mutex = thread_create_mutex(); - /* Save the card's info. */ - net_cards[network_card].priv = dev; - net_cards[network_card].rx = rx; - net_cards[network_card].wait = wait; - net_cards[network_card].set_link_state = set_link_state; - network_mac = mac; - - network_set_wait(0); - - /* Activate the platform module. */ - switch(network_type) { - case NET_TYPE_PCAP: - (void)net_pcap_reset(&net_cards[network_card], network_mac); - break; - - case NET_TYPE_SLIRP: - (void)net_slirp_reset(&net_cards[network_card], network_mac); - break; + for (int i=0; i<3; i++) { + network_queue_init(&card->queues[i]); } - first_pkt[0] = first_pkt[1] = first_pkt[2] = NULL; - last_pkt[0] = last_pkt[1] = last_pkt[2] = NULL; - memset(&queued_pkt, 0x00, sizeof(netpkt_t)); - memset(&network_rx_queue_timer, 0x00, sizeof(pc_timer_t)); - timer_add(&network_rx_queue_timer, network_rx_queue, NULL, 0); - /* 10 mbps. */ - timer_on_auto(&network_rx_queue_timer, 0.762939453125 * 2.0); - network_timer_active = 1; + switch (net_cards_conf[net_card_current].net_type) { + case NET_TYPE_SLIRP: + default: + card->host_drv = net_slirp_drv; + card->host_drv.priv = card->host_drv.init(card, mac, NULL); + break; + + case NET_TYPE_PCAP: + card->host_drv = net_pcap_drv; + card->host_drv.priv = card->host_drv.init(card, mac, net_cards_conf[net_card_current].host_dev_name); + break; + } + + if (!card->host_drv.priv) { + thread_close_mutex(card->tx_mutex); + thread_close_mutex(card->rx_mutex); + for (int i=0; i<3; i++) { + network_queue_clear(&card->queues[i]); + } + + free(card->queued_pkt.data); + free(card); + return NULL; + } + + timer_add(&card->timer, network_rx_queue, card, 0); + timer_on_auto(&card->timer, 0.762939453125 * 2.0); + + return card; } - -/* Stop the network timer. */ void -network_timer_stop(void) +netcard_close(netcard_t *card) { - if (network_timer_active) { - timer_stop(&network_rx_queue_timer); - memset(&network_rx_queue_timer, 0x00, sizeof(pc_timer_t)); - network_timer_active = 0; + timer_stop(&card->timer); + card->host_drv.close(card->host_drv.priv); + + thread_close_mutex(card->tx_mutex); + thread_close_mutex(card->rx_mutex); + for (int i=0; i<3; i++) { + network_queue_clear(&card->queues[i]); } + + free(card->queued_pkt.data); + free(card); } @@ -459,30 +448,11 @@ network_timer_stop(void) void network_close(void) { - network_timer_stop(); - - /* If already closed, do nothing. */ - if (network_mutex == NULL) return; - - /* Force-close the PCAP module. */ - net_pcap_close(); - - /* Force-close the SLIRP module. */ - net_slirp_close(); - - /* Close the network thread mutex. */ - thread_close_mutex(network_mutex); - network_mutex = NULL; - network_mac = NULL; #ifdef ENABLE_NETWORK_LOG thread_close_mutex(network_dump_mutex); network_dump_mutex = NULL; #endif - /* Here is where we clear the queues. */ - network_queue_clear(0); - network_queue_clear(1); - network_log("NETWORK: closed.\n"); } @@ -500,86 +470,52 @@ network_reset(void) { int i = -1; - network_log("NETWORK: reset (type=%d, card=%d)\n", - network_type, network_card); - ui_sb_update_icon(SB_NETWORK, 0); - /* Just in case.. */ - network_close(); - - /* If no active card, we're done. */ - if ((network_type==NET_TYPE_NONE) || (network_card==0)) return; - - network_mutex = thread_create_mutex(); #ifdef ENABLE_NETWORK_LOG network_dump_mutex = thread_create_mutex(); #endif - /* Initialize the platform module. */ - switch(network_type) { - case NET_TYPE_PCAP: - i = net_pcap_init(); - break; + for (i = 0; i < NET_CARD_MAX; i++) { + if (!net_cards_conf[i].device_num || net_cards_conf[i].net_type == NET_TYPE_NONE || + (net_cards_conf[i].net_type == NET_TYPE_PCAP && !strcmp(net_cards_conf[i].host_dev_name, "none"))) { + continue; + } - case NET_TYPE_SLIRP: - i = net_slirp_init(); - break; - } - - if (i < 0) { - /* Tell user we can't do this (at the moment.) */ - ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2093, (wchar_t *) IDS_2129); - - // FIXME: we should ask in the dialog if they want to - // reconfigure or quit, and throw them into the - // Settings dialog if yes. - - /* Disable network. */ - network_type = NET_TYPE_NONE; - - return; - } - - network_log("NETWORK: set up for %s, card='%s'\n", - (network_type==NET_TYPE_SLIRP)?"SLiRP":"Pcap", - net_cards[network_card].device->name); - - /* Add the (new?) card to the I/O system. */ - if (net_cards[network_card].device) { - network_log("NETWORK: adding device '%s'\n", - net_cards[network_card].device->name); - device_add(net_cards[network_card].device); + net_card_current = i; + device_add_inst(net_cards[net_cards_conf[i].device_num], i + 1); } } /* Queue a packet for transmission to one of the network providers. */ void -network_tx(uint8_t *bufp, int len) +network_tx(netcard_t *card, uint8_t *bufp, int len) { - ui_sb_update_icon(SB_NETWORK, 1); - - network_queue_put(2, NULL, bufp, len); - - ui_sb_update_icon(SB_NETWORK, 0); + network_queue_put(&card->queues[NET_QUEUE_TX_VM], bufp, len); } - -/* Actually transmit the packet. */ -int -network_tx_queue_check(void) +int network_tx_pop(netcard_t *card, netpkt_t *out_pkt) { - if ((first_pkt[1] == NULL) && (last_pkt[1] == NULL)) - return 0; + int ret = 0; - if (network_tx_pause) - return 1; + thread_wait_mutex(card->tx_mutex); + ret = network_queue_get(&card->queues[NET_QUEUE_TX_HOST], out_pkt); + thread_release_mutex(card->tx_mutex); - network_queue_transmit(1); - return 1; + return ret; } +int network_rx_put(netcard_t *card, uint8_t *bufp, int len) +{ + int ret = 0; + + thread_wait_mutex(card->rx_mutex); + ret = network_queue_put(&card->queues[NET_QUEUE_RX], bufp, len); + thread_release_mutex(card->rx_mutex); + + return ret; +} int network_dev_to_id(char *devname) @@ -601,9 +537,13 @@ network_dev_to_id(char *devname) int network_available(void) { - if ((network_type == NET_TYPE_NONE) || (network_card == 0)) return(0); + int available = 0; - return(1); + for (int i = 0; i < NET_CARD_MAX; i ++) { + available |= (net_cards_conf[i].device_num > 0) && (net_cards_conf[i].net_type != NET_TYPE_NONE); + } + + return available; } @@ -611,8 +551,8 @@ network_available(void) int network_card_available(int card) { - if (net_cards[card].device) - return(device_available(net_cards[card].device)); + if (net_cards[card]) + return(device_available(net_cards[card])); return(1); } @@ -622,7 +562,7 @@ network_card_available(int card) const device_t * network_card_getdevice(int card) { - return(net_cards[card].device); + return(net_cards[card]); } @@ -630,9 +570,9 @@ network_card_getdevice(int card) int network_card_has_config(int card) { - if (! net_cards[card].device) return(0); + if (!net_cards[card]) return(0); - return(device_has_config(net_cards[card].device) ? 1 : 0); + return(device_has_config(net_cards[card]) ? 1 : 0); } @@ -640,7 +580,7 @@ network_card_has_config(int card) char * network_card_get_internal_name(int card) { - return device_get_internal_name(net_cards[card].device); + return device_get_internal_name(net_cards[card]); } @@ -650,28 +590,11 @@ network_card_get_from_internal_name(char *s) { int c = 0; - while (net_cards[c].device != NULL) { - if (! strcmp((char *)net_cards[c].device->internal_name, s)) + while (net_cards[c] != NULL) { + if (! strcmp((char *)net_cards[c]->internal_name, s)) return(c); c++; } return 0; -} - - -void -network_set_wait(int wait) -{ - net_wait = wait; -} - - -int -network_get_wait(void) -{ - int ret; - - ret = net_wait; - return ret; -} +} \ No newline at end of file diff --git a/src/qt/qt_machinestatus.cpp b/src/qt/qt_machinestatus.cpp index 773566319..a6ea65fd3 100644 --- a/src/qt/qt_machinestatus.cpp +++ b/src/qt/qt_machinestatus.cpp @@ -37,6 +37,7 @@ extern uint64_t tsc; #include <86box/mo.h> #include <86box/plat.h> #include <86box/machine.h> +#include <86box/thread.h> #include <86box/network.h> #include <86box/ui.h> #include <86box/machine_status.h> diff --git a/src/qt/qt_settingsnetwork.cpp b/src/qt/qt_settingsnetwork.cpp index ec5ebbe53..7bf26b263 100644 --- a/src/qt/qt_settingsnetwork.cpp +++ b/src/qt/qt_settingsnetwork.cpp @@ -21,20 +21,29 @@ extern "C" { #include <86box/86box.h> #include <86box/device.h> #include <86box/machine.h> +#include <86box/timer.h> +#include <86box/thread.h> #include <86box/network.h> } #include "qt_models_common.hpp" #include "qt_deviceconfig.hpp" -static void enableElements(Ui::SettingsNetwork *ui) { - int netType = ui->comboBoxNetwork->currentData().toInt(); - ui->comboBoxPcap->setEnabled(netType == NET_TYPE_PCAP); +void SettingsNetwork::enableElements(Ui::SettingsNetwork *ui) { + for (int i = 0; i < NET_CARD_MAX; ++i) { + auto* nic_cbox = findChild(QString("comboBoxNIC%1").arg(i+1)); + auto* net_type_cbox = findChild(QString("comboBoxNet%1").arg(i+1)); + auto* intf_cbox = findChild(QString("comboBoxIntf%1").arg(i+1)); + auto* conf_btn = findChild(QString("pushButtonConf%1").arg(i+1)); - bool adaptersEnabled = netType == NET_TYPE_SLIRP || - (netType == NET_TYPE_PCAP && ui->comboBoxPcap->currentData().toInt() > 0); - ui->comboBoxAdapter->setEnabled(adaptersEnabled); - ui->pushButtonConfigure->setEnabled(adaptersEnabled && ui->comboBoxAdapter->currentIndex() > 0 && network_card_has_config(ui->comboBoxAdapter->currentData().toInt())); + int netType = net_type_cbox->currentData().toInt(); + bool adaptersEnabled = netType == NET_TYPE_SLIRP || + (netType == NET_TYPE_PCAP && intf_cbox->currentData().toInt() > 0); + + intf_cbox->setEnabled(net_type_cbox->currentData().toInt() == NET_TYPE_PCAP); + nic_cbox->setEnabled(adaptersEnabled); + conf_btn->setEnabled(adaptersEnabled && network_card_has_config(nic_cbox->currentData().toInt())); + } } SettingsNetwork::SettingsNetwork(QWidget *parent) : @@ -43,27 +52,16 @@ SettingsNetwork::SettingsNetwork(QWidget *parent) : { ui->setupUi(this); - auto* model = ui->comboBoxNetwork->model(); - Models::AddEntry(model, tr("None"), NET_TYPE_NONE); - Models::AddEntry(model, "PCap", NET_TYPE_PCAP); - Models::AddEntry(model, "SLiRP", NET_TYPE_SLIRP); - ui->comboBoxNetwork->setCurrentIndex(network_type); - - int selectedRow = 0; - model = ui->comboBoxPcap->model(); - QString currentPcapDevice = network_host; - for (int c = 0; c < network_ndev; c++) { - - Models::AddEntry(model, tr(network_devs[c].description), c); - if (QString(network_devs[c].device) == currentPcapDevice) { - selectedRow = c; - } - } - ui->comboBoxPcap->setCurrentIndex(-1); - ui->comboBoxPcap->setCurrentIndex(selectedRow); - onCurrentMachineChanged(machine); enableElements(ui); + for (int i = 0; i < NET_CARD_MAX; i++) { + auto* nic_cbox = findChild(QString("comboBoxNIC%1").arg(i+1)); + auto* net_type_cbox = findChild(QString("comboBoxNet%1").arg(i+1)); + auto* intf_cbox = findChild(QString("comboBoxIntf%1").arg(i+1)); + connect(nic_cbox, QOverload::of(&QComboBox::currentIndexChanged), this, &SettingsNetwork::on_comboIndexChanged); + connect(net_type_cbox, QOverload::of(&QComboBox::currentIndexChanged), this, &SettingsNetwork::on_comboIndexChanged); + connect(intf_cbox, QOverload::of(&QComboBox::currentIndexChanged), this, &SettingsNetwork::on_comboIndexChanged); + } } SettingsNetwork::~SettingsNetwork() @@ -72,41 +70,75 @@ SettingsNetwork::~SettingsNetwork() } void SettingsNetwork::save() { - network_type = ui->comboBoxNetwork->currentData().toInt(); - memset(network_host, '\0', sizeof(network_host)); - strcpy(network_host, network_devs[ui->comboBoxPcap->currentData().toInt()].device); - network_card = ui->comboBoxAdapter->currentData().toInt(); + for (int i = 0; i < NET_CARD_MAX; ++i) { + auto* cbox = findChild(QString("comboBoxNIC%1").arg(i+1)); + net_cards_conf[i].device_num = cbox->currentData().toInt(); + cbox = findChild(QString("comboBoxNet%1").arg(i+1)); + net_cards_conf[i].net_type = cbox->currentData().toInt(); + cbox = findChild(QString("comboBoxIntf%1").arg(i+1)); + memset(net_cards_conf[i].host_dev_name, '\0', sizeof(net_cards_conf[i].host_dev_name)); + strncpy(net_cards_conf[i].host_dev_name, network_devs[cbox->currentData().toInt()].device, sizeof(net_cards_conf[i].host_dev_name) - 1); + } } void SettingsNetwork::onCurrentMachineChanged(int machineId) { this->machineId = machineId; - auto* model = ui->comboBoxAdapter->model(); - auto removeRows = model->rowCount(); int c = 0; int selectedRow = 0; - while (true) { - auto name = DeviceConfig::DeviceName(network_card_getdevice(c), network_card_get_internal_name(c), 1); - if (name.isEmpty()) { - break; + + for (int i = 0; i < NET_CARD_MAX; ++i) { + auto* cbox = findChild(QString("comboBoxNIC%1").arg(i+1)); + auto *model = cbox->model(); + auto removeRows = model->rowCount(); + c = 0; + selectedRow = 0; + + while (true) { + auto name = DeviceConfig::DeviceName(network_card_getdevice(c), network_card_get_internal_name(c), 1); + if (name.isEmpty()) { + break; + } + + if (network_card_available(c) && device_is_valid(network_card_getdevice(c), machineId)) { + int row = Models::AddEntry(model, name, c); + if (c == net_cards_conf[i].device_num) { + selectedRow = row - removeRows; + } + } + c++; } - if (network_card_available(c) && device_is_valid(network_card_getdevice(c), machineId)) { - int row = Models::AddEntry(model, name, c); - if (c == network_card) { - selectedRow = row - removeRows; + model->removeRows(0, removeRows); + cbox->setEnabled(model->rowCount() > 0); + cbox->setCurrentIndex(-1); + cbox->setCurrentIndex(selectedRow); + + cbox = findChild(QString("comboBoxNet%1").arg(i+1)); + model = cbox->model(); + Models::AddEntry(model, tr("None"), NET_TYPE_NONE); + Models::AddEntry(model, "SLiRP", NET_TYPE_SLIRP); + if (network_ndev > 1) { + Models::AddEntry(model, "PCap", NET_TYPE_PCAP); + } + cbox->setCurrentIndex(net_cards_conf[i].net_type); + + selectedRow = 0; + + QString currentPcapDevice = net_cards_conf[i].host_dev_name; + cbox = findChild(QString("comboBoxIntf%1").arg(i+1)); + model = cbox->model(); + for (int c = 0; c < network_ndev; c++) { + Models::AddEntry(model, tr(network_devs[c].description), c); + if (QString(network_devs[c].device) == currentPcapDevice) { + selectedRow = c; } } - - c++; + cbox->setCurrentIndex(selectedRow); } - model->removeRows(0, removeRows); - ui->comboBoxAdapter->setEnabled(model->rowCount() > 0); - ui->comboBoxAdapter->setCurrentIndex(-1); - ui->comboBoxAdapter->setCurrentIndex(selectedRow); } -void SettingsNetwork::on_comboBoxNetwork_currentIndexChanged(int index) { +void SettingsNetwork::on_comboIndexChanged(int index) { if (index < 0) { return; } @@ -114,24 +146,18 @@ void SettingsNetwork::on_comboBoxNetwork_currentIndexChanged(int index) { enableElements(ui); } -void SettingsNetwork::on_comboBoxAdapter_currentIndexChanged(int index) { - if (index < 0) { - return; - } - - enableElements(ui); +void SettingsNetwork::on_pushButtonConf1_clicked() { + DeviceConfig::ConfigureDevice(network_card_getdevice(ui->comboBoxNIC1->currentData().toInt()), 0, qobject_cast(Settings::settings)); } -void SettingsNetwork::on_pushButtonConfigure_clicked() { - DeviceConfig::ConfigureDevice(network_card_getdevice(ui->comboBoxAdapter->currentData().toInt()), 0, qobject_cast(Settings::settings)); +void SettingsNetwork::on_pushButtonConf2_clicked() { + DeviceConfig::ConfigureDevice(network_card_getdevice(ui->comboBoxNIC2->currentData().toInt()), 0, qobject_cast(Settings::settings)); } - -void SettingsNetwork::on_comboBoxPcap_currentIndexChanged(int index) -{ - if (index < 0) { - return; - } - - enableElements(ui); +void SettingsNetwork::on_pushButtonConf3_clicked() { + DeviceConfig::ConfigureDevice(network_card_getdevice(ui->comboBoxNIC3->currentData().toInt()), 0, qobject_cast(Settings::settings)); +} + +void SettingsNetwork::on_pushButtonConf4_clicked() { + DeviceConfig::ConfigureDevice(network_card_getdevice(ui->comboBoxNIC4->currentData().toInt()), 0, qobject_cast(Settings::settings)); } diff --git a/src/qt/qt_settingsnetwork.hpp b/src/qt/qt_settingsnetwork.hpp index b473ee3df..55d983b5f 100644 --- a/src/qt/qt_settingsnetwork.hpp +++ b/src/qt/qt_settingsnetwork.hpp @@ -21,11 +21,13 @@ public slots: void onCurrentMachineChanged(int machineId); private slots: - void on_pushButtonConfigure_clicked(); - void on_comboBoxAdapter_currentIndexChanged(int index); - void on_comboBoxNetwork_currentIndexChanged(int index); + void on_pushButtonConf1_clicked(); + void on_pushButtonConf2_clicked(); + void on_pushButtonConf3_clicked(); + void on_pushButtonConf4_clicked(); + void on_comboIndexChanged(int index); - void on_comboBoxPcap_currentIndexChanged(int index); + void enableElements(Ui::SettingsNetwork *ui); private: Ui::SettingsNetwork *ui; diff --git a/src/qt/qt_settingsnetwork.ui b/src/qt/qt_settingsnetwork.ui index 751e3854d..763537c9e 100644 --- a/src/qt/qt_settingsnetwork.ui +++ b/src/qt/qt_settingsnetwork.ui @@ -6,14 +6,14 @@ 0 0 - 400 - 300 + 548 + 458 Form - + 0 @@ -26,7 +26,291 @@ 0 - + + + + Network Interface Contollers + + + + + + + 0 + 0 + + + + Adapter + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Configure + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Card 3: + + + + + + + + 0 + 0 + + + + QComboBox::AdjustToContents + + + + + + + + 0 + 0 + + + + Card 1: + + + + + + + + 0 + 0 + + + + Interface + + + + + + + + 0 + 0 + + + + QComboBox::AdjustToContents + + + + + + + + 0 + 0 + + + + Configure + + + + + + + + 0 + 0 + + + + QComboBox::AdjustToContents + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Card 4: + + + + + + + + 0 + 0 + + + + Mode + + + + + + + + 0 + 0 + + + + Card 2: + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Configure + + + + + + + + 0 + 0 + + + + Configure + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + QComboBox::AdjustToContents + + + + + + + Qt::Vertical @@ -39,57 +323,6 @@ - - - - PCap device: - - - - - - - Network type: - - - - - - - - 0 - 0 - - - - - - - - Network adapter: - - - - - - - Configure - - - - - - - - 0 - 0 - - - - - - - diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index e072adadc..7014d504c 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -664,7 +664,7 @@ NETOBJ := network.o \ net_dp8390.o \ net_3c503.o net_ne2000.o \ net_pcnet.o net_wd8003.o \ - net_plip.o + net_plip.o net_event.o PRINTOBJ := png.o prt_cpmap.o \ prt_escp.o prt_text.o prt_ps.o From d52bc438029807af548d6070037033c960aa7ca9 Mon Sep 17 00:00:00 2001 From: Adrien Moulin Date: Sun, 21 Aug 2022 17:29:24 +0200 Subject: [PATCH 2/3] network: fix win32 build error --- src/win/Makefile.mingw | 6 +++--- src/win/win_settings.c | 1 + src/win/win_stbar.c | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 7014d504c..6d5fb92fe 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -778,12 +778,12 @@ OBJ += $(EXOBJ) endif ifeq ($(OPENAL), y) -LIBS := -mwindows -lopenal -lcomctl32 -lSDL2 -limagehlp -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid +LIBS := -mwindows -lopenal -lcomctl32 -lSDL2 -limagehlp -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid -lws2_32 else ifeq ($(FAUDIO), y) -LIBS := -mwindows -lfaudio -lcomctl32 -lSDL2 -limagehlp -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid +LIBS := -mwindows -lfaudio -lcomctl32 -lSDL2 -limagehlp -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid -lws2_32 else -LIBS := -mwindows -lcomctl32 -lSDL2 -limagehlp -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid +LIBS := -mwindows -lcomctl32 -lSDL2 -limagehlp -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid -lws2_32 endif endif diff --git a/src/win/win_settings.c b/src/win/win_settings.c index d6780a8bc..91dce4547 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -60,6 +60,7 @@ #include <86box/fdd.h> #include <86box/fdc.h> #include <86box/fdc_ext.h> +#include <86box/thread.h> #include <86box/network.h> #include <86box/sound.h> #include <86box/midi.h> diff --git a/src/win/win_stbar.c b/src/win/win_stbar.c index a71587017..6178b73ce 100644 --- a/src/win/win_stbar.c +++ b/src/win/win_stbar.c @@ -47,6 +47,7 @@ #include <86box/mo.h> #include <86box/cdrom_image.h> #include <86box/scsi_disk.h> +#include <86box/thread.h> #include <86box/network.h> #include <86box/video.h> #include <86box/sound.h> From bf87193f912cfd63346ef9db056e18b11a4a51b4 Mon Sep 17 00:00:00 2001 From: Adrien Moulin Date: Sun, 21 Aug 2022 17:39:40 +0200 Subject: [PATCH 3/3] network: fix another win32 build error --- src/network/net_slirp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index 90812d17e..a74d06173 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -26,8 +26,6 @@ #include #include #include -#include -#include #include #define HAVE_STDARG_H #include <86box/86box.h>