network: Add null network driver and make it the default mode
This commit is contained in:
@@ -48,7 +48,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
/* Network provider types. */
|
||||
#define NET_TYPE_NONE 0 /* networking disabled */
|
||||
#define NET_TYPE_NONE 0 /* use the null network driver */
|
||||
#define NET_TYPE_SLIRP 1 /* use the SLiRP port forwarder */
|
||||
#define NET_TYPE_PCAP 2 /* use the (Win)Pcap API */
|
||||
#define NET_TYPE_VDE 3 /* use the VDE plug API */
|
||||
@@ -57,6 +57,7 @@
|
||||
/* Queue size must be a power of 2 */
|
||||
#define NET_QUEUE_LEN 16
|
||||
#define NET_QUEUE_LEN_MASK (NET_QUEUE_LEN - 1)
|
||||
#define NET_QUEUE_COUNT 3
|
||||
#define NET_CARD_MAX 4
|
||||
#define NET_HOST_INTF_MAX 64
|
||||
|
||||
@@ -125,6 +126,7 @@ typedef struct netdrv_t {
|
||||
extern const netdrv_t net_pcap_drv;
|
||||
extern const netdrv_t net_slirp_drv;
|
||||
extern const netdrv_t net_vde_drv;
|
||||
extern const netdrv_t net_null_drv;
|
||||
|
||||
struct _netcard_t {
|
||||
const device_t *device;
|
||||
@@ -132,7 +134,7 @@ struct _netcard_t {
|
||||
struct netdrv_t host_drv;
|
||||
NETRXCB rx;
|
||||
NETSETLINKSTATE set_link_state;
|
||||
netqueue_t queues[3];
|
||||
netqueue_t queues[NET_QUEUE_COUNT];
|
||||
netpkt_t queued_pkt;
|
||||
mutex_t *tx_mutex;
|
||||
mutex_t *rx_mutex;
|
||||
|
@@ -14,7 +14,7 @@
|
||||
#
|
||||
set(net_sources)
|
||||
list(APPEND net_sources network.c net_pcap.c net_slirp.c net_dp8390.c net_3c501.c
|
||||
net_3c503.c net_ne2000.c net_pcnet.c net_wd8003.c net_plip.c net_event.c)
|
||||
net_3c503.c net_ne2000.c net_pcnet.c net_wd8003.c net_plip.c net_event.c net_null.c)
|
||||
|
||||
option(SLIRP_EXTERNAL "Link against the system-provided libslirp library" OFF)
|
||||
mark_as_advanced(SLIRP_EXTERNAL)
|
||||
|
224
src/network/net_null.c
Normal file
224
src/network/net_null.c
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Null network driver
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: cold-brewed
|
||||
*
|
||||
* Copyright 2023 The 86Box development team
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#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>
|
||||
#endif
|
||||
|
||||
#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_event.h>
|
||||
|
||||
enum {
|
||||
NET_EVENT_STOP = 0,
|
||||
NET_EVENT_TX,
|
||||
NET_EVENT_RX,
|
||||
NET_EVENT_MAX
|
||||
};
|
||||
|
||||
/* Special define for the windows portion. Because we are not interested
|
||||
* in NET_EVENT_RX for the null driver, we only need to poll up to
|
||||
* NET_EVENT_TX. NET_EVENT_RX gives us a different NET_EVENT_MAX
|
||||
* excluding NET_EVENT_RX. */
|
||||
#define NET_EVENT_TX_MAX NET_EVENT_RX
|
||||
|
||||
#define NULL_PKT_BATCH NET_QUEUE_LEN
|
||||
|
||||
typedef struct {
|
||||
uint8_t mac_addr[6];
|
||||
netcard_t *card;
|
||||
thread_t *poll_tid;
|
||||
net_evt_t tx_event;
|
||||
net_evt_t stop_event;
|
||||
netpkt_t pkt;
|
||||
netpkt_t pktv[NULL_PKT_BATCH];
|
||||
} net_null_t;
|
||||
|
||||
#ifdef ENABLE_NET_NULL_LOG
|
||||
int net_null_do_log = ENABLE_NET_NULL_LOG;
|
||||
|
||||
static void
|
||||
net_null_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (net_null_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define net_null_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
static void
|
||||
net_null_thread(void *priv)
|
||||
{
|
||||
net_null_t *net_null = (net_null_t *) priv;
|
||||
|
||||
net_null_log("Null Network: polling started.\n");
|
||||
|
||||
HANDLE events[NET_EVENT_TX_MAX];
|
||||
events[NET_EVENT_STOP] = net_event_get_handle(&net_null->stop_event);
|
||||
events[NET_EVENT_TX] = net_event_get_handle(&net_null->tx_event);
|
||||
|
||||
bool run = true;
|
||||
|
||||
while (run) {
|
||||
int ret = WaitForMultipleObjects(NET_EVENT_TX_MAX, events, FALSE, INFINITE);
|
||||
|
||||
switch (ret - WAIT_OBJECT_0) {
|
||||
case NET_EVENT_STOP:
|
||||
net_event_clear(&net_null->stop_event);
|
||||
run = false;
|
||||
break;
|
||||
|
||||
case NET_EVENT_TX:
|
||||
net_event_clear(&net_null->tx_event);
|
||||
int packets = network_tx_popv(net_null->card, net_null->pktv, NULL_PKT_BATCH);
|
||||
for (int i = 0; i < packets; i++) {
|
||||
net_null_log("Null Network: Ignoring TX packet (%d bytes)\n", net_null->pktv[i].len);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
net_null_log("Null Network: Unknown event.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
net_null_log("Null Network: polling stopped.\n");
|
||||
}
|
||||
#else
|
||||
static void
|
||||
net_null_thread(void *priv)
|
||||
{
|
||||
net_null_t *net_null = (net_null_t *) priv;
|
||||
|
||||
net_null_log("Null Network: polling started.\n");
|
||||
|
||||
struct pollfd pfd[NET_EVENT_MAX];
|
||||
pfd[NET_EVENT_STOP].fd = net_event_get_fd(&net_null->stop_event);
|
||||
pfd[NET_EVENT_STOP].events = POLLIN | POLLPRI;
|
||||
|
||||
pfd[NET_EVENT_TX].fd = net_event_get_fd(&net_null->tx_event);
|
||||
pfd[NET_EVENT_TX].events = POLLIN | POLLPRI;
|
||||
|
||||
while (1) {
|
||||
poll(pfd, NET_EVENT_MAX, -1);
|
||||
|
||||
if (pfd[NET_EVENT_STOP].revents & POLLIN) {
|
||||
net_event_clear(&net_null->stop_event);
|
||||
break;
|
||||
}
|
||||
|
||||
if (pfd[NET_EVENT_TX].revents & POLLIN) {
|
||||
net_event_clear(&net_null->tx_event);
|
||||
|
||||
int packets = network_tx_popv(net_null->card, net_null->pktv, NULL_PKT_BATCH);
|
||||
for (int i = 0; i < packets; i++) {
|
||||
net_null_log("Null Network: Ignoring TX packet (%d bytes)\n", net_null->pktv[i].len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
net_null_log("Null Network: polling stopped.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
void *
|
||||
net_null_init(const netcard_t *card, const uint8_t *mac_addr, void *priv)
|
||||
{
|
||||
net_null_log("Null Network: Init\n");
|
||||
|
||||
net_null_t *net_null = calloc(1, sizeof(net_null_t));
|
||||
net_null->card = (netcard_t *) card;
|
||||
memcpy(net_null->mac_addr, mac_addr, sizeof(net_null->mac_addr));
|
||||
|
||||
for (int i = 0; i < NULL_PKT_BATCH; i++) {
|
||||
net_null->pktv[i].data = calloc(1, NET_MAX_FRAME);
|
||||
}
|
||||
net_null->pkt.data = calloc(1, NET_MAX_FRAME);
|
||||
|
||||
net_event_init(&net_null->tx_event);
|
||||
net_event_init(&net_null->stop_event);
|
||||
net_null->poll_tid = thread_create(net_null_thread, net_null);
|
||||
|
||||
return net_null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
net_null_in_available(void *priv)
|
||||
{
|
||||
net_null_t *net_null = (net_null_t *) priv;
|
||||
net_event_set(&net_null->tx_event);
|
||||
}
|
||||
|
||||
void
|
||||
net_null_close(void *priv)
|
||||
{
|
||||
if (!priv)
|
||||
return;
|
||||
|
||||
net_null_t *net_null = (net_null_t *) priv;
|
||||
|
||||
net_null_log("Null Network: closing.\n");
|
||||
|
||||
/* Tell the thread to terminate. */
|
||||
net_event_set(&net_null->stop_event);
|
||||
|
||||
/* Wait for the thread to finish. */
|
||||
net_null_log("Null Network: waiting for thread to end...\n");
|
||||
thread_wait(net_null->poll_tid);
|
||||
net_null_log("Null Network: thread ended\n");
|
||||
|
||||
for (int i = 0; i < NULL_PKT_BATCH; i++) {
|
||||
free(net_null->pktv[i].data);
|
||||
}
|
||||
free(net_null->pkt.data);
|
||||
|
||||
net_event_close(&net_null->tx_event);
|
||||
net_event_close(&net_null->stop_event);
|
||||
|
||||
free(net_null);
|
||||
}
|
||||
|
||||
const netdrv_t net_null_drv = {
|
||||
&net_null_in_available,
|
||||
&net_null_init,
|
||||
&net_null_close,
|
||||
NULL
|
||||
};
|
@@ -442,13 +442,12 @@ network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETSETLINKSTATE set_lin
|
||||
card->card_num = net_card_current;
|
||||
card->byte_period = NET_PERIOD_10M;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int i = 0; i < NET_QUEUE_COUNT; i++) {
|
||||
network_queue_init(&card->queues[i]);
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -463,18 +462,45 @@ network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETSETLINKSTATE set_lin
|
||||
card->host_drv.priv = card->host_drv.init(card, mac, net_cards_conf[net_card_current].host_dev_name);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
card->host_drv.priv = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
// Use null driver on:
|
||||
// * No specific driver selected (card->host_drv.priv is set to null above)
|
||||
// * Failure to init a specific driver (in which case card->host_drv.priv is null)
|
||||
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]);
|
||||
|
||||
if(net_cards_conf[net_card_current].net_type != NET_TYPE_NONE) {
|
||||
// We're here because of a failure
|
||||
// Placeholder to display a msgbox about falling back to null
|
||||
ui_msgbox(MBX_ERROR | MBX_ANSI, "Network driver initialization failed. Falling back to NULL driver.");
|
||||
}
|
||||
|
||||
// Init null driver
|
||||
card->host_drv = net_null_drv;
|
||||
card->host_drv.priv = card->host_drv.init(card, mac, NULL);
|
||||
// Set link state to disconnected by default
|
||||
network_connect(card->card_num, 0);
|
||||
ui_sb_update_icon_state(SB_NETWORK | card->card_num, 1);
|
||||
|
||||
// If null fails, something is very wrong
|
||||
// Clean up and fatal
|
||||
if(!card->host_drv.priv) {
|
||||
thread_close_mutex(card->tx_mutex);
|
||||
thread_close_mutex(card->rx_mutex);
|
||||
for (int i = 0; i < NET_QUEUE_COUNT; i++) {
|
||||
network_queue_clear(&card->queues[i]);
|
||||
}
|
||||
|
||||
free(card->queued_pkt.data);
|
||||
free(card);
|
||||
// Placeholder - insert the error message
|
||||
fatal("Error initializing the network device: Null driver initialization failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free(card->queued_pkt.data);
|
||||
free(card);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
timer_add(&card->timer, network_rx_queue, card, 0);
|
||||
@@ -491,7 +517,7 @@ netcard_close(netcard_t *card)
|
||||
|
||||
thread_close_mutex(card->tx_mutex);
|
||||
thread_close_mutex(card->rx_mutex);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int i = 0; i < NET_QUEUE_COUNT; i++) {
|
||||
network_queue_clear(&card->queues[i]);
|
||||
}
|
||||
|
||||
@@ -641,7 +667,7 @@ network_dev_to_id(char *devname)
|
||||
int
|
||||
network_dev_available(int id)
|
||||
{
|
||||
int available = (net_cards_conf[id].device_num > 0) && (net_cards_conf[id].net_type != NET_TYPE_NONE);
|
||||
int available = (net_cards_conf[id].device_num > 0);
|
||||
|
||||
if ((net_cards_conf[id].net_type == NET_TYPE_PCAP && (network_dev_to_id(net_cards_conf[id].host_dev_name) <= 0)))
|
||||
available = 0;
|
||||
|
@@ -849,7 +849,7 @@ MediaMenu::nicUpdateMenu(int i)
|
||||
if (!netMenus.contains(i))
|
||||
return;
|
||||
|
||||
QString netType = tr("None");
|
||||
QString netType = tr("Null Driver");
|
||||
switch (net_cards_conf[i].net_type) {
|
||||
case NET_TYPE_SLIRP:
|
||||
netType = "SLiRP";
|
||||
|
@@ -40,9 +40,10 @@ SettingsNetwork::enableElements(Ui::SettingsNetwork *ui)
|
||||
auto *socket_line = findChild<QLineEdit *>(QString("socketVDENIC%1").arg(i + 1));
|
||||
|
||||
int netType = net_type_cbox->currentData().toInt();
|
||||
bool adaptersEnabled = netType == NET_TYPE_SLIRP
|
||||
|| NET_TYPE_VDE
|
||||
|| (netType == NET_TYPE_PCAP && intf_cbox->currentData().toInt() > 0);
|
||||
bool adaptersEnabled = netType == NET_TYPE_NONE
|
||||
|| netType == NET_TYPE_SLIRP
|
||||
|| netType == NET_TYPE_VDE
|
||||
|| (netType == NET_TYPE_PCAP && intf_cbox->currentData().toInt() > 0);
|
||||
|
||||
intf_cbox->setEnabled(net_type_cbox->currentData().toInt() == NET_TYPE_PCAP);
|
||||
nic_cbox->setEnabled(adaptersEnabled);
|
||||
@@ -133,7 +134,7 @@ SettingsNetwork::onCurrentMachineChanged(int machineId)
|
||||
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, tr("Null Driver"), NET_TYPE_NONE);
|
||||
Models::AddEntry(model, "SLiRP", NET_TYPE_SLIRP);
|
||||
|
||||
if (network_ndev > 1) {
|
||||
|
@@ -408,7 +408,7 @@ BEGIN
|
||||
CFG_HMARGIN + (CFG_PANE_LTEXT_PRI_WIDTH * 2) + 20, CFG_VMARGIN, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT
|
||||
|
||||
COMBOBOX IDC_COMBO_NET1_TYPE,
|
||||
CFG_HMARGIN, 28, 32, CFG_COMBO_HEIGHT,
|
||||
CFG_HMARGIN, 28, 48, CFG_COMBO_HEIGHT,
|
||||
CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
|
||||
COMBOBOX IDC_COMBO_PCAP1,
|
||||
@@ -422,7 +422,7 @@ BEGIN
|
||||
CFG_HMARGIN + (CFG_PANE_LTEXT_PRI_WIDTH * 3) + 50, 27, CFG_BTN_WIDTH, CFG_BTN_HEIGHT
|
||||
|
||||
COMBOBOX IDC_COMBO_NET2_TYPE,
|
||||
CFG_HMARGIN, 49, 32, CFG_COMBO_HEIGHT,
|
||||
CFG_HMARGIN, 49, 48, CFG_COMBO_HEIGHT,
|
||||
CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
|
||||
COMBOBOX IDC_COMBO_PCAP2,
|
||||
@@ -436,7 +436,7 @@ BEGIN
|
||||
CFG_HMARGIN + (CFG_PANE_LTEXT_PRI_WIDTH * 3) + 50, 48, CFG_BTN_WIDTH, CFG_BTN_HEIGHT
|
||||
|
||||
COMBOBOX IDC_COMBO_NET3_TYPE,
|
||||
CFG_HMARGIN, 70, 32, CFG_COMBO_HEIGHT,
|
||||
CFG_HMARGIN, 70, 48, CFG_COMBO_HEIGHT,
|
||||
CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
|
||||
COMBOBOX IDC_COMBO_PCAP3,
|
||||
@@ -450,7 +450,7 @@ BEGIN
|
||||
CFG_HMARGIN + (CFG_PANE_LTEXT_PRI_WIDTH * 3) + 50, 69, CFG_BTN_WIDTH, CFG_BTN_HEIGHT
|
||||
|
||||
COMBOBOX IDC_COMBO_NET4_TYPE,
|
||||
CFG_HMARGIN, 91, 32, CFG_COMBO_HEIGHT,
|
||||
CFG_HMARGIN, 91, 48, CFG_COMBO_HEIGHT,
|
||||
CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
|
||||
COMBOBOX IDC_COMBO_PCAP4,
|
||||
|
@@ -2062,7 +2062,7 @@ win_settings_network_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR));
|
||||
|
||||
for (uint8_t i = 0; i < NET_CARD_MAX; i++) {
|
||||
settings_add_string(hdlg, IDC_COMBO_NET1_TYPE + i, (LPARAM) L"None");
|
||||
settings_add_string(hdlg, IDC_COMBO_NET1_TYPE + i, (LPARAM) L"Null Driver");
|
||||
settings_add_string(hdlg, IDC_COMBO_NET1_TYPE + i, (LPARAM) L"SLiRP");
|
||||
settings_add_string(hdlg, IDC_COMBO_NET1_TYPE + i, (LPARAM) L"PCap");
|
||||
settings_set_cur_sel(hdlg, IDC_COMBO_NET1_TYPE + i, temp_net_type[i]);
|
||||
|
Reference in New Issue
Block a user