networking: add Linux-specific TAP mode to network interface
This addition was motivated by my lack of knowledge of VDE and my familiarity with the Linux networking stack. The driver automatically manages the creation of TAP devices and their association with bridges, such that configurations which specify the same bridge will be connected together. It also automatically handles the creation of bridge devices for convenience's sake.
This commit is contained in:
@@ -660,6 +660,8 @@ load_network(void)
|
||||
nc->net_type = NET_TYPE_SLIRP;
|
||||
else if (!strcmp(p, "vde") || !strcmp(p, "2"))
|
||||
nc->net_type = NET_TYPE_VDE;
|
||||
else if (!strcmp(p, "tap") || !strcmp(p, "3"))
|
||||
nc->net_type = NET_TYPE_TAP;
|
||||
else
|
||||
nc->net_type = NET_TYPE_NONE;
|
||||
} else
|
||||
@@ -706,11 +708,12 @@ load_network(void)
|
||||
nc->net_type = NET_TYPE_SLIRP;
|
||||
else if (!strcmp(p, "vde") || !strcmp(p, "2"))
|
||||
nc->net_type = NET_TYPE_VDE;
|
||||
else if (!strcmp(p, "tap") || !strcmp(p, "3"))
|
||||
nc->net_type = NET_TYPE_TAP;
|
||||
else
|
||||
nc->net_type = NET_TYPE_NONE;
|
||||
} else
|
||||
nc->net_type = NET_TYPE_NONE;
|
||||
|
||||
sprintf(temp, "net_%02i_host_device", c + 1);
|
||||
p = ini_section_get_string(cat, temp, NULL);
|
||||
if (p != NULL) {
|
||||
@@ -2309,7 +2312,9 @@ save_network(void)
|
||||
case NET_TYPE_VDE:
|
||||
ini_section_set_string(cat, temp, "vde");
|
||||
break;
|
||||
|
||||
case NET_TYPE_TAP:
|
||||
ini_section_set_string(cat, temp, "tap");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
#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 */
|
||||
#define NET_TYPE_TAP 4 /* use a linux TAP device */
|
||||
|
||||
#define NET_MAX_FRAME 1518
|
||||
/* Queue size must be a power of 2 */
|
||||
@@ -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_tap_drv;
|
||||
extern const netdrv_t net_null_drv;
|
||||
|
||||
struct _netcard_t {
|
||||
@@ -154,10 +156,11 @@ typedef struct {
|
||||
int has_slirp;
|
||||
int has_pcap;
|
||||
int has_vde;
|
||||
int has_tap;
|
||||
} network_devmap_t;
|
||||
|
||||
|
||||
#define HAS_NOSLIRP_NET(x) (x.has_pcap || x.has_vde)
|
||||
#define HAS_NOSLIRP_NET(x) (x.has_pcap || x.has_vde || x.has_tap)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -67,5 +67,14 @@ if (UNIX)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
if (UNIX AND NOT APPLE) # Support for TAP on Linux and BSD, supposedly.
|
||||
find_path(HAS_TAP "linux/if_tun.h" PATHS ${TAP_INCLUDE_DIR} "/usr/include /usr/local/include" "/opt/homebrew/include" )
|
||||
if(HAS_TAP)
|
||||
add_compile_definitions(HAS_TAP)
|
||||
list(APPEND net_sources net_tap.c)
|
||||
else()
|
||||
message(WARNING "TAP support not available. Are you on some BSD?")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(net OBJECT ${net_sources})
|
||||
|
||||
353
src/network/net_tap.c
Normal file
353
src/network/net_tap.c
Normal file
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Linux TAP network interface for 86box.
|
||||
*
|
||||
* This file was created by looking at the VDE network backend
|
||||
* as a reference, credit to jguillaumes.
|
||||
*
|
||||
* Authors: Doug Johnson <dougvj@gmail.com>
|
||||
*
|
||||
*
|
||||
* Copyright 2023 Doug Johnson
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the entire
|
||||
* above notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names
|
||||
* of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
# error TAP networking is only supported on Linux
|
||||
#endif
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#include <stdbool.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/sockios.h>
|
||||
|
||||
#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>
|
||||
|
||||
typedef struct net_tap_t {
|
||||
int fd; // tap device file descriptor
|
||||
netcard_t *card;
|
||||
thread_t *poll_tid;
|
||||
net_evt_t tx_event;
|
||||
net_evt_t stop_event;
|
||||
netpkt_t pkt_rx;
|
||||
netpkt_t pkts_tx[NET_QUEUE_LEN];
|
||||
} net_tap_t;
|
||||
|
||||
#ifdef ENABLE_TAP_LOG
|
||||
int tap_do_log = ENABLE_TAP_LOG;
|
||||
|
||||
|
||||
static void tap_logv(const char *fmt, va_list ap)
|
||||
{
|
||||
if (tap_do_log) {
|
||||
pclog_ex(fmt, ap);
|
||||
}
|
||||
}
|
||||
|
||||
static void tap_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
if (tap_do_log) {
|
||||
va_start(ap, fmt);
|
||||
tap_logv(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#else
|
||||
# define tap_log(...) \
|
||||
do { \
|
||||
} while (0)
|
||||
# define tap_logv(...) \
|
||||
do { \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
static void net_tap_thread(void *priv) {
|
||||
enum {
|
||||
NET_EVENT_STOP = 0,
|
||||
NET_EVENT_TX,
|
||||
NET_EVENT_RX,
|
||||
NET_EVENT_TAP,
|
||||
NET_EVENT_MAX,
|
||||
};
|
||||
net_tap_t *tap = priv;
|
||||
tap_log("TAP: poll thread started.\n");
|
||||
struct pollfd pfd[NET_EVENT_MAX];
|
||||
pfd[NET_EVENT_STOP].fd = net_event_get_fd(&tap->stop_event);
|
||||
pfd[NET_EVENT_STOP].events = POLLIN | POLLPRI;
|
||||
|
||||
pfd[NET_EVENT_TX].fd = net_event_get_fd(&tap->tx_event);
|
||||
pfd[NET_EVENT_TX].events = POLLIN | POLLPRI;
|
||||
|
||||
pfd[NET_EVENT_RX].fd = tap->fd;
|
||||
pfd[NET_EVENT_RX].events = POLLIN | POLLPRI;
|
||||
|
||||
pfd[NET_EVENT_TAP].fd = tap->fd;
|
||||
pfd[NET_EVENT_TAP].events = POLLERR | POLLHUP | POLLPRI;
|
||||
fcntl(tap->fd, F_SETFL, O_NONBLOCK);
|
||||
while(1) {
|
||||
ssize_t ret = poll(pfd, NET_EVENT_MAX, -1);
|
||||
if (ret < 0) {
|
||||
tap_log("TAP: poll error: %s\n", strerror(errno));
|
||||
net_event_set(&tap->stop_event);
|
||||
break;
|
||||
}
|
||||
if (pfd[NET_EVENT_TAP].revents) {
|
||||
tap_log("TAP: tap close/error event received.\n");
|
||||
net_event_set(&tap->stop_event);
|
||||
}
|
||||
if (pfd[NET_EVENT_TX].revents & POLLIN) {
|
||||
net_event_clear(&tap->tx_event);
|
||||
int packets = network_tx_popv(tap->card, tap->pkts_tx,
|
||||
NET_QUEUE_LEN);
|
||||
for(int i = 0; i < packets; i++) {
|
||||
netpkt_t *pkt = &tap->pkts_tx[i];
|
||||
ssize_t ret = write(tap->fd, pkt->data, pkt->len);
|
||||
if (ret < 0) {
|
||||
tap_log("TAP: write error: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pfd[NET_EVENT_RX].revents & POLLIN) {
|
||||
ssize_t len = read(tap->fd, tap->pkt_rx.data, NET_MAX_FRAME);
|
||||
if (len < 0) {
|
||||
tap_log("TAP: read error: %s\n", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
tap->pkt_rx.len = len;
|
||||
network_rx_put_pkt(tap->card, &tap->pkt_rx);
|
||||
}
|
||||
if (pfd[NET_EVENT_STOP].revents & POLLIN) {
|
||||
net_event_clear(&tap->stop_event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void net_tap_close(void *priv)
|
||||
{
|
||||
if (!priv) {
|
||||
return;
|
||||
}
|
||||
net_tap_t *tap = priv;
|
||||
tap_log("TAP: closing.\n");
|
||||
net_event_set(&tap->stop_event);
|
||||
tap_log("TAP: waiting for poll thread to exit.\n");
|
||||
thread_wait(tap->poll_tid);
|
||||
tap_log("TAP: poll thread exited.\n");
|
||||
for(int i = 0; i < NET_QUEUE_LEN; i++) {
|
||||
free(tap->pkts_tx[i].data);
|
||||
}
|
||||
free(tap->pkt_rx.data);
|
||||
if (tap->fd >= 0) {
|
||||
close(tap->fd);
|
||||
}
|
||||
free(tap);
|
||||
}
|
||||
|
||||
void net_tap_error(char *errbuf, const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vsnprintf(errbuf, NET_DRV_ERRBUF_SIZE, format, ap);
|
||||
tap_log("TAP: %s", errbuf);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
// Error handling macro for the many ioctl calls we use in net_tap_alloc
|
||||
#define ioctl_or_fail(fd, request, argp) \
|
||||
do { \
|
||||
if ((err = ioctl(fd, request, argp)) < 0) { \
|
||||
tap_log("TAP: ioctl " #request " error: %s\n", strerror(errno)); \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Returns -ERRNO so we can get an idea what's wrong
|
||||
int net_tap_alloc(const uint8_t *mac_addr, const char* bridge_dev)
|
||||
{
|
||||
int fd;
|
||||
struct ifreq ifr = {0};
|
||||
if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
|
||||
tap_log("TAP: open error: %s\n", strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
int err;
|
||||
if ((err = ioctl(fd, TUNSETIFF, &ifr)) < 0) {
|
||||
tap_log("TAP: ioctl TUNSETIFF error: %s\n", strerror(errno));
|
||||
close(fd);
|
||||
return -errno;
|
||||
}
|
||||
// Create a socket for ioctl operations
|
||||
int sock;
|
||||
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
tap_log("TAP: socket error: %s\n", strerror(errno));
|
||||
close(fd);
|
||||
return -errno;
|
||||
}
|
||||
// Bring the interface up
|
||||
tap_log("TAP: Bringing interface '%s' up.\n", ifr.ifr_name);
|
||||
ifr.ifr_flags = IFF_UP;
|
||||
ioctl_or_fail(sock, SIOCSIFFLAGS, &ifr);
|
||||
// Add interface to bridge, if specified
|
||||
if (bridge_dev && bridge_dev[0] != '\0') {
|
||||
// First see if the bridge exists
|
||||
struct ifreq ifr_bridge;
|
||||
//NOTE strncpy does not null terminate if the string is too long, I use
|
||||
// snprintf or strlcpy instead
|
||||
//strncpy(ifr_bridge.ifr_name, bridge_dev, IFNAMSIZ);
|
||||
snprintf(ifr_bridge.ifr_name, IFNAMSIZ, "%s", bridge_dev);
|
||||
if ((err = ioctl(sock, SIOCGIFINDEX, &ifr_bridge)) < 0) {
|
||||
if (errno != ENODEV) {
|
||||
tap_log("TAP: ioctl SIOCGIFINDEX error: %s\n", strerror(errno));
|
||||
goto fail;
|
||||
} else {
|
||||
// Create the bridge
|
||||
ioctl_or_fail(sock, SIOCBRADDBR, &ifr_bridge);
|
||||
// Set the bridge up
|
||||
ifr_bridge.ifr_flags = IFF_UP;
|
||||
ioctl_or_fail(sock, SIOCSIFFLAGS, &ifr_bridge);
|
||||
}
|
||||
}
|
||||
// Get TAP index
|
||||
ioctl_or_fail(sock, SIOCGIFINDEX, &ifr);
|
||||
// Add the tap device to the bridge
|
||||
ifr_bridge.ifr_ifindex = ifr.ifr_ifindex;
|
||||
ioctl_or_fail(sock, SIOCBRADDIF, &ifr_bridge);
|
||||
}
|
||||
// close the socket we used for ioctl operations
|
||||
close(sock);
|
||||
tap_log("Allocated tap device %s\n", ifr.ifr_name);
|
||||
return fd;
|
||||
// cleanup point used by ioctl_or_fail macro
|
||||
fail:
|
||||
close(sock);
|
||||
close(fd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
void net_tap_in_available(void *priv)
|
||||
{
|
||||
net_tap_t *tap = priv;
|
||||
net_event_set(&tap->tx_event);
|
||||
}
|
||||
|
||||
void *
|
||||
net_tap_init(
|
||||
const netcard_t *card,
|
||||
const uint8_t *mac_addr,
|
||||
void *priv,
|
||||
char *netdrv_errbuf)
|
||||
{
|
||||
const char *bridge_dev = (void *) priv;
|
||||
int tap_fd = net_tap_alloc(mac_addr, bridge_dev);
|
||||
if (tap_fd < 0) {
|
||||
if (tap_fd == -EPERM) {
|
||||
net_tap_error(
|
||||
netdrv_errbuf,
|
||||
"No permissions to allocate tap device. "
|
||||
"Try adding NET_CAP_ADMIN,NET_CAP_RAW to 86box ("
|
||||
"sudo setcap 'CAP_NET_RAW,CAP_NET_ADMIN=eip')");
|
||||
} else {
|
||||
net_tap_error(
|
||||
netdrv_errbuf,
|
||||
"Unable to allocate TAP device: %s",
|
||||
strerror(-tap_fd));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if (bridge_dev && bridge_dev[0] != '\0') {
|
||||
}
|
||||
net_tap_t *tap = calloc(1, sizeof(net_tap_t));
|
||||
if (!tap) {
|
||||
goto alloc_fail;
|
||||
}
|
||||
tap->pkt_rx.data = calloc(1, NET_MAX_FRAME);
|
||||
if (!tap->pkt_rx.data) {
|
||||
goto alloc_fail;
|
||||
}
|
||||
for(int i = 0; i < NET_QUEUE_LEN; i++) {
|
||||
tap->pkts_tx[i].data = calloc(1, NET_MAX_FRAME);
|
||||
if (!tap->pkts_tx[i].data) {
|
||||
goto alloc_fail;
|
||||
}
|
||||
}
|
||||
tap->fd = tap_fd;
|
||||
tap->card = (netcard_t *) card;
|
||||
net_event_init(&tap->tx_event);
|
||||
net_event_init(&tap->stop_event);
|
||||
tap->poll_tid = thread_create(net_tap_thread, tap);
|
||||
return tap;
|
||||
alloc_fail:
|
||||
net_tap_error(netdrv_errbuf, "Failed to allocate memory");
|
||||
close(tap_fd);
|
||||
free(tap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const netdrv_t net_tap_drv = {
|
||||
&net_tap_in_available,
|
||||
&net_tap_init,
|
||||
&net_tap_close,
|
||||
NULL
|
||||
};
|
||||
@@ -480,6 +480,12 @@ network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETSETLINKSTATE set_lin
|
||||
card->host_drv = net_vde_drv;
|
||||
card->host_drv.priv = card->host_drv.init(card, mac, net_cards_conf[net_card_current].host_dev_name, net_drv_error);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAS_TAP
|
||||
case NET_TYPE_TAP:
|
||||
card->host_drv = net_tap_drv;
|
||||
card->host_drv.priv = card->host_drv.init(card, mac, net_cards_conf[net_card_current].host_dev_name, net_drv_error);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
card->host_drv.priv = NULL;
|
||||
|
||||
@@ -1061,6 +1061,9 @@ MediaMenu::nicUpdateMenu(int i)
|
||||
case NET_TYPE_VDE:
|
||||
netType = "VDE";
|
||||
break;
|
||||
case NET_TYPE_TAP:
|
||||
netType = "TAP";
|
||||
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);
|
||||
|
||||
@@ -38,12 +38,13 @@ SettingsNetwork::enableElements(Ui::SettingsNetwork *ui)
|
||||
auto *intf_cbox = findChild<QComboBox *>(QString("comboBoxIntf%1").arg(i + 1));
|
||||
auto *conf_btn = findChild<QPushButton *>(QString("pushButtonConf%1").arg(i + 1));
|
||||
auto *socket_line = findChild<QLineEdit *>(QString("socketVDENIC%1").arg(i + 1));
|
||||
|
||||
auto *bridge_line = findChild<QLineEdit *>(QString("bridgeTAPNIC%1").arg(i + 1));
|
||||
int netType = net_type_cbox->currentData().toInt();
|
||||
bool adaptersEnabled = netType == NET_TYPE_NONE
|
||||
|| netType == NET_TYPE_SLIRP
|
||||
|| netType == NET_TYPE_VDE
|
||||
|| (netType == NET_TYPE_PCAP && intf_cbox->currentData().toInt() > 0);
|
||||
|| (netType == NET_TYPE_PCAP && intf_cbox->currentData().toInt() > 0)
|
||||
|| netType == NET_TYPE_TAP;
|
||||
|
||||
intf_cbox->setEnabled(net_type_cbox->currentData().toInt() == NET_TYPE_PCAP);
|
||||
nic_cbox->setEnabled(adaptersEnabled);
|
||||
@@ -54,6 +55,7 @@ SettingsNetwork::enableElements(Ui::SettingsNetwork *ui)
|
||||
else
|
||||
conf_btn->setEnabled(adaptersEnabled && network_card_has_config(nic_cbox->currentData().toInt()));
|
||||
socket_line->setEnabled(net_type_cbox->currentData().toInt() == NET_TYPE_VDE);
|
||||
bridge_line->setEnabled(net_type_cbox->currentData().toInt() == NET_TYPE_TAP);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,6 +88,7 @@ SettingsNetwork::save()
|
||||
for (int i = 0; i < NET_CARD_MAX; ++i) {
|
||||
auto *cbox = findChild<QComboBox *>(QString("comboBoxNIC%1").arg(i + 1));
|
||||
auto *socket_line = findChild<QLineEdit *>(QString("socketVDENIC%1").arg(i + 1));
|
||||
auto *bridge_line = findChild<QLineEdit *>(QString("bridgeTAPNIC%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();
|
||||
@@ -95,6 +98,8 @@ SettingsNetwork::save()
|
||||
strncpy(net_cards_conf[i].host_dev_name, network_devs[cbox->currentData().toInt()].device, sizeof(net_cards_conf[i].host_dev_name) - 1);
|
||||
} else if (net_cards_conf[i].net_type == NET_TYPE_VDE) {
|
||||
strncpy(net_cards_conf[i].host_dev_name, socket_line->text().toUtf8().constData(), sizeof(net_cards_conf[i].host_dev_name));
|
||||
} else if (net_cards_conf[i].net_type == NET_TYPE_TAP) {
|
||||
strncpy(net_cards_conf[i].host_dev_name, bridge_line->text().toUtf8().constData(), sizeof(net_cards_conf[i].host_dev_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,7 +157,7 @@ SettingsNetwork::onCurrentMachineChanged(int machineId)
|
||||
if (network_devmap.has_vde) {
|
||||
Models::AddEntry(model, "VDE", NET_TYPE_VDE);
|
||||
}
|
||||
|
||||
Models::AddEntry(model, "TAP", NET_TYPE_TAP);
|
||||
model->removeRows(0, removeRows);
|
||||
cbox->setCurrentIndex(net_cards_conf[i].net_type);
|
||||
|
||||
@@ -171,12 +176,17 @@ SettingsNetwork::onCurrentMachineChanged(int machineId)
|
||||
}
|
||||
model->removeRows(0, removeRows);
|
||||
cbox->setCurrentIndex(selectedRow);
|
||||
}
|
||||
}
|
||||
if (net_cards_conf[i].net_type == NET_TYPE_VDE) {
|
||||
QString currentVdeSocket = net_cards_conf[i].host_dev_name;
|
||||
auto editline = findChild<QLineEdit *>(QString("socketVDENIC%1").arg(i+1));
|
||||
editline->setText(currentVdeSocket);
|
||||
}
|
||||
else if (net_cards_conf[i].net_type == NET_TYPE_TAP) {
|
||||
QString currentTapDevice = net_cards_conf[i].host_dev_name;
|
||||
auto editline = findChild<QLineEdit *>(QString("bridgeTAPNIC%1").arg(i+1));
|
||||
editline->setText(currentTapDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -144,7 +144,21 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="labelBridgeTAPNIC1">
|
||||
<property name="text">
|
||||
<string>TAP Bridge Device</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="bridgeTAPNIC1">
|
||||
<property name="maxLength">
|
||||
<number>127</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@@ -259,6 +273,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="bridgeTAPNIC2">
|
||||
<property name="maxLength">
|
||||
<number>127</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="socketVDENIC2">
|
||||
<property name="maxLength">
|
||||
@@ -266,7 +287,14 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="labelBridgeTAPNIC2">
|
||||
<property name="text">
|
||||
<string>TAP Bridge Device</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@@ -394,7 +422,21 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="labelBridgeTAPNIC3">
|
||||
<property name="text">
|
||||
<string>TAP Bridge Device</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="bridgeTAPNIC3">
|
||||
<property name="maxLength">
|
||||
<number>127</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@@ -508,13 +550,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="socketVDENIC4">
|
||||
<property name="maxLength">
|
||||
<number>127</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
@@ -522,7 +557,28 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="3" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="socketVDENIC4">
|
||||
<property name="maxLength">
|
||||
<number>127</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="labelBridgeTAPNIC4">
|
||||
<property name="text">
|
||||
<string>TAP Bridge Device</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="bridgeTAPNIC4">
|
||||
<property name="maxLength">
|
||||
<number>127</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
|
||||
Reference in New Issue
Block a user