Merge branch 'master' of ssh://github.com/86Box/86Box

This commit is contained in:
RichardG867
2022-08-30 17:39:42 -03:00
37 changed files with 1970 additions and 1231 deletions

View File

@@ -60,7 +60,6 @@
#include <86box/device.h>
#include <86box/pit.h>
#include <86box/random.h>
#include <86box/timer.h>
#include <86box/nvr.h>
#include <86box/machine.h>
#include <86box/bugger.h>
@@ -85,6 +84,7 @@
#include <86box/mo.h>
#include <86box/scsi_disk.h>
#include <86box/cdrom_image.h>
#include <86box/thread.h>
#include <86box/network.h>
#include <86box/sound.h>
#include <86box/midi.h>
@@ -93,7 +93,6 @@
#include <86box/ui.h>
#include <86box/path.h>
#include <86box/plat.h>
#include <86box/thread.h>
#include <86box/version.h>
#include <86box/gdbstub.h>
#include <86box/machine_status.h>
@@ -951,8 +950,6 @@ pc_reset_hard_close(void)
/* Close all the memory mappings. */
mem_close();
network_timer_stop();
/* Turn off timer processing to avoid potential segmentation faults. */
timer_close();
@@ -1173,8 +1170,6 @@ pc_close(thread_t *ptr)
/* Close all the memory mappings. */
mem_close();
network_timer_stop();
/* Turn off timer processing to avoid potential segmentation faults. */
timer_close();

View File

@@ -55,6 +55,7 @@
#include <86box/gameport.h>
#include <86box/machine.h>
#include <86box/mouse.h>
#include <86box/thread.h>
#include <86box/network.h>
#include <86box/scsi.h>
#include <86box/scsi_device.h>
@@ -1131,45 +1132,94 @@ 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");
}
sprintf(temp, "net_%02i_link", c +1);
net_cards_conf[c].link_state = config_get_int(cat, temp,
(NET_LINK_10_HD|NET_LINK_10_FD|NET_LINK_100_HD|NET_LINK_100_FD|NET_LINK_1000_HD|NET_LINK_1000_FD));
}
}
/* Load "Ports" section. */
@@ -2688,30 +2738,49 @@ 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);
}
sprintf(temp, "net_%02i_link", c + 1);
if (net_cards_conf[c].link_state == (NET_LINK_10_HD|NET_LINK_10_FD|NET_LINK_100_HD|NET_LINK_100_FD|NET_LINK_1000_HD|NET_LINK_1000_FD)) {
config_delete_var(cat, temp);
} else {
config_set_int(cat, temp, net_cards_conf[c].link_state);
}
}
if (network_card == 0)
config_delete_var(cat, "net_card");
else
config_set_string(cat, "net_card",
network_card_get_internal_name(network_card));
delete_section_if_empty(cat);
}

View File

@@ -122,9 +122,6 @@ extern int cpu, /* (C) cpu type */
cpu_use_dynarec, /* (C) cpu uses/needs Dyna */
fpu_type; /* (C) fpu type */
extern int time_sync; /* (C) enable time sync */
extern int network_type; /* (C) net provider type */
extern int network_card; /* (C) net interface num */
extern char network_host[522]; /* (C) host network intf */
extern int hdd_format_type; /* (C) hard disk file format */
extern int confirm_reset, /* (C) enable reset confirmation */
confirm_exit, /* (C) enable exit confirmation */

View File

@@ -21,7 +21,7 @@ typedef struct {
dev_status_empty_active_t mo[MO_NUM];
dev_status_empty_active_t cassette;
dev_status_active_t hdd[HDD_BUS_USB];
dev_status_active_t net;
dev_status_empty_active_t net[NET_CARD_MAX];
dev_status_empty_t cartridge[2];
} machine_status_t;

View File

@@ -184,11 +184,13 @@ typedef struct {
int tx_timer_active;
void *priv;
netcard_t *card;
void (*interrupt)(void *priv, int set);
} dp8390_t;
extern const device_t dp8390_device;
extern int dp3890_inst;
extern uint32_t dp8390_chipmem_read(dp8390_t *dev, uint32_t addr, unsigned int len);

View File

@@ -0,0 +1,22 @@
#ifndef EMU_NET_EVENT_H
#define EMU_NET_EVENT_H
typedef struct {
#ifdef _WIN32
HANDLE handle;
#else
int fds[2];
#endif
} net_evt_t;
extern void net_event_init(net_evt_t *event);
extern void net_event_set(net_evt_t *event);
extern void net_event_clear(net_evt_t *event);
extern void net_event_close(net_evt_t *event);
#ifdef _WIN32
extern HANDLE net_event_get_handle(net_evt_t *event);
#else
extern int net_event_get_fd(net_evt_t *event);
#endif
#endif

View File

@@ -52,8 +52,29 @@
/* 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
/* Queue size must be a power of 2 */
#define NET_QUEUE_LEN 16
#define NET_QUEUE_LEN_MASK (NET_QUEUE_LEN - 1)
#define NET_CARD_MAX 4
#define NET_HOST_INTF_MAX 64
#define NET_PERIOD_10M 0.8
#define NET_PERIOD_100M 0.08
enum {
NET_LINK_DOWN = (1 << 1),
NET_LINK_TEMP_DOWN = (1 << 2),
NET_LINK_10_HD = (1 << 3),
NET_LINK_10_FD = (1 << 4),
NET_LINK_100_HD = (1 << 5),
NET_LINK_100_FD = (1 << 6),
NET_LINK_1000_HD = (1 << 7),
NET_LINK_1000_FD = (1 << 8),
};
/* Supported network cards. */
enum {
@@ -64,28 +85,66 @@ 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];
uint32_t link_state;
} netcard_conf_t;
extern netcard_conf_t net_cards_conf[NET_CARD_MAX];
extern int net_card_current;
typedef int (*NETRXCB)(void *, uint8_t *, int);
typedef int (*NETWAITCB)(void *);
typedef int (*NETSETLINKSTATE)(void *);
typedef int (*NETSETLINKSTATE)(void *, uint32_t link_state);
typedef struct netpkt {
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;
} 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 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;
NETRXCB rx;
NETSETLINKSTATE set_link_state;
netqueue_t queues[3];
netpkt_t queued_pkt;
mutex_t *tx_mutex;
mutex_t *rx_mutex;
pc_timer_t timer;
int card_num;
double byte_period;
uint32_t led_timer;
uint32_t led_state;
uint32_t link_state;
};
typedef struct {
char device[128];
@@ -100,32 +159,23 @@ 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];
extern netdev_t network_devs[NET_HOST_INTF_MAX];
/* 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, 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 void network_connect(int id, int connect);
extern int network_is_connected(int id);
extern int network_dev_available(int);
extern int network_dev_to_id(char *);
extern int network_card_available(int);
extern int network_card_has_config(int);
@@ -133,13 +183,10 @@ 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_tx_popv(netcard_t *card, netpkt_t *pkt_vec, int vec_size);
extern int network_rx_put(netcard_t *card, uint8_t *bufp, int len);
extern int network_rx_put_pkt(netcard_t *card, netpkt_t *pkt);
#ifdef __cplusplus
}
#endif

View File

@@ -46,32 +46,24 @@ static int next_block_to_write[4] = { 0, 0 };
#define addbyte(val) \
do { \
code_block[block_pos++] = val; \
if (block_pos >= BLOCK_SIZE) \
fatal("Over!\n"); \
} while (0)
#define addword(val) \
do { \
*(uint16_t *) &code_block[block_pos] = val; \
block_pos += 2; \
if (block_pos >= BLOCK_SIZE) \
fatal("Over!\n"); \
} while (0)
#define addlong(val) \
do { \
*(uint32_t *) &code_block[block_pos] = val; \
block_pos += 4; \
if (block_pos >= BLOCK_SIZE) \
fatal("Over!\n"); \
} while (0)
#define addquad(val) \
do { \
*(uint64_t *) &code_block[block_pos] = val; \
block_pos += 8; \
if (block_pos >= BLOCK_SIZE) \
fatal("Over!\n"); \
} while (0)
static __m128i xmm_01_w; // = 0x0001000100010001ull;

View File

@@ -44,32 +44,24 @@ static int next_block_to_write[4] = { 0, 0 };
#define addbyte(val) \
do { \
code_block[block_pos++] = val; \
if (block_pos >= BLOCK_SIZE) \
fatal("Over!\n"); \
} while (0)
#define addword(val) \
do { \
*(uint16_t *) &code_block[block_pos] = val; \
block_pos += 2; \
if (block_pos >= BLOCK_SIZE) \
fatal("Over!\n"); \
} while (0)
#define addlong(val) \
do { \
*(uint32_t *) &code_block[block_pos] = val; \
block_pos += 4; \
if (block_pos >= BLOCK_SIZE) \
fatal("Over!\n"); \
} while (0)
#define addquad(val) \
do { \
*(uint64_t *) &code_block[block_pos] = val; \
block_pos += 8; \
if (block_pos >= BLOCK_SIZE) \
fatal("Over!\n"); \
} while (0)
static __m128i xmm_01_w; // = 0x0001000100010001ull;

View File

@@ -11080,6 +11080,44 @@ const machine_t machines[] = {
.snd_device = NULL,
.net_device = NULL
},
/* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC
firmware. */
{
.name = "[VIA Apollo Pro 133A] BCM GT694VA",
.internal_name = "gt694va",
.type = MACHINE_TYPE_SLOT1,
.chipset = MACHINE_CHIPSET_VIA_APOLLO_PRO_133A,
.init = machine_at_gt694va_init,
.pad = 0,
.pad0 = 0,
.pad1 = MACHINE_AVAILABLE,
.pad2 = 0,
.cpu = {
.package = CPU_PKG_SLOT1,
.block = CPU_BLOCK_NONE,
.min_bus = 66666667,
.max_bus = 133333333,
.min_voltage = 1300,
.max_voltage = 3500,
.min_multi = 1.5,
.max_multi = 8.0
},
.bus_flags = MACHINE_PS2_AGP,
.flags = MACHINE_IDE_DUAL | MACHINE_SOUND,
.ram = {
.min = 8192,
.max = 3145728,
.step = 8192
},
.nvrmask = 255,
.kbc = KBC_UNKNOWN,
.kbc_p1 = 0,
.gpio = 0,
.device = &es1371_onboard_device,
.vid_device = NULL,
.snd_device = NULL,
.net_device = NULL
},
/* Slot 1/2 machines */
/* 440GX */
@@ -11632,44 +11670,6 @@ const machine_t machines[] = {
.snd_device = NULL,
.net_device = NULL
},
/* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC
firmware. */
{
.name = "[VIA Apollo Pro 133A] BCM GT694VA",
.internal_name = "gt694va",
.type = MACHINE_TYPE_SOCKET370,
.chipset = MACHINE_CHIPSET_VIA_APOLLO_PRO_133A,
.init = machine_at_gt694va_init,
.pad = 0,
.pad0 = 0,
.pad1 = MACHINE_AVAILABLE,
.pad2 = 0,
.cpu = {
.package = CPU_PKG_SOCKET370,
.block = CPU_BLOCK_NONE,
.min_bus = 66666667,
.max_bus = 133333333,
.min_voltage = 1300,
.max_voltage = 3500,
.min_multi = 1.5,
.max_multi = 8.0
},
.bus_flags = MACHINE_PS2_AGP,
.flags = MACHINE_IDE_DUAL | MACHINE_SOUND,
.ram = {
.min = 16384,
.max = 3145728,
.step = 8192
},
.nvrmask = 255,
.kbc = KBC_UNKNOWN,
.kbc_p1 = 0,
.gpio = 0,
.device = &es1371_onboard_device,
.vid_device = NULL,
.snd_device = NULL,
.net_device = NULL
},
/* Miscellaneous/Fake/Hypervisor machines */
/* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC

View File

@@ -19,6 +19,8 @@
#include <86box/zip.h>
#include <86box/mo.h>
#include <86box/hdd.h>
#include <86box/thread.h>
#include <86box/network.h>
#include <86box/machine_status.h>
machine_status_t machine_status;
@@ -48,5 +50,8 @@ machine_status_init() {
machine_status.hdd[i].active = false;
}
machine_status.net.active = false;
for (size_t i = 0; i < NET_CARD_MAX; i++) {
machine_status.net[i].active = false;
machine_status.net[i].empty = !network_is_connected(i);
}
}

View File

@@ -14,7 +14,7 @@
#
add_library(net OBJECT network.c net_pcap.c net_slirp.c net_dp8390.c net_3c503.c
net_ne2000.c net_pcnet.c net_wd8003.c net_plip.c)
net_ne2000.c net_pcnet.c net_wd8003.c net_plip.c net_event.c)
option(SLIRP_EXTERNAL "Link against the system-provided libslirp library" OFF)
mark_as_advanced(SLIRP_EXTERNAL)
@@ -35,3 +35,7 @@ endif()
if (HAIKU)
target_link_libraries(86Box network)
endif()
if(WIN32)
target_link_libraries(86Box ws2_32)
endif()

View File

@@ -55,6 +55,8 @@
#include <86box/mem.h>
#include <86box/random.h>
#include <86box/device.h>
#include <86box/thread.h>
#include <86box/timer.h>
#include <86box/network.h>
#include <86box/net_dp8390.h>
#include <86box/net_3c503.h>
@@ -592,7 +594,7 @@ threec503_nic_init(const device_t *info)
dev->maclocal[5] = (mac & 0xff);
}
dev->dp8390 = device_add(&dp8390_device);
dev->dp8390 = device_add_inst(&dp8390_device, dp3890_inst++);
dev->dp8390->priv = dev;
dev->dp8390->interrupt = threec503_interrupt;
dp8390_set_defaults(dev->dp8390, DP8390_FLAG_CHECK_CR | DP8390_FLAG_CLEAR_IRQ);
@@ -617,7 +619,7 @@ threec503_nic_init(const device_t *info)
dev->regs.gacfr = 0x09; /* Start with RAM mapping enabled. */
/* Attach ourselves to the network module. */
network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL, NULL);
dev->dp8390->card = network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL);
return(dev);
}

View File

@@ -25,6 +25,8 @@
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/thread.h>
#include <86box/timer.h>
#include <86box/network.h>
#include <86box/net_dp8390.h>
@@ -33,6 +35,7 @@ static void dp8390_tx(dp8390_t *dev, uint32_t val);
static int dp8390_rx_common(void *priv, uint8_t *buf, int io_len);
int dp8390_rx(void *priv, uint8_t *buf, int io_len);
int dp3890_inst = 0;
#ifdef ENABLE_DP8390_LOG
int dp8390_do_log = ENABLE_DP8390_LOG;
@@ -225,7 +228,9 @@ dp8390_write_cr(dp8390_t *dev, uint32_t val)
/* Send the packet to the system driver */
dev->CR.tx_packet = 1;
network_tx(&dev->mem[(dev->tx_page_start * 256) - dev->mem_start], dev->tx_bytes);
/* TODO: report TX error to the driver ? */
if (!(dev->card->link_state & NET_LINK_DOWN))
network_tx(dev->card, &dev->mem[(dev->tx_page_start * 256) - dev->mem_start], dev->tx_bytes);
/* some more debug */
#ifdef ENABLE_DP8390_LOG
@@ -288,6 +293,8 @@ dp8390_rx_common(void *priv, uint8_t *buf, int io_len)
if ((dev->CR.stop != 0) || (dev->page_start == 0))
return 0;
if (dev->card->link_state & NET_LINK_DOWN)
return 0;
/*
* Add the pkt header + CRC to the length, and work
* out how many 256-byte pages the frame would occupy.
@@ -1099,13 +1106,14 @@ dp8390_close(void *priv)
{
dp8390_t *dp8390 = (dp8390_t *) priv;
/* Make sure the platform layer is shut down. */
network_close();
if (dp8390) {
if (dp8390->mem)
free(dp8390->mem);
if (dp8390->card) {
netcard_close(dp8390->card);
}
free(dp8390);
}
}

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

@@ -0,0 +1,76 @@
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <unistd.h>
#include <fcntl.h>
#endif
#include <86box/net_event.h>
#ifndef _WIN32
static void setup_fd(int fd)
{
fcntl(fd, F_SETFD, FD_CLOEXEC);
fcntl(fd, F_SETFL, O_NONBLOCK);
}
#endif
void
net_event_init(net_evt_t *event)
{
#ifdef _WIN32
event->handle = CreateEvent(NULL, FALSE, FALSE, NULL);
#else
(void)pipe(event->fds);
setup_fd(event->fds[0]);
setup_fd(event->fds[1]);
#endif
}
void
net_event_set(net_evt_t *event)
{
#ifdef _WIN32
SetEvent(event->handle);
#else
(void)write(event->fds[1], "a", 1);
#endif
}
void
net_event_clear(net_evt_t *event)
{
#ifdef _WIN32
/* Do nothing on WIN32 since we use an auto-reset event */
#else
char dummy[1];
(void)read(event->fds[0], &dummy, sizeof(dummy));
#endif
}
void
net_event_close(net_evt_t *event)
{
#ifdef _WIN32
CloseHandle(event->handle);
#else
close(event->fds[0]);
close(event->fds[1]);
#endif
}
#ifdef _WIN32
HANDLE
net_event_get_handle(net_evt_t *event)
{
return event->handle;
}
#else
int
net_event_get_fd(net_evt_t *event)
{
return event->fds[0];
}
#endif

View File

@@ -61,6 +61,8 @@
#include <86box/pic.h>
#include <86box/random.h>
#include <86box/device.h>
#include <86box/thread.h>
#include <86box/timer.h>
#include <86box/network.h>
#include <86box/net_dp8390.h>
#include <86box/net_ne2000.h>
@@ -973,7 +975,7 @@ nic_init(const device_t *info)
dev->maclocal[5] = (mac & 0xff);
}
dev->dp8390 = device_add(&dp8390_device);
dev->dp8390 = device_add_inst(&dp8390_device, dp3890_inst++);
dev->dp8390->priv = dev;
dev->dp8390->interrupt = nic_interrupt;
@@ -1120,7 +1122,7 @@ nic_init(const device_t *info)
nic_reset(dev);
/* Attach ourselves to the network module. */
network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL, NULL);
dev->dp8390->card = network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL);
nelog(1, "%s: %s attached IO=0x%X IRQ=%d\n", dev->name,
dev->is_pci?"PCI":"ISA", dev->base_address, dev->base_irq);

View File

@@ -50,15 +50,40 @@
#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>
#define PCAP_PKT_BATCH NET_QUEUE_LEN
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 +91,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 +120,104 @@ struct pcap_if {
char *name;
char *description;
void *addresses;
unsigned int flags;
bpf_u_int32 flags;
};
struct pcap_send_queue {
u_int maxlen; /* Maximum size of the queue, in bytes. This
variable contains the size of the buffer field. */
u_int len; /* Current size of the queue, in bytes. */
char *buffer; /* Buffer containing the packets to be sent. */
};
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 pcap_send_queue pcap_send_queue;
typedef void (*pcap_handler)(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes);
#endif
typedef struct {
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;
netpkt_t pktv[PCAP_PKT_BATCH];
uint8_t mac_addr[6];
#ifdef _WIN32
struct pcap_send_queue *pcap_queue;
#endif
} net_pcap_t;
typedef struct {
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 int (*f_pcap_dispatch)(void *, int, pcap_handler callback, u_char *user);
static void *(*f_pcap_create)(const char *, char*);
static int (*f_pcap_activate)(void *);
static void *(*f_pcap_geterr)(void *);
#ifdef _WIN32
static HANDLE (*f_pcap_getevent)(void *);
static int (*f_pcap_sendqueue_queue)(void *, void *, void *);
static u_int (*f_pcap_sendqueue_transmit)(void *, void *, int sync);
static void *(*f_pcap_sendqueue_alloc)(u_int memsize);
static void (*f_pcap_sendqueue_destroy)(void *);
#else
static int (*f_pcap_get_selectable_fd)(void *);
#endif
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_dispatch", &f_pcap_dispatch },
{ "pcap_create", &f_pcap_create },
{ "pcap_activate", &f_pcap_activate },
{ "pcap_geterr", &f_pcap_geterr },
#ifdef _WIN32
{ "pcap_getevent", &f_pcap_getevent },
{ "pcap_sendqueue_queue", &f_pcap_sendqueue_queue },
{ "pcap_sendqueue_transmit", &f_pcap_sendqueue_transmit},
{ "pcap_sendqueue_alloc", &f_pcap_sendqueue_alloc },
{ "pcap_sendqueue_destroy", &f_pcap_sendqueue_destroy },
#else
{ "pcap_get_selectable_fd", &f_pcap_get_selectable_fd },
#endif
{ NULL, NULL },
};
#ifdef ENABLE_PCAP_LOG
int pcap_do_log = ENABLE_PCAP_LOG;
static void
pcap_log(const char *fmt, ...)
{
@@ -159,76 +234,121 @@ pcap_log(const char *fmt, ...)
#endif
/* Handle the receiving of frames from the channel. */
static void
poll_thread(void *arg)
net_pcap_rx_handler(uint8_t *user, const struct pcap_pkthdr *h, const uint8_t *bytes)
{
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);
/* 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);
net_pcap_t *pcap = (net_pcap_t*)user;
memcpy(pcap->pkt.data, bytes, h->caplen);
pcap->pkt.len = h->caplen;
network_rx_put_pkt(pcap->card, &pcap->pkt);
}
/* Send a packet to the Pcap interface. */
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;
struct pcap_pkthdr h;
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);
int packets = network_tx_popv(pcap->card, pcap->pktv, PCAP_PKT_BATCH);
for (int i = 0; i < packets; i++) {
h.caplen = pcap->pktv[i].len;
f_pcap_sendqueue_queue(pcap->pcap_queue, &h, pcap->pktv[i].data);
}
f_pcap_sendqueue_transmit(pcap->pcap, pcap->pcap_queue, 0);
pcap->pcap_queue->len = 0;
break;
case NET_EVENT_RX:
f_pcap_dispatch(pcap->pcap, PCAP_PKT_BATCH, net_pcap_rx_handler, (u_char *)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);
int packets = network_tx_popv(pcap->card, pcap->pktv, PCAP_PKT_BATCH);
for (int i = 0; i < packets; i++) {
net_pcap_in(pcap->pcap, pcap->pktv[i].data, pcap->pktv[i].len);
}
}
if (pfd[NET_EVENT_RX].revents & POLLIN) {
f_pcap_dispatch(pcap->pcap, PCAP_PKT_BATCH, net_pcap_rx_handler, (u_char *)pcap);
}
}
pcap_log("PCAP: polling stopped.\n");
}
#endif
/*
* Prepare the (Win)Pcap module for use.
@@ -244,18 +364,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) {
@@ -264,6 +384,9 @@ net_pcap_prepare(netdev_t *list)
}
for (dev=devlist; dev!=NULL; dev=dev->next) {
if (i >= (NET_HOST_INTF_MAX - 1))
break;
/**
* we initialize the strings to NULL first for strncpy
*/
@@ -292,141 +415,146 @@ 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;
#ifdef _WIN32
pcap->pcap_queue = f_pcap_sendqueue_alloc(PCAP_PKT_BATCH * NET_MAX_FRAME);
#endif
pcap_log("PCAP: starting thread..\n");
poll_state = thread_create_event();
poll_tid = thread_create(poll_thread, mac);
thread_wait_event(poll_state, -1);
for (int i = 0; i < PCAP_PKT_BATCH; i++) {
pcap->pktv[i].data = calloc(1, NET_MAX_FRAME);
}
pcap->pkt.data = calloc(1, NET_MAX_FRAME);
return(0);
net_event_init(&pcap->tx_event);
net_event_init(&pcap->stop_event);
pcap->poll_tid = thread_create(net_pcap_thread, pcap);
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");
for (int i = 0; i < PCAP_PKT_BATCH; i++) {
free(pcap->pktv[i].data);
}
free(pcap->pkt.data);
#ifdef _WIN32
f_pcap_sendqueue_destroy((void*)pcap->pcap_queue);
#endif
/* OK, now shut down Pcap itself. */
f_pcap_close((void*)pcap->pcap);
net_event_close(&pcap->tx_event);
net_event_close(&pcap->stop_event);
free(pcap);
}
const netdrv_t net_pcap_drv = {
&net_pcap_in_available,
&net_pcap_init,
&net_pcap_close,
NULL
};

View File

@@ -29,6 +29,7 @@
#include <stdarg.h>
#include <wchar.h>
#include <time.h>
#include <stdbool.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/io.h>
@@ -41,6 +42,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 +262,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? */
@@ -1250,6 +1254,10 @@ pcnetReceiveNoSync(void *priv, uint8_t *buf, int size)
if (!pcnetIsLinkUp(dev))
return 0;
dev->fMaybeOutOfSpace = !pcnetCanReceive(dev);
if (dev->fMaybeOutOfSpace)
return 0;
pcnetlog(1, "%s: pcnetReceiveNoSync: RX %x:%x:%x:%x:%x:%x > %x:%x:%x:%x:%x:%x len %d\n", dev->name,
buf[6], buf[7], buf[8], buf[9], buf[10], buf[11],
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
@@ -1528,7 +1536,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 +1647,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 */
@@ -2022,11 +2030,15 @@ pcnet_bcr_writew(nic_t *dev, uint16_t rap, uint16_t val)
case BCR_BSBC:
case BCR_EECAS:
case BCR_PLAT:
case BCR_MIICAS:
case BCR_MIIADDR:
dev->aBCR[rap] = val;
break;
case BCR_MIICAS:
dev->netcard->byte_period = (dev->board == DEV_AM79C973 && (val & 0x28)) ? NET_PERIOD_100M : NET_PERIOD_10M;
dev->aBCR[rap] = val;
break;
case BCR_STVAL:
val &= 0xffff;
dev->aBCR[BCR_STVAL] = val;
@@ -2088,12 +2100,13 @@ pcnet_mii_readw(nic_t *dev, uint16_t miiaddr)
| 0x0008 /* Able to do auto-negotiation. */
| 0x0004 /* Link up. */
| 0x0001; /* Extended Capability, i.e. registers 4+ valid. */
if (!dev->fLinkUp || dev->fLinkTempDown || isolate) {
if (!pcnetIsLinkUp(dev) || isolate) {
val &= ~(0x0020 | 0x0004);
dev->cLinkDownReported++;
}
if (!autoneg) {
/* Auto-negotiation disabled. */
val &= ~(0x0020 | 0x0008);
if (duplex)
val &= ~0x2800; /* Full duplex forced. */
else
@@ -2124,7 +2137,7 @@ pcnet_mii_readw(nic_t *dev, uint16_t miiaddr)
case 5:
/* Link partner ability register. */
if (dev->fLinkUp && !dev->fLinkTempDown && !isolate) {
if (pcnetIsLinkUp(dev) && !isolate) {
val = 0x8000 /* Next page bit. */
| 0x4000 /* Link partner acked us. */
| 0x0400 /* Can do flow control. */
@@ -2138,7 +2151,7 @@ pcnet_mii_readw(nic_t *dev, uint16_t miiaddr)
case 6:
/* Auto negotiation expansion register. */
if (dev->fLinkUp && !dev->fLinkTempDown && !isolate) {
if (pcnetIsLinkUp(dev) && !isolate) {
val = 0x0008 /* Link partner supports npage. */
| 0x0004 /* Enable npage words. */
| 0x0001; /* Can do N-way auto-negotiation. */
@@ -2150,7 +2163,7 @@ pcnet_mii_readw(nic_t *dev, uint16_t miiaddr)
case 18:
/* Diagnostic Register (FreeBSD pcn/ac101 driver reads this). */
if (dev->fLinkUp && !dev->fLinkTempDown && !isolate) {
if (pcnetIsLinkUp(dev) && !isolate) {
val = 0x1000 /* Receive PLL locked. */
| 0x0200; /* Signal detected. */
@@ -2188,7 +2201,7 @@ pcnet_bcr_readw(nic_t *dev, uint16_t rap)
case BCR_LED2:
case BCR_LED3:
val = dev->aBCR[rap] & ~0x8000;
if (dev->fLinkTempDown || !dev->fLinkUp) {
if (!(pcnetIsLinkUp(dev))) {
if (rap == 4)
dev->cLinkDownReported++;
val &= ~0x40;
@@ -2839,40 +2852,28 @@ pcnetCanReceive(nic_t *dev)
return rc;
}
static int
pcnetWaitReceiveAvail(void *priv)
pcnetSetLinkState(void *priv, uint32_t link_state)
{
nic_t *dev = (nic_t *) priv;
dev->fMaybeOutOfSpace = !pcnetCanReceive(dev);
return dev->fMaybeOutOfSpace;
}
static int
pcnetSetLinkState(void *priv)
{
nic_t *dev = (nic_t *) priv;
int fLinkUp;
if (dev->fLinkTempDown) {
pcnetTempLinkDown(dev);
return 1;
if (link_state & NET_LINK_TEMP_DOWN) {
pcnetTempLinkDown(dev);
return 1;
}
fLinkUp = (dev->fLinkUp && !dev->fLinkTempDown);
if (dev->fLinkUp != fLinkUp) {
dev->fLinkUp = fLinkUp;
if (fLinkUp) {
dev->fLinkTempDown = 1;
dev->cLinkDownReported = 0;
dev->aCSR[0] |= 0x8000 | 0x2000; /* ERR | CERR (this is probably wrong) */
timer_set_delay_u64(&dev->timer_restore, (dev->cMsLinkUpDelay * 1000) * TIMER_USEC);
} else {
dev->cLinkDownReported = 0;
dev->aCSR[0] |= 0x8000 | 0x2000; /* ERR | CERR (this is probably wrong) */
}
bool link_up = !(link_state & NET_LINK_DOWN);
if (dev->fLinkUp != link_up) {
dev->fLinkUp = link_up;
if (link_up) {
dev->fLinkTempDown = 1;
dev->cLinkDownReported = 0;
dev->aCSR[0] |= 0x8000 | 0x2000;
timer_set_delay_u64(&dev->timer_restore, (dev->cMsLinkUpDelay * 1000) * TIMER_USEC);
} else {
dev->cLinkDownReported = 0;
dev->aCSR[0] |= 0x8000 | 0x2000;
}
}
return 0;
@@ -3051,7 +3052,8 @@ 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, pcnetSetLinkState);
dev->netcard->byte_period = (dev->board == DEV_AM79C973) ? NET_PERIOD_100M : NET_PERIOD_10M;
timer_add(&dev->timer, pcnetPollTimer, dev, 0);
@@ -3071,8 +3073,7 @@ pcnet_close(void *priv)
pcnetlog(1, "%s: closed\n", dev->name);
/* Make sure the platform layer is shut down. */
network_close();
netcard_close(dev->netcard);
if (dev) {
free(dev);

View File

@@ -31,6 +31,8 @@
#include <86box/timer.h>
#include <86box/pit.h>
#include <86box/device.h>
#include <86box/thread.h>
#include <86box/timer.h>
#include <86box/network.h>
#include <86box/net_plip.h>
@@ -70,6 +72,7 @@ typedef struct
uint8_t *rx_pkt, rx_checksum, rx_return_state;
uint16_t rx_len, rx_ptr;
netcard_t *card;
} plip_t;
@@ -117,8 +120,6 @@ timeout_timer(void *priv)
dev->rx_pkt = NULL;
}
network_rx_pause = 0;
timer_disable(&dev->timeout_timer);
}
@@ -229,7 +230,7 @@ plip_write_data(uint8_t val, void *priv)
/* Transmit packet. */
plip_log(2, "PLIP: transmitting %d-byte packet\n", dev->tx_len);
network_tx(dev->tx_pkt, dev->tx_len);
network_tx(dev->card, dev->tx_pkt, dev->tx_len);
} else {
plip_log(1, "PLIP: checksum error: expected %02X, got %02X\n", dev->tx_checksum_calc, dev->tx_checksum);
}
@@ -381,7 +382,6 @@ plip_receive_packet(plip_t *dev)
}
if (!dev->rx_pkt || !dev->rx_len) { /* unpause RX queue if there's no packet to receive */
network_rx_pause = 0;
return;
}
@@ -432,8 +432,6 @@ plip_rx(void *priv, uint8_t *buf, int io_len)
if (!(dev->rx_pkt = malloc(io_len))) /* unlikely */
fatal("PLIP: unable to allocate rx_pkt\n");
network_rx_pause = 1; /* make sure we don't get any more packets while processing this one */
/* Copy this packet to our buffer. */
dev->rx_len = io_len;
memcpy(dev->rx_pkt, buf, dev->rx_len);
@@ -478,7 +476,7 @@ plip_net_init(const device_t *info)
}
plip_log(1, " (attached to LPT)\n");
network_attach(instance, instance->mac, plip_rx, NULL, NULL);
instance->card = network_attach(instance, instance->mac, plip_rx, NULL);
return instance;
}
@@ -487,6 +485,9 @@ plip_net_init(const device_t *info)
static void
plip_close(void *priv)
{
if (instance->card) {
netcard_close(instance->card);
}
free(priv);
}

View File

@@ -24,6 +24,7 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include <wchar.h>
#include <slirp/libslirp.h>
#define HAVE_STDARG_H
@@ -31,45 +32,44 @@
#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>
#define SLIRP_PKT_BATCH NET_QUEUE_LEN
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;
netpkt_t pkt_tx_v[SLIRP_PKT_BATCH];
#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 +101,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 +118,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 +155,121 @@ 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;
uint32_t mac_cmp32[2];
uint16_t mac_cmp16[2];
net_slirp_t *slirp = (net_slirp_t *) opaque;
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);
memcpy(slirp->pkt.data, (uint8_t*) qp, pkt_len);
slirp->pkt.len = pkt_len;
network_rx_put_pkt(slirp->card, &slirp->pkt);
/* 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);
}
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 +283,218 @@ 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:
int packets = network_tx_popv(slirp->card, slirp->pkt_tx_v, SLIRP_PKT_BATCH);
for (int i = 0; i < packets; i++) {
net_slirp_in(slirp, slirp->pkt_tx_v[i].data, slirp->pkt_tx_v[i].len);
}
break;
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);
int packets = network_tx_popv(slirp->card, slirp->pkt_tx_v, SLIRP_PKT_BATCH);
for (int i = 0; i < packets; i++) {
net_slirp_in(slirp, slirp->pkt_tx_v[i].data, slirp->pkt_tx_v[i].len);
}
}
}
slirp_log("SLiRP: polling stopped.\n");
}
#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) }; /* 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[32];
snprintf(category, sizeof(category), "SLiRP Port Forwarding #%i", card->card_num + 1);
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++;
}
for (int i = 0; i < SLIRP_PKT_BATCH; i++) {
slirp->pkt_tx_v[i].data = calloc(1, NET_MAX_FRAME);
}
slirp->pkt.data = calloc(1, NET_MAX_FRAME);
net_event_init(&slirp->tx_event);
net_event_init(&slirp->stop_event);
#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);
for (int i = 0; i < SLIRP_PKT_BATCH; i++) {
free(slirp->pkt_tx_v[i].data);
}
free(slirp->pkt.data);
free(slirp);
slirp_card_num--;
}
const netdrv_t net_slirp_drv = {
&net_slirp_in_available,
&net_slirp_init,
&net_slirp_close
};
/* Stubs to stand in for the parts of libslirp we skip compiling. */
void ncsi_input(void *slirp, const uint8_t *pkt, int pkt_len) {}

View File

@@ -58,6 +58,8 @@
#include <86box/pic.h>
#include <86box/random.h>
#include <86box/device.h>
#include <86box/timer.h>
#include <86box/thread.h>
#include <86box/network.h>
#include <86box/net_dp8390.h>
#include <86box/net_wd8003.h>
@@ -696,7 +698,7 @@ wd_init(const device_t *info)
dev->ram_addr = device_get_config_hex20("ram_addr");
}
dev->dp8390 = device_add(&dp8390_device);
dev->dp8390 = device_add_inst(&dp8390_device, dp3890_inst++);
dev->dp8390->priv = dev;
dev->dp8390->interrupt = wd_interrupt;
dp8390_set_defaults(dev->dp8390, DP8390_FLAG_CHECK_CR | DP8390_FLAG_CLEAR_IRQ);
@@ -786,7 +788,7 @@ wd_init(const device_t *info)
mem_mapping_disable(&dev->ram_mapping);
/* Attach ourselves to the network module. */
network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL, NULL);
dev->dp8390->card = network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL);
if (!(dev->board_chip & WE_ID_BUS_MCA)) {
wdlog("%s: attached IO=0x%X IRQ=%d, RAM addr=0x%06x\n", dev->name,

View File

@@ -56,6 +56,7 @@
#include <stdlib.h>
#include <wchar.h>
#include <time.h>
#include <stdbool.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
@@ -63,6 +64,7 @@
#include <86box/plat.h>
#include <86box/thread.h>
#include <86box/ui.h>
#include <86box/timer.h>
#include <86box/network.h>
#include <86box/net_3c503.h>
#include <86box/net_ne2000.h>
@@ -70,6 +72,11 @@
#include <86box/net_plip.h>
#include <86box/net_wd8003.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#endif
static const device_t net_none_device = {
.name = "None",
@@ -86,53 +93,39 @@ static const device_t net_none_device = {
};
static netcard_t net_cards[] = {
// clang-format off
{ &net_none_device, NULL },
{ &threec503_device, NULL },
{ &pcnet_am79c960_device, NULL },
{ &pcnet_am79c961_device, NULL },
{ &ne1000_device, NULL },
{ &ne2000_device, NULL },
{ &pcnet_am79c960_eb_device, NULL },
{ &rtl8019as_device, NULL },
{ &wd8003e_device, NULL },
{ &wd8003eb_device, NULL },
{ &wd8013ebt_device, NULL },
{ &plip_device, NULL },
{ &ethernext_mc_device, NULL },
{ &wd8003eta_device, NULL },
{ &wd8003ea_device, NULL },
{ &wd8013epa_device, NULL },
{ &pcnet_am79c973_device, NULL },
{ &pcnet_am79c970a_device, NULL },
{ &rtl8029as_device, NULL },
{ &pcnet_am79c960_vlb_device, NULL },
{ NULL, NULL }
// clang-format off
static const device_t *net_cards[] = {
&net_none_device,
&threec503_device,
&pcnet_am79c960_device,
&pcnet_am79c961_device,
&ne1000_device,
&ne2000_device,
&pcnet_am79c960_eb_device,
&rtl8019as_device,
&wd8003e_device,
&wd8003eb_device,
&wd8013ebt_device,
&plip_device,
&ethernext_mc_device,
&wd8003eta_device,
&wd8003ea_device,
&wd8013epa_device,
&pcnet_am79c973_device,
&pcnet_am79c970a_device,
&rtl8029as_device,
&pcnet_am79c960_vlb_device,
NULL
};
netcard_conf_t net_cards_conf[NET_CARD_MAX];
int net_card_current = 0;
/* Global variables. */
int network_type;
int network_ndev;
int network_card;
char network_host[522];
netdev_t network_devs[32];
int network_rx_pause = 0,
network_tx_pause = 0;
netdev_t network_devs[NET_HOST_INTF_MAX];
/* 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 +184,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 +204,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 +240,166 @@ network_init(void)
#endif
}
void
network_queue_init(netqueue_t *queue)
{
queue->head = queue->tail = 0;
for (int i=0; i<NET_QUEUE_LEN; i++) {
queue->packets[i].data = calloc(1, NET_MAX_FRAME);
queue->packets[i].len = 0;
}
}
static bool
network_queue_full(netqueue_t *queue)
{
return ((queue->head + 1) & NET_QUEUE_LEN_MASK) == queue->tail;
}
static bool
network_queue_empty(netqueue_t *queue)
{
return (queue->head == queue->tail);
}
static inline void
network_swap_packet(netpkt_t *pkt1, netpkt_t *pkt2)
{
netpkt_t tmp = *pkt2;
*pkt2 = *pkt1;
*pkt1 = tmp;
}
int
network_queue_put(netqueue_t *queue, uint8_t *data, int len)
{
if (len == 0 || len > NET_MAX_FRAME || network_queue_full(queue)) {
return 0;
}
netpkt_t *pkt = &queue->packets[queue->head];
memcpy(pkt->data, data, len);
pkt->len = len;
queue->head = (queue->head + 1) & NET_QUEUE_LEN_MASK;
return 1;
}
int
network_queue_put_swap(netqueue_t *queue, netpkt_t *src_pkt)
{
if (src_pkt->len == 0 || src_pkt->len > NET_MAX_FRAME || network_queue_full(queue)) {
return 0;
}
netpkt_t *dst_pkt = &queue->packets[queue->head];
network_swap_packet(src_pkt, dst_pkt);
queue->head = (queue->head + 1) & NET_QUEUE_LEN_MASK;
return 1;
}
static int
network_queue_get_swap(netqueue_t *queue, netpkt_t *dst_pkt) {
if (network_queue_empty(queue))
return 0;
netpkt_t *src_pkt = &queue->packets[queue->tail];
network_swap_packet(src_pkt, dst_pkt);
queue->tail = (queue->tail + 1) & NET_QUEUE_LEN_MASK;
return 1;
}
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];
network_swap_packet(src_pkt, dst_pkt);
dst_q->head = (dst_q->head + 1) & NET_QUEUE_LEN_MASK;
src_q->tail = (src_q->tail + 1) & NET_QUEUE_LEN_MASK;
return dst_pkt->len;
}
void
network_queue_put(int tx, void *priv, uint8_t *data, int len)
network_queue_clear(netqueue_t *queue)
{
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)
{
netpkt_t *temp;
temp = first_pkt[tx];
if (temp == NULL) {
memset(pkt, 0x00, sizeof(netpkt_t));
return;
for (int i=0; i<NET_QUEUE_LEN; i++) {
free(queue->packets[i].data);
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)
{
netpkt_t *temp;
temp = first_pkt[tx];
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;
}
}
first_pkt[tx] = temp->next;
free(temp);
if (first_pkt[tx] == NULL)
last_pkt[tx] = NULL;
}
static void
network_queue_copy(int dest, int src)
{
netpkt_t *temp, *temp2;
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;
}
static void
network_queue_clear(int tx)
{
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;
queue->tail = queue->head = 0;
}
static void
network_rx_queue(void *priv)
{
int ret = 1;
netcard_t *card = (netcard_t *)priv;
if (network_rx_pause || !thread_test_mutex(network_mutex)) {
timer_on_auto(&network_rx_queue_timer, 0.762939453125 * 2.0 * 128.0);
return;
uint32_t new_link_state = net_cards_conf[card->card_num].link_state;
if (new_link_state != card->link_state) {
if (card->set_link_state)
card->set_link_state(card->card_drv, new_link_state);
card->link_state = new_link_state;
}
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);
uint32_t rx_bytes = 0;
for (int i = 0; i < NET_QUEUE_LEN; i++) {
if (card->queued_pkt.len == 0) {
thread_wait_mutex(card->rx_mutex);
int res = network_queue_get_swap(&card->queues[NET_QUEUE_RX], &card->queued_pkt);
thread_release_mutex(card->rx_mutex);
if (!res)
break;
}
network_dump_packet(&card->queued_pkt);
int res = card->rx(card->card_drv, card->queued_pkt.data, card->queued_pkt.len);
if (!res)
break;
rx_bytes += card->queued_pkt.len;
card->queued_pkt.len = 0;
}
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;
/* Transmission. */
network_queue_copy(1, 2);
uint32_t tx_bytes = 0;
thread_wait_mutex(card->tx_mutex);
for (int i = 0; i < NET_QUEUE_LEN; i++) {
uint32_t bytes = network_queue_move(&card->queues[NET_QUEUE_TX_HOST], &card->queues[NET_QUEUE_TX_VM]);
if (!bytes)
break;
tx_bytes += bytes;
}
thread_release_mutex(card->tx_mutex);
if (tx_bytes) {
/* Notify host that a packet is available in the TX queue */
card->host_drv.notify_in(card->host_drv.priv);
}
network_wait(0);
double timer_period = card->byte_period * (rx_bytes > tx_bytes ? rx_bytes : tx_bytes);
if (timer_period < 200)
timer_period = 200;
timer_on_auto(&card->timer, timer_period);
bool activity = rx_bytes || tx_bytes;
bool led_on = card->led_timer & 0x80000000;
if ((activity && !led_on) || (card->led_timer & 0x7fffffff) >= 150000) {
ui_sb_update_icon(SB_NETWORK | card->card_num, activity);
card->led_timer = 0 | (activity << 31);
}
card->led_timer += timer_period;
}
@@ -407,51 +410,68 @@ 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, 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->set_link_state = set_link_state;
card->tx_mutex = thread_create_mutex();
card->rx_mutex = thread_create_mutex();
card->card_num = net_card_current;
card->byte_period = NET_PERIOD_10M;
/* 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, 100);
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 +479,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,87 +501,102 @@ 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 (!network_dev_available(i)) {
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);
}
int network_tx_pop(netcard_t *card, netpkt_t *out_pkt)
{
int ret = 0;
thread_wait_mutex(card->tx_mutex);
ret = network_queue_get_swap(&card->queues[NET_QUEUE_TX_HOST], out_pkt);
thread_release_mutex(card->tx_mutex);
return ret;
}
int network_tx_popv(netcard_t *card, netpkt_t *pkt_vec, int vec_size)
{
int pkt_count = 0;
netqueue_t *queue = &card->queues[NET_QUEUE_TX_HOST];
thread_wait_mutex(card->tx_mutex);
for (int i = 0; i < vec_size; i++) {
if (!network_queue_get_swap(queue, pkt_vec))
break;
pkt_count++;
pkt_vec++;
}
thread_release_mutex(card->tx_mutex);
return pkt_count;
}
int network_rx_put(netcard_t *card, uint8_t *bufp, int len)
{
int ret = 0;
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_rx_put_pkt(netcard_t *card, netpkt_t *pkt)
{
int ret = 0;
thread_wait_mutex(card->rx_mutex);
ret = network_queue_put_swap(&card->queues[NET_QUEUE_RX], pkt);
thread_release_mutex(card->rx_mutex);
return ret;
}
void
network_connect(int id, int connect)
{
if (id >= NET_CARD_MAX)
return;
if (connect) {
net_cards_conf[id].link_state &= ~NET_LINK_DOWN;
} else {
net_cards_conf[id].link_state |= NET_LINK_DOWN;
}
}
/* Actually transmit the packet. */
int
network_tx_queue_check(void)
network_is_connected(int id)
{
if ((first_pkt[1] == NULL) && (last_pkt[1] == NULL))
return 0;
if (id >= NET_CARD_MAX)
return 0;
if (network_tx_pause)
return 1;
network_queue_transmit(1);
return 1;
return !(net_cards_conf[id].link_state & NET_LINK_DOWN);
}
int
network_dev_to_id(char *devname)
{
@@ -592,18 +608,32 @@ network_dev_to_id(char *devname)
}
}
/* If no match found, assume "none". */
return(0);
return(-1);
}
/* UI */
int
network_dev_available(int id)
{
int available = (net_cards_conf[id].device_num > 0) && (net_cards_conf[id].net_type != NET_TYPE_NONE);
if ((net_cards_conf[id].net_type == NET_TYPE_PCAP && (network_dev_to_id(net_cards_conf[id].host_dev_name) <= 0)))
available = 0;
return available;
}
int
network_available(void)
{
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 |= network_dev_available(i);
}
return available;
}
@@ -611,8 +641,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 +652,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 +660,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 +670,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 +680,11 @@ network_card_get_from_internal_name(char *s)
{
int c = 0;
while (net_cards[c].device != NULL) {
if (! strcmp((char *)net_cards[c].device->internal_name, s))
while (net_cards[c] != NULL) {
if (! strcmp((char *)net_cards[c]->internal_name, s))
return(c);
c++;
}
return 0;
}
void
network_set_wait(int wait)
{
net_wait = wait;
}
int
network_get_wait(void)
{
int ret;
ret = net_wait;
return ret;
}
}

View File

@@ -90,7 +90,7 @@
#ifdef _WIN32
# define PATH_FREETYPE_DLL "freetype.dll"
#elif defined __APPLE__
# define PATH_FREETYPE_DLL "libfreetype.dylib"
# define PATH_FREETYPE_DLL "libfreetype.6.dylib"
#else
# define PATH_FREETYPE_DLL "libfreetype.so.6"
#endif

View File

@@ -309,7 +309,11 @@ if (APPLE AND CMAKE_MACOSX_BUNDLE)
install(CODE "
include(BundleUtilities)
get_filename_component(CMAKE_INSTALL_PREFIX_ABSOLUTE \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX} ABSOLUTE)
fixup_bundle(\"\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/86Box.app\" \"${QT_PLUGINS}\" \"${DIRS}\")")
fixup_bundle(\"\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/86Box.app\" \"${QT_PLUGINS}\" \"${DIRS}\")
execute_process(
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath \"@executable_path/../Frameworks/\"
\"\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/${INSTALL_RUNTIME_DIR}/86Box\")
")
endif()
if (UNIX AND NOT APPLE AND NOT HAIKU)

View File

@@ -37,6 +37,7 @@ extern uint64_t tsc;
#include <86box/mo.h>
#include <86box/plat.h>
#include <86box/machine.h>
#include <86box/thread.h>
#include <86box/network.h>
#include <86box/ui.h>
#include <86box/machine_status.h>
@@ -87,7 +88,7 @@ namespace {
PixmapSetEmptyActive zip;
PixmapSetEmptyActive mo;
PixmapSetActive hd;
PixmapSetActive net;
PixmapSetEmptyActive net;
QPixmap sound;
};
@@ -219,7 +220,9 @@ struct MachineStatus::States {
for (auto& h : hdds) {
h.pixmaps = &pixmaps.hd;
}
net.pixmaps = &pixmaps.net;
for (auto& n : net) {
n.pixmaps = &pixmaps.net;
}
}
std::array<StateEmpty, 2> cartridge;
@@ -229,7 +232,7 @@ struct MachineStatus::States {
std::array<StateEmptyActive, ZIP_NUM> zip;
std::array<StateEmptyActive, MO_NUM> mo;
std::array<StateActive, HDD_BUS_USB> hdds;
StateActive net;
std::array<StateEmptyActive, NET_CARD_MAX> net;
std::unique_ptr<ClickableLabel> sound;
std::unique_ptr<QLabel> text;
};
@@ -319,6 +322,14 @@ void MachineStatus::iterateMO(const std::function<void (int)> &cb) {
}
}
void MachineStatus::iterateNIC(const std::function<void (int)> &cb) {
for (int i = 0; i < NET_CARD_MAX; i++) {
if (network_dev_available(i)) {
cb(i);
}
}
}
static int hdd_count(int bus) {
int c = 0;
int i;
@@ -356,7 +367,10 @@ void MachineStatus::refreshIcons() {
d->hdds[i].setActive(machine_status.hdd[i].active);
}
d->net.setActive(machine_status.net.active);
for (size_t i = 0; i < NET_CARD_MAX; i++) {
d->net[i].setActive(machine_status.net[i].active);
d->net[i].setEmpty(machine_status.net[i].empty);
}
for (int i = 0; i < 2; ++i) {
d->cartridge[i].setEmpty(machine_status.cartridge[i].empty);
@@ -374,7 +388,6 @@ void MachineStatus::refresh(QStatusBar* sbar) {
int c_xta = hdd_count(HDD_BUS_XTA);
int c_ide = hdd_count(HDD_BUS_IDE);
int c_scsi = hdd_count(HDD_BUS_SCSI);
int do_net = network_available();
sbar->removeWidget(d->cassette.label.get());
for (int i = 0; i < 2; ++i) {
@@ -395,7 +408,9 @@ void MachineStatus::refresh(QStatusBar* sbar) {
for (size_t i = 0; i < HDD_BUS_USB; i++) {
sbar->removeWidget(d->hdds[i].label.get());
}
sbar->removeWidget(d->net.label.get());
for (size_t i = 0; i < NET_CARD_MAX; i++) {
sbar->removeWidget(d->net[i].label.get());
}
sbar->removeWidget(d->sound.get());
if (cassette_enable) {
@@ -502,6 +517,18 @@ void MachineStatus::refresh(QStatusBar* sbar) {
sbar->addWidget(d->mo[i].label.get());
});
iterateNIC([this, sbar](int i) {
d->net[i].label = std::make_unique<ClickableLabel>();
d->net[i].setEmpty(!network_is_connected(i));
d->net[i].setActive(false);
d->net[i].refresh();
d->net[i].label->setToolTip(MediaMenu::ptr->netMenus[i]->title());
connect((ClickableLabel*)d->net[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) {
MediaMenu::ptr->netMenus[i]->popup(pos - QPoint(0, MediaMenu::ptr->netMenus[i]->sizeHint().height()));
});
sbar->addWidget(d->net[i].label.get());
});
auto hdc_name = QString(hdc_get_internal_name(hdc_current));
if ((has_mfm || hdc_name.left(5) == QStringLiteral("st506")) && c_mfm > 0) {
d->hdds[HDD_BUS_MFM].label = std::make_unique<QLabel>();
@@ -540,13 +567,6 @@ void MachineStatus::refresh(QStatusBar* sbar) {
sbar->addWidget(d->hdds[HDD_BUS_SCSI].label.get());
}
if (do_net) {
d->net.label = std::make_unique<QLabel>();
d->net.setActive(false);
d->net.refresh();
d->net.label->setToolTip(tr("Network"));
sbar->addWidget(d->net.label.get());
}
d->sound = std::make_unique<ClickableLabel>();
d->sound->setPixmap(d->pixmaps.sound);

View File

@@ -66,6 +66,7 @@ public:
static void iterateCDROM(const std::function<void(int i)>& cb);
static void iterateZIP(const std::function<void(int i)>& cb);
static void iterateMO(const std::function<void(int i)>& cb);
static void iterateNIC(const std::function<void(int i)>& cb);
QString getMessage();
public slots:

View File

@@ -44,10 +44,14 @@ extern "C" {
#include <86box/mo.h>
#include <86box/sound.h>
#include <86box/ui.h>
#include <86box/thread.h>
#include <86box/network.h>
};
#include "qt_newfloppydialog.hpp"
#include "qt_util.hpp"
#include "qt_deviceconfig.hpp"
std::shared_ptr<MediaMenu> MediaMenu::ptr;
@@ -156,6 +160,16 @@ void MediaMenu::refresh(QMenu *parentMenu) {
moMenus[i] = menu;
moUpdateMenu(i);
});
netMenus.clear();
MachineStatus::iterateNIC([this, parentMenu](int i) {
auto *menu = parentMenu->addMenu("");
netDisconnPos = menu->children().count();
auto *action = menu->addAction(tr("&Connected"), [this, i] { network_is_connected(i) ? nicDisconnect(i) : nicConnect(i); });
action->setCheckable(true);
netMenus[i] = menu;
nicUpdateMenu(i);
});
}
void MediaMenu::cassetteNewImage() {
@@ -662,6 +676,44 @@ void MediaMenu::moUpdateMenu(int i) {
menu->setTitle(QString::asprintf(tr("MO %i (%ls): %ls").toUtf8().constData(), i + 1, busName.toStdU16String().data(), name.isEmpty() ? tr("(empty)").toStdU16String().data() : name.toStdU16String().data()));
}
void MediaMenu::nicConnect(int i) {
network_connect(i, 1);
ui_sb_update_icon_state(SB_NETWORK|i, 0);
nicUpdateMenu(i);
config_save();
}
void MediaMenu::nicDisconnect(int i) {
network_connect(i, 0);
ui_sb_update_icon_state(SB_NETWORK|i, 1);
nicUpdateMenu(i);
config_save();
}
void MediaMenu::nicUpdateMenu(int i) {
if (!netMenus.contains(i))
return;
QString netType = tr("None");
switch (net_cards_conf[i].net_type) {
case NET_TYPE_SLIRP:
netType = "SLiRP";
break;
case NET_TYPE_PCAP:
netType = "PCAP";
break;
}
QString devName = DeviceConfig::DeviceName(network_card_getdevice(net_cards_conf[i].device_num), network_card_get_internal_name(net_cards_conf[i].device_num), 1);
auto *menu = netMenus[i];
auto childs = menu->children();
auto *connectedAction = dynamic_cast<QAction*>(childs[netDisconnPos]);
connectedAction->setChecked(network_is_connected(i));
menu->setTitle(QString::asprintf(tr("NIC %02i (%ls) %ls").toUtf8().constData(), i + 1, netType.toStdU16String().data(), devName.toStdU16String().data()));
}
QString MediaMenu::getMediaOpenDirectory() {
QString openDirectory;
if (open_dir_usr_path > 0) {

View File

@@ -56,6 +56,10 @@ public:
void moEject(int i);
void moReload(int i);
void moUpdateMenu(int i);
void nicConnect(int i);
void nicDisconnect(int i);
void nicUpdateMenu(int i);
private:
QWidget* parentWidget = nullptr;
@@ -65,6 +69,7 @@ private:
QMap<int, QMenu*> cdromMenus;
QMap<int, QMenu*> zipMenus;
QMap<int, QMenu*> moMenus;
QMap<int, QMenu*> netMenus;
QString getMediaOpenDirectory();
@@ -89,5 +94,7 @@ private:
int moEjectPos;
int moReloadPos;
int netDisconnPos;
friend class MachineStatus;
};

View File

@@ -21,20 +21,29 @@ extern "C" {
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/machine.h>
#include <86box/timer.h>
#include <86box/thread.h>
#include <86box/network.h>
}
#include "qt_models_common.hpp"
#include "qt_deviceconfig.hpp"
static void enableElements(Ui::SettingsNetwork *ui) {
int netType = ui->comboBoxNetwork->currentData().toInt();
ui->comboBoxPcap->setEnabled(netType == NET_TYPE_PCAP);
void SettingsNetwork::enableElements(Ui::SettingsNetwork *ui) {
for (int i = 0; i < NET_CARD_MAX; ++i) {
auto* nic_cbox = findChild<QComboBox*>(QString("comboBoxNIC%1").arg(i+1));
auto* net_type_cbox = findChild<QComboBox*>(QString("comboBoxNet%1").arg(i+1));
auto* intf_cbox = findChild<QComboBox*>(QString("comboBoxIntf%1").arg(i+1));
auto* conf_btn = findChild<QPushButton*>(QString("pushButtonConf%1").arg(i+1));
bool adaptersEnabled = netType == NET_TYPE_SLIRP ||
(netType == NET_TYPE_PCAP && ui->comboBoxPcap->currentData().toInt() > 0);
ui->comboBoxAdapter->setEnabled(adaptersEnabled);
ui->pushButtonConfigure->setEnabled(adaptersEnabled && ui->comboBoxAdapter->currentIndex() > 0 && network_card_has_config(ui->comboBoxAdapter->currentData().toInt()));
int netType = net_type_cbox->currentData().toInt();
bool adaptersEnabled = netType == NET_TYPE_SLIRP ||
(netType == NET_TYPE_PCAP && intf_cbox->currentData().toInt() > 0);
intf_cbox->setEnabled(net_type_cbox->currentData().toInt() == NET_TYPE_PCAP);
nic_cbox->setEnabled(adaptersEnabled);
conf_btn->setEnabled(adaptersEnabled && network_card_has_config(nic_cbox->currentData().toInt()));
}
}
SettingsNetwork::SettingsNetwork(QWidget *parent) :
@@ -43,27 +52,16 @@ SettingsNetwork::SettingsNetwork(QWidget *parent) :
{
ui->setupUi(this);
auto* model = ui->comboBoxNetwork->model();
Models::AddEntry(model, tr("None"), NET_TYPE_NONE);
Models::AddEntry(model, "PCap", NET_TYPE_PCAP);
Models::AddEntry(model, "SLiRP", NET_TYPE_SLIRP);
ui->comboBoxNetwork->setCurrentIndex(network_type);
int selectedRow = 0;
model = ui->comboBoxPcap->model();
QString currentPcapDevice = network_host;
for (int c = 0; c < network_ndev; c++) {
Models::AddEntry(model, tr(network_devs[c].description), c);
if (QString(network_devs[c].device) == currentPcapDevice) {
selectedRow = c;
}
}
ui->comboBoxPcap->setCurrentIndex(-1);
ui->comboBoxPcap->setCurrentIndex(selectedRow);
onCurrentMachineChanged(machine);
enableElements(ui);
for (int i = 0; i < NET_CARD_MAX; i++) {
auto* nic_cbox = findChild<QComboBox*>(QString("comboBoxNIC%1").arg(i+1));
auto* net_type_cbox = findChild<QComboBox*>(QString("comboBoxNet%1").arg(i+1));
auto* intf_cbox = findChild<QComboBox*>(QString("comboBoxIntf%1").arg(i+1));
connect(nic_cbox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SettingsNetwork::on_comboIndexChanged);
connect(net_type_cbox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SettingsNetwork::on_comboIndexChanged);
connect(intf_cbox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SettingsNetwork::on_comboIndexChanged);
}
}
SettingsNetwork::~SettingsNetwork()
@@ -72,41 +70,79 @@ 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();
removeRows = model->rowCount();
Models::AddEntry(model, tr("None"), NET_TYPE_NONE);
Models::AddEntry(model, "SLiRP", NET_TYPE_SLIRP);
if (network_ndev > 1) {
Models::AddEntry(model, "PCap", NET_TYPE_PCAP);
}
model->removeRows(0, removeRows);
cbox->setCurrentIndex(net_cards_conf[i].net_type);
selectedRow = 0;
QString currentPcapDevice = net_cards_conf[i].host_dev_name;
cbox = findChild<QComboBox*>(QString("comboBoxIntf%1").arg(i+1));
model = cbox->model();
removeRows = model->rowCount();
for (int c = 0; c < network_ndev; c++) {
Models::AddEntry(model, tr(network_devs[c].description), c);
if (QString(network_devs[c].device) == currentPcapDevice) {
selectedRow = c;
}
}
c++;
model->removeRows(0, removeRows);
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 +150,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()), 1, 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()), 2, 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()), 3, qobject_cast<Settings*>(Settings::settings));
}
void SettingsNetwork::on_pushButtonConf4_clicked() {
DeviceConfig::ConfigureDevice(network_card_getdevice(ui->comboBoxNIC4->currentData().toInt()), 4, qobject_cast<Settings*>(Settings::settings));
}

View File

@@ -21,11 +21,13 @@ public slots:
void onCurrentMachineChanged(int machineId);
private slots:
void on_pushButtonConfigure_clicked();
void on_comboBoxAdapter_currentIndexChanged(int index);
void on_comboBoxNetwork_currentIndexChanged(int index);
void on_pushButtonConf1_clicked();
void on_pushButtonConf2_clicked();
void on_pushButtonConf3_clicked();
void on_pushButtonConf4_clicked();
void on_comboIndexChanged(int index);
void on_comboBoxPcap_currentIndexChanged(int index);
void enableElements(Ui::SettingsNetwork *ui);
private:
Ui::SettingsNetwork *ui;

View File

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

View File

@@ -50,6 +50,8 @@ extern "C" {
#include <86box/zip.h>
#include <86box/mo.h>
#include <86box/hdd.h>
#include <86box/thread.h>
#include <86box/network.h>
#include <86box/machine_status.h>
void
@@ -213,6 +215,7 @@ ui_sb_update_icon_state(int tag, int state) {
case SB_HDD:
break;
case SB_NETWORK:
machine_status.net[item].empty = state > 0 ? true : false;
break;
case SB_SOUND:
break;
@@ -246,7 +249,7 @@ ui_sb_update_icon(int tag, int active) {
machine_status.hdd[item].active = active > 0 ? true : false;
break;
case SB_NETWORK:
machine_status.net.active = active > 0 ? true : false;
machine_status.net[item].active = active > 0 ? true : false;
break;
case SB_SOUND:
break;

View File

@@ -33,6 +33,7 @@
<file>win/icons/mo_empty_active.ico</file>
<file>win/icons/network.ico</file>
<file>win/icons/network_active.ico</file>
<file>win/icons/network_empty.ico</file>
<file>win/icons/other_peripherals.ico</file>
<file>win/icons/other_removable_devices.ico</file>
<file>win/icons/ports.ico</file>

View File

@@ -664,7 +664,7 @@ NETOBJ := network.o \
net_dp8390.o \
net_3c503.o net_ne2000.o \
net_pcnet.o net_wd8003.o \
net_plip.o
net_plip.o net_event.o
PRINTOBJ := png.o prt_cpmap.o \
prt_escp.o prt_text.o prt_ps.o
@@ -778,12 +778,12 @@ OBJ += $(EXOBJ)
endif
ifeq ($(OPENAL), y)
LIBS := -mwindows -lopenal -lcomctl32 -lSDL2 -limagehlp -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid
LIBS := -mwindows -lopenal -lcomctl32 -lSDL2 -limagehlp -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid -lws2_32
else
ifeq ($(FAUDIO), y)
LIBS := -mwindows -lfaudio -lcomctl32 -lSDL2 -limagehlp -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid
LIBS := -mwindows -lfaudio -lcomctl32 -lSDL2 -limagehlp -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid -lws2_32
else
LIBS := -mwindows -lcomctl32 -lSDL2 -limagehlp -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid
LIBS := -mwindows -lcomctl32 -lSDL2 -limagehlp -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid -lws2_32
endif
endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@@ -60,6 +60,7 @@
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/fdc_ext.h>
#include <86box/thread.h>
#include <86box/network.h>
#include <86box/sound.h>
#include <86box/midi.h>
@@ -98,7 +99,7 @@ static int temp_float, temp_fm_driver;
/* Network category */
static int temp_net_type, temp_net_card;
static char temp_pcap_dev[522];
static char temp_pcap_dev[128];
/* Ports category */
static int temp_lpt_devices[PARALLEL_MAX];
@@ -339,13 +340,13 @@ win_settings_init(void)
temp_fm_driver = fm_driver;
/* Network category */
temp_net_type = network_type;
temp_net_type = net_cards_conf[0].net_type;
memset(temp_pcap_dev, 0, sizeof(temp_pcap_dev));
#ifdef ENABLE_SETTINGS_LOG
assert(sizeof(temp_pcap_dev) == sizeof(network_host));
assert(sizeof(temp_pcap_dev) == sizeof(net_cards_conf[0].host_dev_name));
#endif
memcpy(temp_pcap_dev, network_host, sizeof(network_host));
temp_net_card = network_card;
memcpy(temp_pcap_dev, net_cards_conf[0].host_dev_name, sizeof(net_cards_conf[0].host_dev_name));
temp_net_card = net_cards_conf[0].device_num;
/* Ports category */
for (i = 0; i < PARALLEL_MAX; i++) {
@@ -465,9 +466,9 @@ win_settings_changed(void)
i = i || (fm_driver != temp_fm_driver);
/* Network category */
i = i || (network_type != temp_net_type);
i = i || strcmp(temp_pcap_dev, network_host);
i = i || (network_card != temp_net_card);
i = i || (net_cards_conf[i].net_type != temp_net_type);
i = i || strcmp(temp_pcap_dev, net_cards_conf[0].host_dev_name);
i = i || (net_cards_conf[0].device_num != temp_net_card);
/* Ports category */
for (j = 0; j < PARALLEL_MAX; j++) {
@@ -557,10 +558,10 @@ win_settings_save(void)
fm_driver = temp_fm_driver;
/* Network category */
network_type = temp_net_type;
memset(network_host, '\0', sizeof(network_host));
strcpy(network_host, temp_pcap_dev);
network_card = temp_net_card;
net_cards_conf[i].net_type = temp_net_type;
memset(net_cards_conf[0].host_dev_name, '\0', sizeof(net_cards_conf[0].host_dev_name));
strcpy(net_cards_conf[0].host_dev_name, temp_pcap_dev);
net_cards_conf[0].device_num = temp_net_card;
/* Ports category */
for (i = 0; i < PARALLEL_MAX; i++) {
@@ -1813,8 +1814,8 @@ win_settings_network_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam)
lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR));
settings_add_string(hdlg, IDC_COMBO_NET_TYPE, (LPARAM) L"None");
settings_add_string(hdlg, IDC_COMBO_NET_TYPE, (LPARAM) L"PCap");
settings_add_string(hdlg, IDC_COMBO_NET_TYPE, (LPARAM) L"SLiRP");
settings_add_string(hdlg, IDC_COMBO_NET_TYPE, (LPARAM) L"PCap");
settings_set_cur_sel(hdlg, IDC_COMBO_NET_TYPE, temp_net_type);
settings_enable_window(hdlg, IDC_COMBO_PCAP, temp_net_type == NET_TYPE_PCAP);

View File

@@ -47,6 +47,7 @@
#include <86box/mo.h>
#include <86box/cdrom_image.h>
#include <86box/scsi_disk.h>
#include <86box/thread.h>
#include <86box/network.h>
#include <86box/video.h>
#include <86box/sound.h>