From 19db1d2c7b195cfbaf14eeea5c90401b170b791b Mon Sep 17 00:00:00 2001 From: Adrien Moulin Date: Sun, 21 Aug 2022 16:55:47 +0200 Subject: [PATCH 01/17] 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 02/17] 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 03/17] 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> From 552ea55a92aa06d763cabe507c2323b933e0a8d9 Mon Sep 17 00:00:00 2001 From: Adrien Moulin Date: Sun, 21 Aug 2022 19:48:00 +0200 Subject: [PATCH 04/17] network: always link to ws2_32 on win32 --- src/network/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index ffd5d03a7..50f07612b 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -35,3 +35,7 @@ endif() if (HAIKU) target_link_libraries(86Box network) endif() + +if(WIN32) + target_link_libraries(86Box ws2_32) +endif() From 2f57de3f6056631af026a2eea5c0b505467c8a94 Mon Sep 17 00:00:00 2001 From: Adrien Moulin Date: Sun, 21 Aug 2022 21:05:07 +0200 Subject: [PATCH 05/17] Restore the ability to configure the first NIC with the win32 ui --- src/include/86box/86box.h | 3 --- src/network/network.c | 3 --- src/win/win_settings.c | 26 +++++++++++++------------- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 30a7542dc..28c370e78 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -122,9 +122,6 @@ extern int cpu, /* (C) cpu type */ cpu_use_dynarec, /* (C) cpu uses/needs Dyna */ fpu_type; /* (C) fpu type */ extern int time_sync; /* (C) enable time sync */ -extern int network_type; /* (C) net provider type */ -extern int network_card; /* (C) net interface num */ -extern char network_host[522]; /* (C) host network intf */ extern int hdd_format_type; /* (C) hard disk file format */ extern int confirm_reset, /* (C) enable reset confirmation */ confirm_exit, /* (C) enable exit confirmation */ diff --git a/src/network/network.c b/src/network/network.c index 714037b4c..5ea866c01 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -121,10 +121,7 @@ netcard_conf_t net_cards_conf[NET_CARD_MAX]; int net_card_current = 0; /* Global variables. */ -int network_type; int network_ndev; -int network_card; -char network_host[522]; netdev_t network_devs[32]; diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 91dce4547..365532ead 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -99,7 +99,7 @@ static int temp_float, temp_fm_driver; /* Network category */ static int temp_net_type, temp_net_card; -static char temp_pcap_dev[522]; +static char temp_pcap_dev[128]; /* Ports category */ static int temp_lpt_devices[PARALLEL_MAX]; @@ -340,13 +340,13 @@ win_settings_init(void) temp_fm_driver = fm_driver; /* Network category */ - temp_net_type = network_type; + temp_net_type = net_cards_conf[0].net_type; memset(temp_pcap_dev, 0, sizeof(temp_pcap_dev)); #ifdef ENABLE_SETTINGS_LOG - assert(sizeof(temp_pcap_dev) == sizeof(network_host)); + assert(sizeof(temp_pcap_dev) == sizeof(net_cards_conf[0].host_dev_name)); #endif - memcpy(temp_pcap_dev, network_host, sizeof(network_host)); - temp_net_card = network_card; + memcpy(temp_pcap_dev, net_cards_conf[0].host_dev_name, sizeof(net_cards_conf[0].host_dev_name)); + temp_net_card = net_cards_conf[0].device_num; /* Ports category */ for (i = 0; i < PARALLEL_MAX; i++) { @@ -466,9 +466,9 @@ win_settings_changed(void) i = i || (fm_driver != temp_fm_driver); /* Network category */ - i = i || (network_type != temp_net_type); - i = i || strcmp(temp_pcap_dev, network_host); - i = i || (network_card != temp_net_card); + i = i || (net_cards_conf[i].net_type != temp_net_type); + i = i || strcmp(temp_pcap_dev, net_cards_conf[0].host_dev_name); + i = i || (net_cards_conf[0].device_num != temp_net_card); /* Ports category */ for (j = 0; j < PARALLEL_MAX; j++) { @@ -558,10 +558,10 @@ win_settings_save(void) fm_driver = temp_fm_driver; /* Network category */ - network_type = temp_net_type; - memset(network_host, '\0', sizeof(network_host)); - strcpy(network_host, temp_pcap_dev); - network_card = temp_net_card; + net_cards_conf[i].net_type = temp_net_type; + memset(net_cards_conf[0].host_dev_name, '\0', sizeof(net_cards_conf[0].host_dev_name)); + strcpy(net_cards_conf[0].host_dev_name, temp_pcap_dev); + net_cards_conf[0].device_num = temp_net_card; /* Ports category */ for (i = 0; i < PARALLEL_MAX; i++) { @@ -1814,8 +1814,8 @@ win_settings_network_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); settings_add_string(hdlg, IDC_COMBO_NET_TYPE, (LPARAM) L"None"); - settings_add_string(hdlg, IDC_COMBO_NET_TYPE, (LPARAM) L"PCap"); settings_add_string(hdlg, IDC_COMBO_NET_TYPE, (LPARAM) L"SLiRP"); + settings_add_string(hdlg, IDC_COMBO_NET_TYPE, (LPARAM) L"PCap"); settings_set_cur_sel(hdlg, IDC_COMBO_NET_TYPE, temp_net_type); settings_enable_window(hdlg, IDC_COMBO_PCAP, temp_net_type == NET_TYPE_PCAP); From 2a4df321641d1c1023e687f265ae63a402022df2 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Wed, 17 Aug 2022 17:06:44 -0400 Subject: [PATCH 06/17] Correct BCM GT694VA --- src/machine/machine_table.c | 76 ++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 4a41b6ef1..ef1c2a566 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -11080,6 +11080,44 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[VIA Apollo Pro 133A] BCM GT694VA", + .internal_name = "gt694va", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_VIA_APOLLO_PRO_133A, + .init = machine_at_gt694va_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 133333333, + .min_voltage = 1300, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP, + .flags = MACHINE_IDE_DUAL | MACHINE_SOUND, + .ram = { + .min = 8192, + .max = 3145728, + .step = 8192 + }, + .nvrmask = 255, + .kbc = KBC_UNKNOWN, + .kbc_p1 = 0, + .gpio = 0, + .device = &es1371_onboard_device, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* Slot 1/2 machines */ /* 440GX */ @@ -11632,44 +11670,6 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ - { - .name = "[VIA Apollo Pro 133A] BCM GT694VA", - .internal_name = "gt694va", - .type = MACHINE_TYPE_SOCKET370, - .chipset = MACHINE_CHIPSET_VIA_APOLLO_PRO_133A, - .init = machine_at_gt694va_init, - .pad = 0, - .pad0 = 0, - .pad1 = MACHINE_AVAILABLE, - .pad2 = 0, - .cpu = { - .package = CPU_PKG_SOCKET370, - .block = CPU_BLOCK_NONE, - .min_bus = 66666667, - .max_bus = 133333333, - .min_voltage = 1300, - .max_voltage = 3500, - .min_multi = 1.5, - .max_multi = 8.0 - }, - .bus_flags = MACHINE_PS2_AGP, - .flags = MACHINE_IDE_DUAL | MACHINE_SOUND, - .ram = { - .min = 16384, - .max = 3145728, - .step = 8192 - }, - .nvrmask = 255, - .kbc = KBC_UNKNOWN, - .kbc_p1 = 0, - .gpio = 0, - .device = &es1371_onboard_device, - .vid_device = NULL, - .snd_device = NULL, - .net_device = NULL - }, /* Miscellaneous/Fake/Hypervisor machines */ /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC From 8ec983b1ef362030c891d3c043a43ca4310f727f Mon Sep 17 00:00:00 2001 From: Adrien Moulin Date: Thu, 25 Aug 2022 00:43:48 +0200 Subject: [PATCH 07/17] pcap: do bounds checking in net_pcap_prepare when processing the list of host interfaces --- src/include/86box/network.h | 3 ++- src/network/net_pcap.c | 3 +++ src/network/network.c | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/include/86box/network.h b/src/include/86box/network.h index f38db801a..967c581b1 100644 --- a/src/include/86box/network.h +++ b/src/include/86box/network.h @@ -58,6 +58,7 @@ #define NET_MAX_FRAME 1518 #define NET_QUEUE_LEN 8 #define NET_CARD_MAX 4 +#define NET_HOST_INTF_MAX 64 /* Supported network cards. */ enum { @@ -141,7 +142,7 @@ extern "C" { /* Global variables. */ extern int nic_do_log; /* config */ extern int network_ndev; -extern netdev_t network_devs[32]; +extern netdev_t network_devs[NET_HOST_INTF_MAX]; /* Function prototypes. */ diff --git a/src/network/net_pcap.c b/src/network/net_pcap.c index d695d4992..0baa16186 100644 --- a/src/network/net_pcap.c +++ b/src/network/net_pcap.c @@ -354,6 +354,9 @@ net_pcap_prepare(netdev_t *list) } for (dev=devlist; dev!=NULL; dev=dev->next) { + if (i >= (NET_HOST_INTF_MAX - 1)) + break; + /** * we initialize the strings to NULL first for strncpy */ diff --git a/src/network/network.c b/src/network/network.c index 5ea866c01..58ff2516d 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -122,7 +122,7 @@ int net_card_current = 0; /* Global variables. */ int network_ndev; -netdev_t network_devs[32]; +netdev_t network_devs[NET_HOST_INTF_MAX]; /* Local variables. */ From 06ec705098458d1f71addb77dcb0bb1ee9b7f5bc Mon Sep 17 00:00:00 2001 From: Adrien Moulin Date: Thu, 25 Aug 2022 22:25:11 +0200 Subject: [PATCH 08/17] qt: fix duplicate entries in network settings --- src/qt/qt_settingsnetwork.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/qt/qt_settingsnetwork.cpp b/src/qt/qt_settingsnetwork.cpp index 7bf26b263..8c4c82904 100644 --- a/src/qt/qt_settingsnetwork.cpp +++ b/src/qt/qt_settingsnetwork.cpp @@ -116,11 +116,13 @@ void SettingsNetwork::onCurrentMachineChanged(int machineId) { cbox = findChild(QString("comboBoxNet%1").arg(i+1)); model = cbox->model(); + removeRows = model->rowCount(); 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); } + model->removeRows(0, removeRows); cbox->setCurrentIndex(net_cards_conf[i].net_type); selectedRow = 0; @@ -128,12 +130,14 @@ void SettingsNetwork::onCurrentMachineChanged(int machineId) { QString currentPcapDevice = net_cards_conf[i].host_dev_name; cbox = findChild(QString("comboBoxIntf%1").arg(i+1)); model = cbox->model(); + removeRows = model->rowCount(); 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; } } + model->removeRows(0, removeRows); cbox->setCurrentIndex(selectedRow); } } From 9ad587dbfd8735f62d6a0a6162f15e7f0255ed79 Mon Sep 17 00:00:00 2001 From: Adrien Moulin Date: Thu, 25 Aug 2022 23:53:09 +0200 Subject: [PATCH 09/17] qt: fix instance number not set when editing nic config --- src/qt/qt_settingsnetwork.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/qt/qt_settingsnetwork.cpp b/src/qt/qt_settingsnetwork.cpp index 8c4c82904..1cb42cc22 100644 --- a/src/qt/qt_settingsnetwork.cpp +++ b/src/qt/qt_settingsnetwork.cpp @@ -151,17 +151,17 @@ void SettingsNetwork::on_comboIndexChanged(int index) { } void SettingsNetwork::on_pushButtonConf1_clicked() { - DeviceConfig::ConfigureDevice(network_card_getdevice(ui->comboBoxNIC1->currentData().toInt()), 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(network_card_getdevice(ui->comboBoxNIC1->currentData().toInt()), 1, qobject_cast(Settings::settings)); } void SettingsNetwork::on_pushButtonConf2_clicked() { - DeviceConfig::ConfigureDevice(network_card_getdevice(ui->comboBoxNIC2->currentData().toInt()), 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(network_card_getdevice(ui->comboBoxNIC2->currentData().toInt()), 2, qobject_cast(Settings::settings)); } void SettingsNetwork::on_pushButtonConf3_clicked() { - DeviceConfig::ConfigureDevice(network_card_getdevice(ui->comboBoxNIC3->currentData().toInt()), 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(network_card_getdevice(ui->comboBoxNIC3->currentData().toInt()), 3, qobject_cast(Settings::settings)); } void SettingsNetwork::on_pushButtonConf4_clicked() { - DeviceConfig::ConfigureDevice(network_card_getdevice(ui->comboBoxNIC4->currentData().toInt()), 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(network_card_getdevice(ui->comboBoxNIC4->currentData().toInt()), 4, qobject_cast(Settings::settings)); } From 448bd9d958294c5ac8b9529f0d9fd63f5042b61e Mon Sep 17 00:00:00 2001 From: Adrien Moulin Date: Fri, 26 Aug 2022 18:22:19 +0200 Subject: [PATCH 10/17] slirp: fix port forwarding and handle configuration with multiple nics --- src/include/86box/network.h | 1 + src/network/net_slirp.c | 5 +++-- src/network/network.c | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/include/86box/network.h b/src/include/86box/network.h index 967c581b1..2fe0553f8 100644 --- a/src/include/86box/network.h +++ b/src/include/86box/network.h @@ -127,6 +127,7 @@ struct _netcard_t { mutex_t *tx_mutex; mutex_t *rx_mutex; pc_timer_t timer; + int card_num; }; typedef struct { diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index a74d06173..7535a0609 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -415,7 +415,7 @@ net_slirp_init(const netcard_t *card, const uint8_t *mac_addr, void *priv) 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 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. */ @@ -428,7 +428,8 @@ net_slirp_init(const netcard_t *card, const uint8_t *mac_addr, void *priv) /* Set up port forwarding. */ int udp, external, internal, i = 0; - char *category = "SLiRP Port Forwarding"; + char category[32]; + snprintf(category, sizeof(category), "SLiRP Port Forwarding #%i", card->card_num + 1); char key[20]; while (1) { sprintf(key, "%d_protocol", i); diff --git a/src/network/network.c b/src/network/network.c index 58ff2516d..a406140c4 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -388,6 +388,7 @@ network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETWAITCB wait, NETSETL card->set_link_state = set_link_state; card->tx_mutex = thread_create_mutex(); card->rx_mutex = thread_create_mutex(); + card->card_num = net_card_current; for (int i=0; i<3; i++) { network_queue_init(&card->queues[i]); From 147c27b96ef54fda0dac1df91bbf273618424811 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 27 Aug 2022 01:51:56 +0600 Subject: [PATCH 11/17] voodoo_codegen_x86*: Remove bounds checking for block_pos Block sizes are sufficiently large enough to ensure no buffer overrun as block_pos is initialized to 0 every time a block is requested. It should cause a good performance increase on x86 and x86-64. --- src/include/86box/vid_voodoo_codegen_x86-64.h | 8 -------- src/include/86box/vid_voodoo_codegen_x86.h | 8 -------- 2 files changed, 16 deletions(-) diff --git a/src/include/86box/vid_voodoo_codegen_x86-64.h b/src/include/86box/vid_voodoo_codegen_x86-64.h index bd992e1d0..4999f38c5 100644 --- a/src/include/86box/vid_voodoo_codegen_x86-64.h +++ b/src/include/86box/vid_voodoo_codegen_x86-64.h @@ -46,32 +46,24 @@ static int next_block_to_write[4] = { 0, 0 }; #define addbyte(val) \ do { \ code_block[block_pos++] = val; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n"); \ } while (0) #define addword(val) \ do { \ *(uint16_t *) &code_block[block_pos] = val; \ block_pos += 2; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n"); \ } while (0) #define addlong(val) \ do { \ *(uint32_t *) &code_block[block_pos] = val; \ block_pos += 4; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n"); \ } while (0) #define addquad(val) \ do { \ *(uint64_t *) &code_block[block_pos] = val; \ block_pos += 8; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n"); \ } while (0) static __m128i xmm_01_w; // = 0x0001000100010001ull; diff --git a/src/include/86box/vid_voodoo_codegen_x86.h b/src/include/86box/vid_voodoo_codegen_x86.h index f9685344f..9432fa3b3 100644 --- a/src/include/86box/vid_voodoo_codegen_x86.h +++ b/src/include/86box/vid_voodoo_codegen_x86.h @@ -44,32 +44,24 @@ static int next_block_to_write[4] = { 0, 0 }; #define addbyte(val) \ do { \ code_block[block_pos++] = val; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n"); \ } while (0) #define addword(val) \ do { \ *(uint16_t *) &code_block[block_pos] = val; \ block_pos += 2; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n"); \ } while (0) #define addlong(val) \ do { \ *(uint32_t *) &code_block[block_pos] = val; \ block_pos += 4; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n"); \ } while (0) #define addquad(val) \ do { \ *(uint64_t *) &code_block[block_pos] = val; \ block_pos += 8; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n"); \ } while (0) static __m128i xmm_01_w; // = 0x0001000100010001ull; From 4efd1d90c2892e6636c572262ec226d41d3f5f0b Mon Sep 17 00:00:00 2001 From: cold-brewed Date: Sat, 27 Aug 2022 10:47:55 -0400 Subject: [PATCH 12/17] macos: Add RPATH to the installed binary to enable dynamic loading of bundled libraries. --- src/qt/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 0cb4560c4..1db01301d 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -309,7 +309,11 @@ if (APPLE AND CMAKE_MACOSX_BUNDLE) install(CODE " include(BundleUtilities) get_filename_component(CMAKE_INSTALL_PREFIX_ABSOLUTE \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX} ABSOLUTE) - fixup_bundle(\"\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/86Box.app\" \"${QT_PLUGINS}\" \"${DIRS}\")") + fixup_bundle(\"\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/86Box.app\" \"${QT_PLUGINS}\" \"${DIRS}\") + execute_process( + COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath \"@executable_path/../Frameworks/\" + \"\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/${INSTALL_RUNTIME_DIR}/86Box\") + ") endif() if (UNIX AND NOT APPLE AND NOT HAIKU) From 9c65d20621d360bd5bc6331507c9269c1087293b Mon Sep 17 00:00:00 2001 From: Adrien Moulin Date: Sat, 27 Aug 2022 16:52:33 +0200 Subject: [PATCH 13/17] network: improve throughput by batch processing packets --- src/include/86box/network.h | 8 ++- src/network/net_pcap.c | 74 +++++++++++++++---- src/network/net_slirp.c | 36 +++++----- src/network/network.c | 140 ++++++++++++++++++++++++------------ 4 files changed, 176 insertions(+), 82 deletions(-) diff --git a/src/include/86box/network.h b/src/include/86box/network.h index 2fe0553f8..54181ae8e 100644 --- a/src/include/86box/network.h +++ b/src/include/86box/network.h @@ -56,7 +56,9 @@ #define NET_TYPE_PCAP 2 /* use the (Win)Pcap API */ #define NET_MAX_FRAME 1518 -#define NET_QUEUE_LEN 8 +/* Queue size must be a power of 2 */ +#define NET_QUEUE_LEN 16 +#define NET_QUEUE_LEN_MASK (NET_QUEUE_LEN - 1) #define NET_CARD_MAX 4 #define NET_HOST_INTF_MAX 64 @@ -92,12 +94,10 @@ typedef int (*NETSETLINKSTATE)(void *); typedef struct netpkt { uint8_t *data; int len; - uint64_t tsc; } netpkt_t; typedef struct { netpkt_t packets[NET_QUEUE_LEN]; - int size; int head; int tail; } netqueue_t; @@ -165,7 +165,9 @@ extern int network_card_get_from_internal_name(char *); extern const device_t *network_card_getdevice(int); extern int network_tx_pop(netcard_t *card, netpkt_t *out_pkt); +extern int network_tx_popv(netcard_t *card, netpkt_t *pkt_vec, int vec_size); extern int network_rx_put(netcard_t *card, uint8_t *bufp, int len); +extern int network_rx_put_pkt(netcard_t *card, netpkt_t *pkt); #ifdef __cplusplus } #endif diff --git a/src/network/net_pcap.c b/src/network/net_pcap.c index 0baa16186..9aa486316 100644 --- a/src/network/net_pcap.c +++ b/src/network/net_pcap.c @@ -72,6 +72,8 @@ #include <86box/network.h> #include <86box/net_event.h> +#define PCAP_PKT_BATCH NET_QUEUE_LEN + enum { NET_EVENT_STOP = 0, NET_EVENT_TX, @@ -120,6 +122,17 @@ struct pcap_if { void *addresses; bpf_u_int32 flags; }; + +struct pcap_send_queue { + u_int maxlen; /* Maximum size of the queue, in bytes. This + variable contains the size of the buffer field. */ + u_int len; /* Current size of the queue, in bytes. */ + char *buffer; /* Buffer containing the packets to be sent. */ +}; + +typedef struct pcap_send_queue pcap_send_queue; + +typedef void (*pcap_handler)(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes); #endif typedef struct { @@ -129,7 +142,11 @@ typedef struct { net_evt_t tx_event; net_evt_t stop_event; netpkt_t pkt; + netpkt_t pktv[PCAP_PKT_BATCH]; uint8_t mac_addr[6]; +#ifdef _WIN32 + struct pcap_send_queue *pcap_queue; +#endif } net_pcap_t; typedef struct { @@ -154,11 +171,16 @@ 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 int (*f_pcap_dispatch)(void *, int, pcap_handler callback, u_char *user); 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 *); +static int (*f_pcap_sendqueue_queue)(void *, void *, void *); +static u_int (*f_pcap_sendqueue_transmit)(void *, void *, int sync); +static void *(*f_pcap_sendqueue_alloc)(u_int memsize); +static void (*f_pcap_sendqueue_destroy)(void *); #else static int (*f_pcap_get_selectable_fd)(void *); #endif @@ -177,13 +199,18 @@ static dllimp_t pcap_imports[] = { { "pcap_set_immediate_mode", &f_pcap_set_immediate_mode}, { "pcap_set_promisc", &f_pcap_set_promisc }, { "pcap_set_snaplen", &f_pcap_set_snaplen }, + { "pcap_dispatch", &f_pcap_dispatch }, { "pcap_create", &f_pcap_create }, { "pcap_activate", &f_pcap_activate }, { "pcap_geterr", &f_pcap_geterr }, #ifdef _WIN32 { "pcap_getevent", &f_pcap_getevent }, + { "pcap_sendqueue_queue", &f_pcap_sendqueue_queue }, + { "pcap_sendqueue_transmit", &f_pcap_sendqueue_transmit}, + { "pcap_sendqueue_alloc", &f_pcap_sendqueue_alloc }, + { "pcap_sendqueue_destroy", &f_pcap_sendqueue_destroy }, #else - { "pcap_get_selectable_fd", &f_pcap_get_selectable_fd }, + { "pcap_get_selectable_fd", &f_pcap_get_selectable_fd }, #endif { NULL, NULL }, }; @@ -208,15 +235,12 @@ pcap_log(const char *fmt, ...) static void -net_pcap_read_packet(net_pcap_t *pcap) +net_pcap_rx_handler(uint8_t *user, const struct pcap_pkthdr *h, const uint8_t *bytes) { - struct pcap_pkthdr h; - - uint8_t *data = (uint8_t *) f_pcap_next((void *) pcap->pcap, &h); - if (!data) - return; - - network_rx_put(pcap->card, data, h.caplen); + net_pcap_t *pcap = (net_pcap_t*)user; + memcpy(pcap->pkt.data, bytes, h->caplen); + pcap->pkt.len = h->caplen; + network_rx_put_pkt(pcap->card, &pcap->pkt); } /* Send a packet to the Pcap interface. */ @@ -251,6 +275,7 @@ net_pcap_thread(void *priv) bool run = true; + struct pcap_pkthdr h; while (run) { int ret = WaitForMultipleObjects(NET_EVENT_MAX, events, FALSE, INFINITE); @@ -262,13 +287,17 @@ net_pcap_thread(void *priv) 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); + int packets = network_tx_popv(pcap->card, pcap->pktv, PCAP_PKT_BATCH); + for (int i = 0; i < packets; i++) { + h.caplen = pcap->pktv[i].len; + f_pcap_sendqueue_queue(pcap->pcap_queue, &h, pcap->pktv[i].data); } + f_pcap_sendqueue_transmit(pcap->pcap, pcap->pcap_queue, 0); + pcap->pcap_queue->len = 0; break; case NET_EVENT_RX: - net_pcap_read_packet(pcap); + f_pcap_dispatch(pcap->pcap, PCAP_PKT_BATCH, net_pcap_rx_handler, (u_char *)pcap); break; } } @@ -305,13 +334,14 @@ net_pcap_thread(void *priv) 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); + int packets = network_tx_popv(pcap->card, pcap->pktv, PCAP_PKT_BATCH); + for (int i = 0; i < packets; i++) { + net_pcap_in(pcap->pcap, pcap->pktv[i].data, pcap->pktv[i].len); } } if (pfd[NET_EVENT_RX].revents & POLLIN) { - net_pcap_read_packet(pcap); + f_pcap_dispatch(pcap->pcap, PCAP_PKT_BATCH, net_pcap_rx_handler, (u_char *)pcap); } } @@ -470,7 +500,15 @@ net_pcap_init(const netcard_t *card, const uint8_t *mac_addr, void *priv) return NULL; } +#ifdef _WIN32 + pcap->pcap_queue = f_pcap_sendqueue_alloc(PCAP_PKT_BATCH * NET_MAX_FRAME); +#endif + + for (int i = 0; i < PCAP_PKT_BATCH; i++) { + pcap->pktv[i].data = calloc(1, NET_MAX_FRAME); + } 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); @@ -497,8 +535,14 @@ net_pcap_close(void *priv) thread_wait(pcap->poll_tid); pcap_log("PCAP: thread ended\n"); + for (int i = 0; i < PCAP_PKT_BATCH; i++) { + free(pcap->pktv[i].data); + } free(pcap->pkt.data); +#ifdef _WIN32 + f_pcap_sendqueue_destroy((void*)pcap->pcap_queue); +#endif /* OK, now shut down Pcap itself. */ f_pcap_close((void*)pcap->pcap); diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index 7535a0609..46b913416 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -45,6 +45,8 @@ #endif #include <86box/net_event.h> +#define SLIRP_PKT_BATCH NET_QUEUE_LEN + enum { NET_EVENT_STOP = 0, NET_EVENT_TX, @@ -60,6 +62,7 @@ typedef struct { net_evt_t tx_event; net_evt_t stop_event; netpkt_t pkt; + netpkt_t pkt_tx_v[SLIRP_PKT_BATCH]; #ifdef _WIN32 HANDLE sock_event; #else @@ -153,22 +156,12 @@ ssize_t net_slirp_send_packet(const void *qp, size_t pkt_len, void *opaque) { net_slirp_t *slirp = (net_slirp_t *) opaque; - uint8_t *mac = slirp->mac_addr; - uint32_t mac_cmp32[2]; - uint16_t mac_cmp16[2]; 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); - - /* 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); - } + memcpy(slirp->pkt.data, (uint8_t*) qp, pkt_len); + slirp->pkt.len = pkt_len; + network_rx_put_pkt(slirp->card, &slirp->pkt); return pkt_len; } @@ -336,8 +329,9 @@ net_slirp_thread(void *priv) break; case NET_EVENT_TX: - while (network_tx_pop(slirp->card, &slirp->pkt)) { - net_slirp_in(slirp, slirp->pkt.data, slirp->pkt.len); + int packets = network_tx_popv(slirp->card, slirp->pkt_tx_v, SLIRP_PKT_BATCH); + for (int i = 0; i < packets; i++) { + net_slirp_in(slirp, slirp->pkt_tx_v[i].data, slirp->pkt_tx_v[i].len); } break; @@ -381,11 +375,11 @@ net_slirp_thread(void *priv) 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); + int packets = network_tx_popv(slirp->card, slirp->pkt_tx_v, SLIRP_PKT_BATCH); + for (int i = 0; i < packets; i++) { + net_slirp_in(slirp, slirp->pkt_tx_v[i].data, slirp->pkt_tx_v[i].len); } } - } slirp_log("SLiRP: polling stopped.\n"); @@ -453,6 +447,9 @@ net_slirp_init(const netcard_t *card, const uint8_t *mac_addr, void *priv) i++; } + for (int i = 0; i < SLIRP_PKT_BATCH; i++) { + slirp->pkt_tx_v[i].data = calloc(1, NET_MAX_FRAME); + } slirp->pkt.data = calloc(1, NET_MAX_FRAME); net_event_init(&slirp->tx_event); net_event_init(&slirp->stop_event); @@ -485,6 +482,9 @@ net_slirp_close(void *priv) net_event_close(&slirp->tx_event); net_event_close(&slirp->stop_event); slirp_cleanup(slirp->slirp); + for (int i = 0; i < SLIRP_PKT_BATCH; i++) { + free(slirp->pkt_tx_v[i].data); + } free(slirp->pkt.data); free(slirp); slirp_card_num--; diff --git a/src/network/network.c b/src/network/network.c index a406140c4..a01eb938e 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -240,12 +240,11 @@ network_init(void) #endif } -static void +void network_queue_init(netqueue_t *queue) { - queue->size = NET_QUEUE_LEN; queue->head = queue->tail = 0; - for (int i=0; isize; i++) { + for (int i=0; ipackets[i].data = calloc(1, NET_MAX_FRAME); queue->packets[i].len = 0; } @@ -255,7 +254,7 @@ network_queue_init(netqueue_t *queue) static bool network_queue_full(netqueue_t *queue) { - return ((queue->head + 1) % queue->size) == queue->tail; + return ((queue->head + 1) & NET_QUEUE_LEN_MASK) == queue->tail; } static bool @@ -264,30 +263,50 @@ network_queue_empty(netqueue_t *queue) return (queue->head == queue->tail); } +static inline void +network_swap_packet(netpkt_t *pkt1, netpkt_t *pkt2) +{ + netpkt_t tmp = *pkt2; + *pkt2 = *pkt1; + *pkt1 = tmp; +} + int network_queue_put(netqueue_t *queue, uint8_t *data, int len) { - if (len > NET_MAX_FRAME || network_queue_full(queue)) { + if (len == 0 || len > NET_MAX_FRAME || network_queue_full(queue)) { return 0; } netpkt_t *pkt = &queue->packets[queue->head]; memcpy(pkt->data, data, len); pkt->len = len; - queue->head = (queue->head + 1) % queue->size; + queue->head = (queue->head + 1) & NET_QUEUE_LEN_MASK; + return 1; +} + +int +network_queue_put_swap(netqueue_t *queue, netpkt_t *src_pkt) +{ + if (src_pkt->len == 0 || src_pkt->len > NET_MAX_FRAME || network_queue_full(queue)) { + return 0; + } + + netpkt_t *dst_pkt = &queue->packets[queue->head]; + network_swap_packet(src_pkt, dst_pkt); + + queue->head = (queue->head + 1) & NET_QUEUE_LEN_MASK; return 1; } static int -network_queue_get(netqueue_t *queue, netpkt_t *dst_pkt) { +network_queue_get_swap(netqueue_t *queue, netpkt_t *dst_pkt) { if (network_queue_empty(queue)) return 0; - 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; - + netpkt_t *src_pkt = &queue->packets[queue->tail]; + network_swap_packet(src_pkt, dst_pkt); + queue->tail = (queue->tail + 1) & NET_QUEUE_LEN_MASK; return 1; } @@ -303,23 +322,18 @@ network_queue_move(netqueue_t *dst_q, netqueue_t *src_q) 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; + network_swap_packet(src_pkt, dst_pkt); + dst_q->head = (dst_q->head + 1) & NET_QUEUE_LEN_MASK; + src_q->tail = (src_q->tail + 1) & NET_QUEUE_LEN_MASK; - src_pkt->data = tmp_dat; - src_pkt->len = 0; - src_q->tail = (src_q->tail + 1) % src_q->size; - - return 1; + return dst_pkt->len; } -static void +void network_queue_clear(netqueue_t *queue) { - for (int i=0; isize; i++) { + for (int i=0; ipackets[i].data); queue->packets[i].len = 0; } @@ -331,41 +345,47 @@ static void network_rx_queue(void *priv) { netcard_t *card = (netcard_t *)priv; - double timer_period; - int ret = 0; - bool activity = false; + uint32_t rx_bytes = 0; + for (int i = 0; i < NET_QUEUE_LEN; i++) { + if (card->queued_pkt.len == 0) { + thread_wait_mutex(card->rx_mutex); + int res = network_queue_get_swap(&card->queues[NET_QUEUE_RX], &card->queued_pkt); + thread_release_mutex(card->rx_mutex); + if (!res) + break; + } - 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 (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); - } - - if (ret) { - activity = true; - timer_period = 0.762939453125 * ((card->queued_pkt.len >= 128) ? ((double) card->queued_pkt.len) : 128.0); + int res = card->rx(card->card_drv, card->queued_pkt.data, card->queued_pkt.len); + if (!res) + break; + rx_bytes += card->queued_pkt.len; card->queued_pkt.len = 0; - } else { - timer_period = 0.762939453125 * 128.0; } - timer_on_auto(&card->timer, timer_period); /* Transmission. */ + uint32_t tx_bytes = 0; thread_wait_mutex(card->tx_mutex); - ret = network_queue_move(&card->queues[NET_QUEUE_TX_HOST], &card->queues[NET_QUEUE_TX_VM]); + for (int i = 0; i < NET_QUEUE_LEN; i++) { + uint32_t bytes = network_queue_move(&card->queues[NET_QUEUE_TX_HOST], &card->queues[NET_QUEUE_TX_VM]); + if (!bytes) + break; + tx_bytes += bytes; + } thread_release_mutex(card->tx_mutex); - if (ret) { + if (tx_bytes) { /* Notify host that a packet is available in the TX queue */ card->host_drv.notify_in(card->host_drv.priv); - activity = true; } + double timer_period = 0.762939453125 * (rx_bytes > tx_bytes ? rx_bytes : tx_bytes); + if (timer_period < 200) + timer_period = 200; + + timer_on_auto(&card->timer, timer_period); + + bool activity = rx_bytes || tx_bytes; ui_sb_update_icon(SB_NETWORK, activity); } @@ -498,12 +518,29 @@ int network_tx_pop(netcard_t *card, netpkt_t *out_pkt) int ret = 0; thread_wait_mutex(card->tx_mutex); - ret = network_queue_get(&card->queues[NET_QUEUE_TX_HOST], out_pkt); + ret = network_queue_get_swap(&card->queues[NET_QUEUE_TX_HOST], out_pkt); thread_release_mutex(card->tx_mutex); return ret; } +int network_tx_popv(netcard_t *card, netpkt_t *pkt_vec, int vec_size) +{ + int pkt_count = 0; + + netqueue_t *queue = &card->queues[NET_QUEUE_TX_HOST]; + thread_wait_mutex(card->tx_mutex); + for (int i = 0; i < vec_size; i++) { + if (!network_queue_get_swap(queue, pkt_vec)) + break; + pkt_count++; + pkt_vec++; + } + thread_release_mutex(card->tx_mutex); + + return pkt_count; +} + int network_rx_put(netcard_t *card, uint8_t *bufp, int len) { int ret = 0; @@ -515,6 +552,17 @@ int network_rx_put(netcard_t *card, uint8_t *bufp, int len) return ret; } +int network_rx_put_pkt(netcard_t *card, netpkt_t *pkt) +{ + int ret = 0; + + thread_wait_mutex(card->rx_mutex); + ret = network_queue_put_swap(&card->queues[NET_QUEUE_RX], pkt); + thread_release_mutex(card->rx_mutex); + + return ret; +} + int network_dev_to_id(char *devname) { From 5384eb35bbb42a6aa03cec562a8e4ee1bea41bb3 Mon Sep 17 00:00:00 2001 From: cold-brewed Date: Sat, 27 Aug 2022 11:03:45 -0400 Subject: [PATCH 14/17] macos: Fix the name of the bundled freetype library --- src/printer/prt_escp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index ec07dc95f..013726c06 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -90,7 +90,7 @@ #ifdef _WIN32 # define PATH_FREETYPE_DLL "freetype.dll" #elif defined __APPLE__ -# define PATH_FREETYPE_DLL "libfreetype.dylib" +# define PATH_FREETYPE_DLL "libfreetype.6.dylib" #else # define PATH_FREETYPE_DLL "libfreetype.so.6" #endif From c0b6c55926c4526f267fc742714a8e67d691d1ee Mon Sep 17 00:00:00 2001 From: Adrien Moulin Date: Sat, 27 Aug 2022 17:08:50 +0200 Subject: [PATCH 15/17] network: support > 10Mbps throughput --- src/include/86box/network.h | 4 ++++ src/network/net_pcnet.c | 7 ++++++- src/network/network.c | 5 +++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/include/86box/network.h b/src/include/86box/network.h index 54181ae8e..4f9e6b70e 100644 --- a/src/include/86box/network.h +++ b/src/include/86box/network.h @@ -62,6 +62,9 @@ #define NET_CARD_MAX 4 #define NET_HOST_INTF_MAX 64 +#define NET_PERIOD_10M 0.8 +#define NET_PERIOD_100M 0.08 + /* Supported network cards. */ enum { NONE = 0, @@ -128,6 +131,7 @@ struct _netcard_t { mutex_t *rx_mutex; pc_timer_t timer; int card_num; + double byte_period; }; typedef struct { diff --git a/src/network/net_pcnet.c b/src/network/net_pcnet.c index 25ced4679..2b2b22540 100644 --- a/src/network/net_pcnet.c +++ b/src/network/net_pcnet.c @@ -2025,11 +2025,15 @@ pcnet_bcr_writew(nic_t *dev, uint16_t rap, uint16_t val) case BCR_BSBC: case BCR_EECAS: case BCR_PLAT: - case BCR_MIICAS: case BCR_MIIADDR: dev->aBCR[rap] = val; break; + case BCR_MIICAS: + dev->netcard->byte_period = (dev->board == DEV_AM79C973 && (val & 0x28)) ? NET_PERIOD_100M : NET_PERIOD_10M; + dev->aBCR[rap] = val; + break; + case BCR_STVAL: val &= 0xffff; dev->aBCR[BCR_STVAL] = val; @@ -3055,6 +3059,7 @@ pcnet_init(const device_t *info) /* Attach ourselves to the network module. */ dev->netcard = network_attach(dev, dev->aPROM, pcnetReceiveNoSync, pcnetWaitReceiveAvail, pcnetSetLinkState); + dev->netcard->byte_period = (dev->board == DEV_AM79C973) ? NET_PERIOD_100M : NET_PERIOD_10M; timer_add(&dev->timer, pcnetPollTimer, dev, 0); diff --git a/src/network/network.c b/src/network/network.c index a01eb938e..a8106afeb 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -379,7 +379,7 @@ network_rx_queue(void *priv) card->host_drv.notify_in(card->host_drv.priv); } - double timer_period = 0.762939453125 * (rx_bytes > tx_bytes ? rx_bytes : tx_bytes); + double timer_period = card->byte_period * (rx_bytes > tx_bytes ? rx_bytes : tx_bytes); if (timer_period < 200) timer_period = 200; @@ -409,6 +409,7 @@ network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETWAITCB wait, NETSETL card->tx_mutex = thread_create_mutex(); card->rx_mutex = thread_create_mutex(); card->card_num = net_card_current; + card->byte_period = NET_PERIOD_10M; for (int i=0; i<3; i++) { network_queue_init(&card->queues[i]); @@ -440,7 +441,7 @@ network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETWAITCB wait, NETSETL } timer_add(&card->timer, network_rx_queue, card, 0); - timer_on_auto(&card->timer, 0.762939453125 * 2.0); + timer_on_auto(&card->timer, 100); return card; } From ea21790fc9a3dec558c17a01e54cb5c98ce3f35c Mon Sep 17 00:00:00 2001 From: Adrien Moulin Date: Sat, 27 Aug 2022 19:08:28 +0200 Subject: [PATCH 16/17] network: allow to set a NIC's link from the status bar --- src/config.c | 12 ++++++ src/include/86box/machine_status.h | 2 +- src/include/86box/network.h | 25 +++++++++--- src/machine_status.c | 6 ++- src/network/net_3c503.c | 2 +- src/network/net_dp8390.c | 6 ++- src/network/net_ne2000.c | 2 +- src/network/net_pcnet.c | 62 ++++++++++++++---------------- src/network/net_plip.c | 2 +- src/network/net_wd8003.c | 2 +- src/network/network.c | 59 ++++++++++++++++++++++++---- src/qt/qt_machinestatus.cpp | 41 ++++++++++++++------ src/qt/qt_machinestatus.hpp | 1 + src/qt/qt_mediamenu.cpp | 38 ++++++++++++++++++ src/qt/qt_mediamenu.hpp | 5 +++ src/qt/qt_ui.cpp | 4 +- 16 files changed, 202 insertions(+), 67 deletions(-) diff --git a/src/config.c b/src/config.c index b0c73e0d0..0c6c0e28b 100644 --- a/src/config.c +++ b/src/config.c @@ -1214,6 +1214,11 @@ load_network(void) } else { strcpy(net_cards_conf[c].host_dev_name, "none"); } + + sprintf(temp, "net_%02i_link", c +1); + net_cards_conf[c].link_state = config_get_int(cat, temp, + (NET_LINK_10_HD|NET_LINK_10_FD|NET_LINK_100_HD|NET_LINK_100_FD|NET_LINK_1000_HD|NET_LINK_1000_FD)); + } } @@ -2767,6 +2772,13 @@ save_network(void) /* config_set_string(cat, temp, "none"); */ config_delete_var(cat, temp); } + + sprintf(temp, "net_%02i_link", c + 1); + if (net_cards_conf[c].link_state == (NET_LINK_10_HD|NET_LINK_10_FD|NET_LINK_100_HD|NET_LINK_100_FD|NET_LINK_1000_HD|NET_LINK_1000_FD)) { + config_delete_var(cat, temp); + } else { + config_set_int(cat, temp, net_cards_conf[c].link_state); + } } delete_section_if_empty(cat); diff --git a/src/include/86box/machine_status.h b/src/include/86box/machine_status.h index 2afed078e..6baafeeb0 100644 --- a/src/include/86box/machine_status.h +++ b/src/include/86box/machine_status.h @@ -21,7 +21,7 @@ typedef struct { dev_status_empty_active_t mo[MO_NUM]; dev_status_empty_active_t cassette; dev_status_active_t hdd[HDD_BUS_USB]; - dev_status_active_t net; + dev_status_active_t net[NET_CARD_MAX]; dev_status_empty_t cartridge[2]; } machine_status_t; diff --git a/src/include/86box/network.h b/src/include/86box/network.h index 4f9e6b70e..f294bf500 100644 --- a/src/include/86box/network.h +++ b/src/include/86box/network.h @@ -65,6 +65,17 @@ #define NET_PERIOD_10M 0.8 #define NET_PERIOD_100M 0.08 +enum { + NET_LINK_DOWN = (1 << 1), + NET_LINK_TEMP_DOWN = (1 << 2), + NET_LINK_10_HD = (1 << 3), + NET_LINK_10_FD = (1 << 4), + NET_LINK_100_HD = (1 << 5), + NET_LINK_100_FD = (1 << 6), + NET_LINK_1000_HD = (1 << 7), + NET_LINK_1000_FD = (1 << 8), +}; + /* Supported network cards. */ enum { NONE = 0, @@ -84,14 +95,14 @@ typedef struct { int device_num; int net_type; char host_dev_name[128]; + uint32_t link_state; } 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 *); -typedef int (*NETSETLINKSTATE)(void *); +typedef int (*NETSETLINKSTATE)(void *, uint32_t link_state); typedef struct netpkt { @@ -121,9 +132,7 @@ 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; @@ -132,6 +141,9 @@ struct _netcard_t { pc_timer_t timer; int card_num; double byte_period; + uint32_t led_timer; + uint32_t led_state; + uint32_t link_state; }; typedef struct { @@ -152,7 +164,7 @@ extern netdev_t network_devs[NET_HOST_INTF_MAX]; /* Function prototypes. */ extern void network_init(void); -extern netcard_t *network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETWAITCB wait, NETSETLINKSTATE set_link_state); +extern netcard_t *network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETSETLINKSTATE set_link_state); extern void netcard_close(netcard_t *card); extern void network_close(void); extern void network_reset(void); @@ -161,6 +173,9 @@ extern void network_tx(netcard_t *card, uint8_t *, int); extern int net_pcap_prepare(netdev_t *); +extern void network_connect(int id, int connect); +extern int network_is_connected(int id); +extern int network_dev_available(int); extern int network_dev_to_id(char *); extern int network_card_available(int); extern int network_card_has_config(int); diff --git a/src/machine_status.c b/src/machine_status.c index 258c16821..3031c9ad3 100644 --- a/src/machine_status.c +++ b/src/machine_status.c @@ -19,6 +19,8 @@ #include <86box/zip.h> #include <86box/mo.h> #include <86box/hdd.h> +#include <86box/thread.h> +#include <86box/network.h> #include <86box/machine_status.h> machine_status_t machine_status; @@ -48,5 +50,7 @@ machine_status_init() { machine_status.hdd[i].active = false; } - machine_status.net.active = false; + for (size_t i = 0; i < NET_CARD_MAX; i++) { + machine_status.net[i].active = false; + } } \ No newline at end of file diff --git a/src/network/net_3c503.c b/src/network/net_3c503.c index d54a00593..2e5c97519 100644 --- a/src/network/net_3c503.c +++ b/src/network/net_3c503.c @@ -619,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. */ - dev->dp8390->card = network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL, NULL); + dev->dp8390->card = network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL); return(dev); } diff --git a/src/network/net_dp8390.c b/src/network/net_dp8390.c index c9908f883..ad4345ae6 100644 --- a/src/network/net_dp8390.c +++ b/src/network/net_dp8390.c @@ -228,7 +228,9 @@ dp8390_write_cr(dp8390_t *dev, uint32_t val) /* Send the packet to the system driver */ dev->CR.tx_packet = 1; - network_tx(dev->card, &dev->mem[(dev->tx_page_start * 256) - dev->mem_start], dev->tx_bytes); + /* TODO: report TX error to the driver ? */ + if (!(dev->card->link_state & NET_LINK_DOWN)) + network_tx(dev->card, &dev->mem[(dev->tx_page_start * 256) - dev->mem_start], dev->tx_bytes); /* some more debug */ #ifdef ENABLE_DP8390_LOG @@ -291,6 +293,8 @@ dp8390_rx_common(void *priv, uint8_t *buf, int io_len) if ((dev->CR.stop != 0) || (dev->page_start == 0)) return 0; + if (dev->card->link_state & NET_LINK_DOWN) + return 0; /* * Add the pkt header + CRC to the length, and work * out how many 256-byte pages the frame would occupy. diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index 960f7cdbf..c7f1a0ccb 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -1122,7 +1122,7 @@ nic_init(const device_t *info) nic_reset(dev); /* Attach ourselves to the network module. */ - dev->dp8390->card = network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL, NULL); + dev->dp8390->card = network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, 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_pcnet.c b/src/network/net_pcnet.c index 2b2b22540..340b056d3 100644 --- a/src/network/net_pcnet.c +++ b/src/network/net_pcnet.c @@ -29,6 +29,7 @@ #include #include #include +#include #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/io.h> @@ -1253,6 +1254,10 @@ pcnetReceiveNoSync(void *priv, uint8_t *buf, int size) if (!pcnetIsLinkUp(dev)) return 0; + dev->fMaybeOutOfSpace = !pcnetCanReceive(dev); + if (dev->fMaybeOutOfSpace) + return 0; + pcnetlog(1, "%s: pcnetReceiveNoSync: RX %x:%x:%x:%x:%x:%x > %x:%x:%x:%x:%x:%x len %d\n", dev->name, buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], @@ -2095,12 +2100,13 @@ pcnet_mii_readw(nic_t *dev, uint16_t miiaddr) | 0x0008 /* Able to do auto-negotiation. */ | 0x0004 /* Link up. */ | 0x0001; /* Extended Capability, i.e. registers 4+ valid. */ - if (!dev->fLinkUp || dev->fLinkTempDown || isolate) { + if (!pcnetIsLinkUp(dev) || isolate) { val &= ~(0x0020 | 0x0004); dev->cLinkDownReported++; } if (!autoneg) { /* Auto-negotiation disabled. */ + val &= ~(0x0020 | 0x0008); if (duplex) val &= ~0x2800; /* Full duplex forced. */ else @@ -2131,7 +2137,7 @@ pcnet_mii_readw(nic_t *dev, uint16_t miiaddr) case 5: /* Link partner ability register. */ - if (dev->fLinkUp && !dev->fLinkTempDown && !isolate) { + if (pcnetIsLinkUp(dev) && !isolate) { val = 0x8000 /* Next page bit. */ | 0x4000 /* Link partner acked us. */ | 0x0400 /* Can do flow control. */ @@ -2145,7 +2151,7 @@ pcnet_mii_readw(nic_t *dev, uint16_t miiaddr) case 6: /* Auto negotiation expansion register. */ - if (dev->fLinkUp && !dev->fLinkTempDown && !isolate) { + if (pcnetIsLinkUp(dev) && !isolate) { val = 0x0008 /* Link partner supports npage. */ | 0x0004 /* Enable npage words. */ | 0x0001; /* Can do N-way auto-negotiation. */ @@ -2157,7 +2163,7 @@ pcnet_mii_readw(nic_t *dev, uint16_t miiaddr) case 18: /* Diagnostic Register (FreeBSD pcn/ac101 driver reads this). */ - if (dev->fLinkUp && !dev->fLinkTempDown && !isolate) { + if (pcnetIsLinkUp(dev) && !isolate) { val = 0x1000 /* Receive PLL locked. */ | 0x0200; /* Signal detected. */ @@ -2195,7 +2201,7 @@ pcnet_bcr_readw(nic_t *dev, uint16_t rap) case BCR_LED2: case BCR_LED3: val = dev->aBCR[rap] & ~0x8000; - if (dev->fLinkTempDown || !dev->fLinkUp) { + if (!(pcnetIsLinkUp(dev))) { if (rap == 4) dev->cLinkDownReported++; val &= ~0x40; @@ -2846,40 +2852,28 @@ pcnetCanReceive(nic_t *dev) return rc; } - static int -pcnetWaitReceiveAvail(void *priv) +pcnetSetLinkState(void *priv, uint32_t link_state) { nic_t *dev = (nic_t *) priv; - dev->fMaybeOutOfSpace = !pcnetCanReceive(dev); - - return dev->fMaybeOutOfSpace; -} - -static int -pcnetSetLinkState(void *priv) -{ - nic_t *dev = (nic_t *) priv; - int fLinkUp; - - if (dev->fLinkTempDown) { - pcnetTempLinkDown(dev); - return 1; + if (link_state & NET_LINK_TEMP_DOWN) { + pcnetTempLinkDown(dev); + return 1; } - fLinkUp = (dev->fLinkUp && !dev->fLinkTempDown); - if (dev->fLinkUp != fLinkUp) { - dev->fLinkUp = fLinkUp; - if (fLinkUp) { - dev->fLinkTempDown = 1; - dev->cLinkDownReported = 0; - dev->aCSR[0] |= 0x8000 | 0x2000; /* ERR | CERR (this is probably wrong) */ - timer_set_delay_u64(&dev->timer_restore, (dev->cMsLinkUpDelay * 1000) * TIMER_USEC); - } else { - dev->cLinkDownReported = 0; - dev->aCSR[0] |= 0x8000 | 0x2000; /* ERR | CERR (this is probably wrong) */ - } + bool link_up = !(link_state & NET_LINK_DOWN); + if (dev->fLinkUp != link_up) { + dev->fLinkUp = link_up; + if (link_up) { + dev->fLinkTempDown = 1; + dev->cLinkDownReported = 0; + dev->aCSR[0] |= 0x8000 | 0x2000; + timer_set_delay_u64(&dev->timer_restore, (dev->cMsLinkUpDelay * 1000) * TIMER_USEC); + } else { + dev->cLinkDownReported = 0; + dev->aCSR[0] |= 0x8000 | 0x2000; + } } return 0; @@ -3058,7 +3052,7 @@ pcnet_init(const device_t *info) pcnetHardReset(dev); /* Attach ourselves to the network module. */ - dev->netcard = network_attach(dev, dev->aPROM, pcnetReceiveNoSync, pcnetWaitReceiveAvail, pcnetSetLinkState); + dev->netcard = network_attach(dev, dev->aPROM, pcnetReceiveNoSync, pcnetSetLinkState); dev->netcard->byte_period = (dev->board == DEV_AM79C973) ? NET_PERIOD_100M : NET_PERIOD_10M; timer_add(&dev->timer, pcnetPollTimer, dev, 0); diff --git a/src/network/net_plip.c b/src/network/net_plip.c index cf1a0f9c3..9372e8022 100644 --- a/src/network/net_plip.c +++ b/src/network/net_plip.c @@ -476,7 +476,7 @@ plip_net_init(const device_t *info) } plip_log(1, " (attached to LPT)\n"); - instance->card = network_attach(instance, instance->mac, plip_rx, NULL, NULL); + instance->card = network_attach(instance, instance->mac, plip_rx, NULL); return instance; } diff --git a/src/network/net_wd8003.c b/src/network/net_wd8003.c index be52a11aa..d53f570f0 100644 --- a/src/network/net_wd8003.c +++ b/src/network/net_wd8003.c @@ -788,7 +788,7 @@ wd_init(const device_t *info) mem_mapping_disable(&dev->ram_mapping); /* Attach ourselves to the network module. */ - dev->dp8390->card = network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL, NULL); + dev->dp8390->card = network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, 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 a8106afeb..7c6ab0826 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -346,6 +346,13 @@ network_rx_queue(void *priv) { netcard_t *card = (netcard_t *)priv; + uint32_t new_link_state = net_cards_conf[card->card_num].link_state; + if (new_link_state != card->link_state) { + if (card->set_link_state) + card->set_link_state(card->card_drv, new_link_state); + card->link_state = new_link_state; + } + uint32_t rx_bytes = 0; for (int i = 0; i < NET_QUEUE_LEN; i++) { if (card->queued_pkt.len == 0) { @@ -386,7 +393,13 @@ network_rx_queue(void *priv) timer_on_auto(&card->timer, timer_period); bool activity = rx_bytes || tx_bytes; - ui_sb_update_icon(SB_NETWORK, activity); + bool led_on = card->led_timer & 0x80000000; + if ((activity && !led_on) || (card->led_timer & 0x7fffffff) >= 150000) { + ui_sb_update_icon(SB_NETWORK | card->card_num, activity); + card->led_timer = 0 | (activity << 31); + } + + card->led_timer += timer_period; } @@ -398,13 +411,12 @@ network_rx_queue(void *priv) * modules. */ netcard_t * -network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETWAITCB wait, NETSETLINKSTATE set_link_state) +network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETSETLINKSTATE set_link_state) { 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(); @@ -496,8 +508,7 @@ network_reset(void) #endif 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"))) { + if (!network_dev_available(i)) { continue; } @@ -564,6 +575,28 @@ int network_rx_put_pkt(netcard_t *card, netpkt_t *pkt) return ret; } +void +network_connect(int id, int connect) +{ + if (id >= NET_CARD_MAX) + return; + + if (connect) { + net_cards_conf[id].link_state &= ~NET_LINK_DOWN; + } else { + net_cards_conf[id].link_state |= NET_LINK_DOWN; + } +} + +int +network_is_connected(int id) +{ + if (id >= NET_CARD_MAX) + return 0; + + return !(net_cards_conf[id].link_state & NET_LINK_DOWN); +} + int network_dev_to_id(char *devname) { @@ -575,19 +608,29 @@ network_dev_to_id(char *devname) } } - /* If no match found, assume "none". */ - return(0); + return(-1); } /* UI */ +int +network_dev_available(int id) +{ + int available = (net_cards_conf[id].device_num > 0) && (net_cards_conf[id].net_type != NET_TYPE_NONE); + + if ((net_cards_conf[id].net_type == NET_TYPE_PCAP && (network_dev_to_id(net_cards_conf[id].host_dev_name) <= 0))) + available = 0; + + return available; +} + int network_available(void) { int available = 0; 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); + available |= network_dev_available(i); } return available; diff --git a/src/qt/qt_machinestatus.cpp b/src/qt/qt_machinestatus.cpp index a6ea65fd3..c04d6ee5c 100644 --- a/src/qt/qt_machinestatus.cpp +++ b/src/qt/qt_machinestatus.cpp @@ -220,7 +220,9 @@ struct MachineStatus::States { for (auto& h : hdds) { h.pixmaps = &pixmaps.hd; } - net.pixmaps = &pixmaps.net; + for (auto& n : net) { + n.pixmaps = &pixmaps.net; + } } std::array cartridge; @@ -230,7 +232,7 @@ struct MachineStatus::States { std::array zip; std::array mo; std::array hdds; - StateActive net; + std::array net; std::unique_ptr sound; std::unique_ptr text; }; @@ -320,6 +322,14 @@ void MachineStatus::iterateMO(const std::function &cb) { } } +void MachineStatus::iterateNIC(const std::function &cb) { + for (int i = 0; i < NET_CARD_MAX; i++) { + if (network_dev_available(i)) { + cb(i); + } + } +} + static int hdd_count(int bus) { int c = 0; int i; @@ -357,7 +367,9 @@ void MachineStatus::refreshIcons() { d->hdds[i].setActive(machine_status.hdd[i].active); } - d->net.setActive(machine_status.net.active); + for (size_t i = 0; i < NET_CARD_MAX; i++) { + d->net[i].setActive(machine_status.net[i].active); + } for (int i = 0; i < 2; ++i) { d->cartridge[i].setEmpty(machine_status.cartridge[i].empty); @@ -375,7 +387,6 @@ void MachineStatus::refresh(QStatusBar* sbar) { int c_xta = hdd_count(HDD_BUS_XTA); int c_ide = hdd_count(HDD_BUS_IDE); int c_scsi = hdd_count(HDD_BUS_SCSI); - int do_net = network_available(); sbar->removeWidget(d->cassette.label.get()); for (int i = 0; i < 2; ++i) { @@ -396,7 +407,9 @@ void MachineStatus::refresh(QStatusBar* sbar) { for (size_t i = 0; i < HDD_BUS_USB; i++) { sbar->removeWidget(d->hdds[i].label.get()); } - sbar->removeWidget(d->net.label.get()); + for (size_t i = 0; i < NET_CARD_MAX; i++) { + sbar->removeWidget(d->net[i].label.get()); + } sbar->removeWidget(d->sound.get()); if (cassette_enable) { @@ -503,6 +516,17 @@ void MachineStatus::refresh(QStatusBar* sbar) { sbar->addWidget(d->mo[i].label.get()); }); + iterateNIC([this, sbar](int i) { + d->net[i].label = std::make_unique(); + d->net[i].setActive(false); + d->net[i].refresh(); + d->net[i].label->setToolTip(MediaMenu::ptr->netMenus[i]->title()); + connect((ClickableLabel*)d->net[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) { + MediaMenu::ptr->netMenus[i]->popup(pos - QPoint(0, MediaMenu::ptr->netMenus[i]->sizeHint().height())); + }); + sbar->addWidget(d->net[i].label.get()); + }); + auto hdc_name = QString(hdc_get_internal_name(hdc_current)); if ((has_mfm || hdc_name.left(5) == QStringLiteral("st506")) && c_mfm > 0) { d->hdds[HDD_BUS_MFM].label = std::make_unique(); @@ -541,13 +565,6 @@ void MachineStatus::refresh(QStatusBar* sbar) { sbar->addWidget(d->hdds[HDD_BUS_SCSI].label.get()); } - if (do_net) { - d->net.label = std::make_unique(); - d->net.setActive(false); - d->net.refresh(); - d->net.label->setToolTip(tr("Network")); - sbar->addWidget(d->net.label.get()); - } d->sound = std::make_unique(); d->sound->setPixmap(d->pixmaps.sound); diff --git a/src/qt/qt_machinestatus.hpp b/src/qt/qt_machinestatus.hpp index 8c31dd238..8d085f93a 100644 --- a/src/qt/qt_machinestatus.hpp +++ b/src/qt/qt_machinestatus.hpp @@ -66,6 +66,7 @@ public: static void iterateCDROM(const std::function& cb); static void iterateZIP(const std::function& cb); static void iterateMO(const std::function& cb); + static void iterateNIC(const std::function& cb); QString getMessage(); public slots: diff --git a/src/qt/qt_mediamenu.cpp b/src/qt/qt_mediamenu.cpp index a4fcb5113..90cd80257 100644 --- a/src/qt/qt_mediamenu.cpp +++ b/src/qt/qt_mediamenu.cpp @@ -44,10 +44,14 @@ extern "C" { #include <86box/mo.h> #include <86box/sound.h> #include <86box/ui.h> +#include <86box/thread.h> +#include <86box/network.h> + }; #include "qt_newfloppydialog.hpp" #include "qt_util.hpp" +#include "qt_deviceconfig.hpp" std::shared_ptr MediaMenu::ptr; @@ -156,6 +160,16 @@ void MediaMenu::refresh(QMenu *parentMenu) { moMenus[i] = menu; moUpdateMenu(i); }); + + netMenus.clear(); + MachineStatus::iterateNIC([this, parentMenu](int i) { + auto *menu = parentMenu->addMenu(""); + netDisconnPos = menu->children().count(); + auto *action = menu->addAction(tr("&Disconnected"), [i] { network_connect(i, !network_is_connected(i)); config_save(); }); + action->setCheckable(true); + netMenus[i] = menu; + nicUpdateMenu(i); + }); } void MediaMenu::cassetteNewImage() { @@ -662,6 +676,30 @@ void MediaMenu::moUpdateMenu(int i) { menu->setTitle(QString::asprintf(tr("MO %i (%ls): %ls").toUtf8().constData(), i + 1, busName.toStdU16String().data(), name.isEmpty() ? tr("(empty)").toStdU16String().data() : name.toStdU16String().data())); } +void MediaMenu::nicUpdateMenu(int i) { + if (!netMenus.contains(i)) + return; + + QString netType = tr("None"); + switch (net_cards_conf[i].net_type) { + case NET_TYPE_SLIRP: + netType = "SLiRP"; + break; + case NET_TYPE_PCAP: + netType = "PCAP"; + break; + } + + QString devName = DeviceConfig::DeviceName(network_card_getdevice(net_cards_conf[i].device_num), network_card_get_internal_name(net_cards_conf[i].device_num), 1); + + auto *menu = netMenus[i]; + auto childs = menu->children(); + auto *connectedAction = dynamic_cast(childs[netDisconnPos]); + connectedAction->setChecked(!network_is_connected(i)); + + menu->setTitle(QString::asprintf(tr("NIC %02i (%ls) %ls").toUtf8().constData(), i + 1, netType.toStdU16String().data(), devName.toStdU16String().data())); +} + QString MediaMenu::getMediaOpenDirectory() { QString openDirectory; if (open_dir_usr_path > 0) { diff --git a/src/qt/qt_mediamenu.hpp b/src/qt/qt_mediamenu.hpp index 9b08d3ee3..a5c50a472 100644 --- a/src/qt/qt_mediamenu.hpp +++ b/src/qt/qt_mediamenu.hpp @@ -56,6 +56,8 @@ public: void moEject(int i); void moReload(int i); void moUpdateMenu(int i); + + void nicUpdateMenu(int i); private: QWidget* parentWidget = nullptr; @@ -65,6 +67,7 @@ private: QMap cdromMenus; QMap zipMenus; QMap moMenus; + QMap netMenus; QString getMediaOpenDirectory(); @@ -89,5 +92,7 @@ private: int moEjectPos; int moReloadPos; + int netDisconnPos; + friend class MachineStatus; }; diff --git a/src/qt/qt_ui.cpp b/src/qt/qt_ui.cpp index 7400a4f7a..65a8cec44 100644 --- a/src/qt/qt_ui.cpp +++ b/src/qt/qt_ui.cpp @@ -50,6 +50,8 @@ extern "C" { #include <86box/zip.h> #include <86box/mo.h> #include <86box/hdd.h> +#include <86box/thread.h> +#include <86box/network.h> #include <86box/machine_status.h> void @@ -246,7 +248,7 @@ ui_sb_update_icon(int tag, int active) { machine_status.hdd[item].active = active > 0 ? true : false; break; case SB_NETWORK: - machine_status.net.active = active > 0 ? true : false; + machine_status.net[item].active = active > 0 ? true : false; break; case SB_SOUND: break; From d3dde1737a6a8f11dbf83beacde9aeeefd710682 Mon Sep 17 00:00:00 2001 From: Adrien Moulin Date: Sun, 28 Aug 2022 13:56:24 +0200 Subject: [PATCH 17/17] network: add a new status bar icon for the network disconnected state --- src/include/86box/machine_status.h | 2 +- src/machine_status.c | 1 + src/qt/qt_machinestatus.cpp | 6 ++++-- src/qt/qt_mediamenu.cpp | 18 ++++++++++++++++-- src/qt/qt_mediamenu.hpp | 2 ++ src/qt/qt_ui.cpp | 1 + src/qt_resources.qrc | 1 + src/win/icons/network_empty.ico | Bin 0 -> 6950 bytes 8 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 src/win/icons/network_empty.ico diff --git a/src/include/86box/machine_status.h b/src/include/86box/machine_status.h index 6baafeeb0..31cefdfd4 100644 --- a/src/include/86box/machine_status.h +++ b/src/include/86box/machine_status.h @@ -21,7 +21,7 @@ typedef struct { dev_status_empty_active_t mo[MO_NUM]; dev_status_empty_active_t cassette; dev_status_active_t hdd[HDD_BUS_USB]; - dev_status_active_t net[NET_CARD_MAX]; + dev_status_empty_active_t net[NET_CARD_MAX]; dev_status_empty_t cartridge[2]; } machine_status_t; diff --git a/src/machine_status.c b/src/machine_status.c index 3031c9ad3..1429d9295 100644 --- a/src/machine_status.c +++ b/src/machine_status.c @@ -52,5 +52,6 @@ machine_status_init() { for (size_t i = 0; i < NET_CARD_MAX; i++) { machine_status.net[i].active = false; + machine_status.net[i].empty = !network_is_connected(i); } } \ No newline at end of file diff --git a/src/qt/qt_machinestatus.cpp b/src/qt/qt_machinestatus.cpp index c04d6ee5c..9e93e882b 100644 --- a/src/qt/qt_machinestatus.cpp +++ b/src/qt/qt_machinestatus.cpp @@ -88,7 +88,7 @@ namespace { PixmapSetEmptyActive zip; PixmapSetEmptyActive mo; PixmapSetActive hd; - PixmapSetActive net; + PixmapSetEmptyActive net; QPixmap sound; }; @@ -232,7 +232,7 @@ struct MachineStatus::States { std::array zip; std::array mo; std::array hdds; - std::array net; + std::array net; std::unique_ptr sound; std::unique_ptr text; }; @@ -369,6 +369,7 @@ void MachineStatus::refreshIcons() { for (size_t i = 0; i < NET_CARD_MAX; i++) { d->net[i].setActive(machine_status.net[i].active); + d->net[i].setEmpty(machine_status.net[i].empty); } for (int i = 0; i < 2; ++i) { @@ -518,6 +519,7 @@ void MachineStatus::refresh(QStatusBar* sbar) { iterateNIC([this, sbar](int i) { d->net[i].label = std::make_unique(); + d->net[i].setEmpty(!network_is_connected(i)); d->net[i].setActive(false); d->net[i].refresh(); d->net[i].label->setToolTip(MediaMenu::ptr->netMenus[i]->title()); diff --git a/src/qt/qt_mediamenu.cpp b/src/qt/qt_mediamenu.cpp index 90cd80257..0050da900 100644 --- a/src/qt/qt_mediamenu.cpp +++ b/src/qt/qt_mediamenu.cpp @@ -165,7 +165,7 @@ void MediaMenu::refresh(QMenu *parentMenu) { MachineStatus::iterateNIC([this, parentMenu](int i) { auto *menu = parentMenu->addMenu(""); netDisconnPos = menu->children().count(); - auto *action = menu->addAction(tr("&Disconnected"), [i] { network_connect(i, !network_is_connected(i)); config_save(); }); + auto *action = menu->addAction(tr("&Connected"), [this, i] { network_is_connected(i) ? nicDisconnect(i) : nicConnect(i); }); action->setCheckable(true); netMenus[i] = menu; nicUpdateMenu(i); @@ -676,6 +676,20 @@ void MediaMenu::moUpdateMenu(int i) { menu->setTitle(QString::asprintf(tr("MO %i (%ls): %ls").toUtf8().constData(), i + 1, busName.toStdU16String().data(), name.isEmpty() ? tr("(empty)").toStdU16String().data() : name.toStdU16String().data())); } +void MediaMenu::nicConnect(int i) { + network_connect(i, 1); + ui_sb_update_icon_state(SB_NETWORK|i, 0); + nicUpdateMenu(i); + config_save(); +} + +void MediaMenu::nicDisconnect(int i) { + network_connect(i, 0); + ui_sb_update_icon_state(SB_NETWORK|i, 1); + nicUpdateMenu(i); + config_save(); +} + void MediaMenu::nicUpdateMenu(int i) { if (!netMenus.contains(i)) return; @@ -695,7 +709,7 @@ void MediaMenu::nicUpdateMenu(int i) { auto *menu = netMenus[i]; auto childs = menu->children(); auto *connectedAction = dynamic_cast(childs[netDisconnPos]); - connectedAction->setChecked(!network_is_connected(i)); + connectedAction->setChecked(network_is_connected(i)); menu->setTitle(QString::asprintf(tr("NIC %02i (%ls) %ls").toUtf8().constData(), i + 1, netType.toStdU16String().data(), devName.toStdU16String().data())); } diff --git a/src/qt/qt_mediamenu.hpp b/src/qt/qt_mediamenu.hpp index a5c50a472..de892d73c 100644 --- a/src/qt/qt_mediamenu.hpp +++ b/src/qt/qt_mediamenu.hpp @@ -57,6 +57,8 @@ public: void moReload(int i); void moUpdateMenu(int i); + void nicConnect(int i); + void nicDisconnect(int i); void nicUpdateMenu(int i); private: QWidget* parentWidget = nullptr; diff --git a/src/qt/qt_ui.cpp b/src/qt/qt_ui.cpp index 65a8cec44..febf4cba7 100644 --- a/src/qt/qt_ui.cpp +++ b/src/qt/qt_ui.cpp @@ -215,6 +215,7 @@ ui_sb_update_icon_state(int tag, int state) { case SB_HDD: break; case SB_NETWORK: + machine_status.net[item].empty = state > 0 ? true : false; break; case SB_SOUND: break; diff --git a/src/qt_resources.qrc b/src/qt_resources.qrc index fec56ad71..67f9cadac 100644 --- a/src/qt_resources.qrc +++ b/src/qt_resources.qrc @@ -33,6 +33,7 @@ win/icons/mo_empty_active.ico win/icons/network.ico win/icons/network_active.ico + win/icons/network_empty.ico win/icons/other_peripherals.ico win/icons/other_removable_devices.ico win/icons/ports.ico diff --git a/src/win/icons/network_empty.ico b/src/win/icons/network_empty.ico new file mode 100644 index 0000000000000000000000000000000000000000..4a1a102846ea018ba6d899b5352dd9fbdcfce858 GIT binary patch literal 6950 zcmeHLJ#Q015S{qj1WO4@kuoJEKY@xW1qIUsq z+(bghdow$GXI~r%I^cF?&+dHf>{@wmHzEhplcOVn9La~i$U6}^IkEX@Ao2;i(^H#& z!F+Kja&~6(k0X)UE0NcTK?;Fd^FZuvM_BCm_*l-*&*k#+Qf9N6q-iQwS66a~J5*p}fFns2#BrfZ_;>&<0p;3`NHk z6Rn_TXMQSU080XbTKje(lI0>vBC^UvzCvb@oJUDJ{Q!GOx-E&bfM&&8;`MXQ@wJYt z#MJxy`xaN9JGj=?p1{9-0v!NYfUvO+2(MAuQD7P1o9NmhZkn~L3Mx5A!)*{l_Y0s$ z+$LzU$7RgVmOv=iV`nIrQ@=4&LdgYeWlYA}sWe~p@bC`QTAxPh*Ff{?(7n1^XK)z< z=mS}J5dDV0=s-B8wqgP;nX1a?k&sn|TT1hds&ccIJo^lse-E5D`8~Ul2c6$+>1i*L zwPf?P6w{_$E!T?wxRT2oeEyUN+Pii9dD=mH0{`y`7`TW1``wlR78yY>#O)Y3N~AP& zR;H?}okspu`kQp8< zoL4djZ*fjZ|2bp|Swfakt}x$V{+O4_V`o_UEk3`?W4E`r?f-~yZf$E%pgn=c3D`TL zp*984ukmLbsQQ^*nI7&P-Y3gp<>h1?Pxh@OlghB}cL$3zEvF41wqn~b_)&21G9$ejCDZIQ>v=*26#ghPljYEDIX#e8XsoIL2O1w6shHVQQzD)w z>)RVtv+