Merge pull request #2630 from elyosh/network
Network overhaul: support for multiple NICs, performance improvement
This commit is contained in:
@@ -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();
|
||||
|
||||
|
169
src/config.c
169
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);
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
|
22
src/include/86box/net_event.h
Normal file
22
src/include/86box/net_event.h
Normal 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
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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
76
src/network/net_event.c
Normal 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
|
@@ -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);
|
||||
|
@@ -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
|
||||
};
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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) {}
|
||||
|
@@ -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,
|
||||
|
@@ -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 },
|
||||
{ ð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; 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;
|
||||
}
|
||||
}
|
@@ -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>
|
||||
|
@@ -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));
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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/>
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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>
|
||||
|
@@ -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>
|
||||
|
Reference in New Issue
Block a user