Merge pull request #2630 from elyosh/network

Network overhaul: support for multiple NICs, performance improvement
This commit is contained in:
Miran Grča
2022-08-21 19:13:20 +02:00
committed by GitHub
23 changed files with 1560 additions and 1078 deletions

View File

@@ -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();

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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);
}

View File

@@ -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);
}
}

76
src/network/net_event.c Normal file
View File

@@ -0,0 +1,76 @@
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <unistd.h>
#include <fcntl.h>
#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

View File

@@ -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);

View File

@@ -50,15 +50,38 @@
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include <stdbool.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#else
#include <poll.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>
#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 <pcap/pcap.h>
#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
};

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -24,6 +24,7 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include <wchar.h>
#include <slirp/libslirp.h>
#define HAVE_STDARG_H
@@ -31,45 +32,41 @@
#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 <winsock2.h>
# define poll WSAPoll
# else
# include <poll.h>
# endif
#include <86box/video.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <poll.h>
#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 +98,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 +115,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 +152,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 +290,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) {}

View File

@@ -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,

View File

@@ -56,6 +56,7 @@
#include <stdlib.h>
#include <wchar.h>
#include <time.h>
#include <stdbool.h>
#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 <windows.h>
#include <winsock2.h>
#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 },
{ &ethernext_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,
&ethernext_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; i<queue->size; 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; i<queue->size; 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;
}
}

View File

@@ -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>

View File

@@ -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<QComboBox*>(QString("comboBoxNIC%1").arg(i+1));
auto* net_type_cbox = findChild<QComboBox*>(QString("comboBoxNet%1").arg(i+1));
auto* intf_cbox = findChild<QComboBox*>(QString("comboBoxIntf%1").arg(i+1));
auto* conf_btn = findChild<QPushButton*>(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<QComboBox*>(QString("comboBoxNIC%1").arg(i+1));
auto* net_type_cbox = findChild<QComboBox*>(QString("comboBoxNet%1").arg(i+1));
auto* intf_cbox = findChild<QComboBox*>(QString("comboBoxIntf%1").arg(i+1));
connect(nic_cbox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SettingsNetwork::on_comboIndexChanged);
connect(net_type_cbox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SettingsNetwork::on_comboIndexChanged);
connect(intf_cbox, QOverload<int>::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<QComboBox*>(QString("comboBoxNIC%1").arg(i+1));
net_cards_conf[i].device_num = cbox->currentData().toInt();
cbox = findChild<QComboBox*>(QString("comboBoxNet%1").arg(i+1));
net_cards_conf[i].net_type = cbox->currentData().toInt();
cbox = findChild<QComboBox*>(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<QComboBox*>(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<QComboBox*>(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<QComboBox*>(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::settings));
}
void SettingsNetwork::on_pushButtonConfigure_clicked() {
DeviceConfig::ConfigureDevice(network_card_getdevice(ui->comboBoxAdapter->currentData().toInt()), 0, qobject_cast<Settings*>(Settings::settings));
void SettingsNetwork::on_pushButtonConf2_clicked() {
DeviceConfig::ConfigureDevice(network_card_getdevice(ui->comboBoxNIC2->currentData().toInt()), 0, qobject_cast<Settings*>(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::settings));
}
void SettingsNetwork::on_pushButtonConf4_clicked() {
DeviceConfig::ConfigureDevice(network_card_getdevice(ui->comboBoxNIC4->currentData().toInt()), 0, qobject_cast<Settings*>(Settings::settings));
}

View File

@@ -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;

View File

@@ -6,14 +6,14 @@
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
<width>548</width>
<height>458</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
@@ -26,7 +26,291 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item row="6" column="0">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Network Interface Contollers</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="4">
<widget class="QLabel" name="label_7">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Adapter</string>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QComboBox" name="comboBoxIntf4">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QComboBox" name="comboBoxIntf3">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="3" column="5">
<widget class="QPushButton" name="pushButtonConf3">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="comboBoxNet1">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Card 3:</string>
</property>
</widget>
</item>
<item row="4" column="4">
<widget class="QComboBox" name="comboBoxNIC4">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Card 1:</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Interface</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QComboBox" name="comboBoxNIC1">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
</widget>
</item>
<item row="1" column="5">
<widget class="QPushButton" name="pushButtonConf1">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QComboBox" name="comboBoxNIC3">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QComboBox" name="comboBoxNet4">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Card 4:</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Mode</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Card 2:</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QComboBox" name="comboBoxNet3">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QComboBox" name="comboBoxNet2">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="2" column="5">
<widget class="QPushButton" name="pushButtonConf2">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="4" column="5">
<widget class="QPushButton" name="pushButtonConf4">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QComboBox" name="comboBoxIntf1">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QComboBox" name="comboBoxIntf2">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QComboBox" name="comboBoxNIC2">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -39,57 +323,6 @@
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>PCap device:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Network type:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="comboBoxAdapter">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Network adapter:</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="pushButtonConfigure">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QComboBox" name="comboBoxNetwork">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QComboBox" name="comboBoxPcap"/>
</item>
</layout>
</widget>
<resources/>

View File

@@ -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
@@ -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

View File

@@ -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>

View File

@@ -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>