2004-08-27 12:23:50 +04:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2011-02-25 01:05:47 +03:00
|
|
|
// $Id$
|
2004-08-27 12:23:50 +04:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2004-01-16 18:53:44 +03:00
|
|
|
//
|
2020-04-12 12:14:01 +03:00
|
|
|
// Copyright (C) 2004-2020 The Bochs Project
|
2009-02-08 12:05:52 +03:00
|
|
|
//
|
|
|
|
// This library is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
|
|
// License as published by the Free Software Foundation; either
|
|
|
|
// version 2 of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This library is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// Lesser General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
|
|
// License along with this library; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
|
2004-01-16 18:53:44 +03:00
|
|
|
// virtual Ethernet locator
|
|
|
|
//
|
2005-06-12 12:59:32 +04:00
|
|
|
// An implementation of ARP, ping(ICMP-echo), DHCP and read/write TFTP.
|
2004-01-16 18:53:44 +03:00
|
|
|
// Virtual host acts as a DHCP server for guest.
|
2020-04-12 12:14:01 +03:00
|
|
|
// Limited DNS server for 'vnet' and the client only.
|
2004-01-16 18:53:44 +03:00
|
|
|
// There are no connections between the virtual host and real ethernets.
|
|
|
|
//
|
2020-04-12 12:14:01 +03:00
|
|
|
// Virtual host name: vnet
|
|
|
|
// Virtual server IP: 192.168.10.1
|
|
|
|
// Virtual DNS server IP: 192.168.10.2
|
|
|
|
// Guest IP: 192.168.10.15
|
|
|
|
// Guest netmask: 255.255.255.0
|
|
|
|
// Guest broadcast: 192.168.10.255
|
2005-06-12 12:59:32 +04:00
|
|
|
// TFTP server uses ethdev value for the root directory and doesn't overwrite files
|
2004-01-16 18:53:44 +03:00
|
|
|
|
|
|
|
#define BX_PLUGGABLE
|
|
|
|
|
2004-06-19 19:20:15 +04:00
|
|
|
#include "iodev.h"
|
2011-08-16 21:27:27 +04:00
|
|
|
#include "netmod.h"
|
2017-03-12 10:48:08 +03:00
|
|
|
#include "netutil.h"
|
2005-12-10 21:37:35 +03:00
|
|
|
|
2004-10-04 00:06:12 +04:00
|
|
|
#if BX_NETWORKING
|
2004-01-16 18:53:44 +03:00
|
|
|
|
2017-03-12 23:26:42 +03:00
|
|
|
static unsigned int bx_vnet_instances = 0;
|
2017-03-12 10:48:08 +03:00
|
|
|
|
|
|
|
// network driver plugin entry points
|
|
|
|
|
|
|
|
int CDECL libvnet_net_plugin_init(plugin_t *plugin, plugintype_t type)
|
|
|
|
{
|
|
|
|
return 0; // Success
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDECL libvnet_net_plugin_fini(void)
|
|
|
|
{
|
|
|
|
// Nothing here yet
|
|
|
|
}
|
|
|
|
|
|
|
|
// network driver implementation
|
|
|
|
|
2009-04-13 17:33:11 +04:00
|
|
|
#define LOG_THIS netdev->
|
2004-01-16 18:53:44 +03:00
|
|
|
|
2007-07-01 11:28:14 +04:00
|
|
|
#define BX_ETH_VNET_PCAP_LOGGING 0
|
|
|
|
|
|
|
|
#if BX_ETH_VNET_PCAP_LOGGING
|
|
|
|
#include <pcap.h>
|
|
|
|
#endif
|
2004-01-16 18:53:44 +03:00
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
// handler to send/receive packets
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
static const Bit8u default_host_ipv4addr[4] = {192,168,10,1};
|
2020-04-12 12:14:01 +03:00
|
|
|
static const Bit8u default_dns_ipv4addr[4] = {192,168,10,2};
|
|
|
|
static const Bit8u default_guest_ipv4addr[4] = {192,168,10,15};
|
2004-08-27 12:23:50 +04:00
|
|
|
|
2004-10-07 21:38:03 +04:00
|
|
|
static Bit8u packet_buffer[BX_PACKET_BUFSIZE];
|
2004-08-27 12:23:50 +04:00
|
|
|
static unsigned packet_len;
|
|
|
|
|
2004-01-16 18:53:44 +03:00
|
|
|
class bx_vnet_pktmover_c : public eth_pktmover_c {
|
|
|
|
public:
|
|
|
|
bx_vnet_pktmover_c();
|
2013-09-16 21:06:03 +04:00
|
|
|
virtual ~bx_vnet_pktmover_c();
|
2004-01-16 18:53:44 +03:00
|
|
|
void pktmover_init(
|
|
|
|
const char *netif, const char *macaddr,
|
2011-12-17 12:22:33 +04:00
|
|
|
eth_rx_handler_t rxh, eth_rx_status_t rxstat,
|
|
|
|
bx_devmodel_c *dev, const char *script);
|
2004-01-16 18:53:44 +03:00
|
|
|
void sendpkt(void *buf, unsigned io_len);
|
|
|
|
private:
|
|
|
|
void guest_to_host(const Bit8u *buf, unsigned io_len);
|
2020-05-12 23:51:26 +03:00
|
|
|
void host_to_guest(void);
|
2004-01-16 18:53:44 +03:00
|
|
|
|
2020-04-12 12:14:01 +03:00
|
|
|
vnet_server_c vnet_server;
|
2012-08-16 15:59:44 +04:00
|
|
|
|
2020-04-12 12:14:01 +03:00
|
|
|
dhcp_cfg_t dhcp;
|
2004-01-16 18:53:44 +03:00
|
|
|
|
2004-08-27 12:23:50 +04:00
|
|
|
static void rx_timer_handler(void *);
|
|
|
|
void rx_timer(void);
|
2011-12-18 13:12:38 +04:00
|
|
|
|
2004-08-27 12:23:50 +04:00
|
|
|
int rx_timer_index;
|
2020-05-18 22:25:27 +03:00
|
|
|
bx_bool rx_timer_pending;
|
2011-12-18 13:12:38 +04:00
|
|
|
unsigned netdev_speed;
|
2004-09-11 15:26:41 +04:00
|
|
|
unsigned tx_time;
|
2004-08-27 12:23:50 +04:00
|
|
|
|
2020-05-03 00:21:53 +03:00
|
|
|
bx_bool vnet_logging;
|
2004-01-16 18:53:44 +03:00
|
|
|
FILE *pktlog_txt;
|
2007-07-01 11:28:14 +04:00
|
|
|
#if BX_ETH_VNET_PCAP_LOGGING
|
|
|
|
pcap_t *pcapp;
|
|
|
|
pcap_dumper_t *pktlog_pcap;
|
|
|
|
struct pcap_pkthdr pcaphdr;
|
|
|
|
#endif // BX_ETH_VNET_PCAP_LOGGING
|
2004-01-16 18:53:44 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
class bx_vnet_locator_c : public eth_locator_c {
|
|
|
|
public:
|
|
|
|
bx_vnet_locator_c(void) : eth_locator_c("vnet") {}
|
|
|
|
protected:
|
|
|
|
eth_pktmover_c *allocate(
|
|
|
|
const char *netif, const char *macaddr,
|
2011-12-17 12:22:33 +04:00
|
|
|
eth_rx_handler_t rxh, eth_rx_status_t rxstat,
|
2009-04-13 17:33:11 +04:00
|
|
|
bx_devmodel_c *dev, const char *script) {
|
2004-01-16 18:53:44 +03:00
|
|
|
bx_vnet_pktmover_c *pktmover;
|
|
|
|
pktmover = new bx_vnet_pktmover_c();
|
2011-12-17 12:22:33 +04:00
|
|
|
pktmover->pktmover_init(netif, macaddr, rxh, rxstat, dev, script);
|
2004-01-16 18:53:44 +03:00
|
|
|
return pktmover;
|
|
|
|
}
|
|
|
|
} bx_vnet_match;
|
|
|
|
|
|
|
|
|
|
|
|
bx_vnet_pktmover_c::bx_vnet_pktmover_c()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2007-07-01 11:28:14 +04:00
|
|
|
void bx_vnet_pktmover_c::pktmover_init(
|
2004-01-16 18:53:44 +03:00
|
|
|
const char *netif, const char *macaddr,
|
2011-12-17 12:22:33 +04:00
|
|
|
eth_rx_handler_t rxh, eth_rx_status_t rxstat,
|
|
|
|
bx_devmodel_c *dev, const char *script)
|
2004-01-16 18:53:44 +03:00
|
|
|
{
|
2013-09-16 21:06:03 +04:00
|
|
|
if (bx_vnet_instances > 0) {
|
|
|
|
BX_PANIC(("only one 'vnet' instance supported yet"));
|
|
|
|
}
|
2009-04-13 17:33:11 +04:00
|
|
|
this->netdev = dev;
|
2011-12-17 12:22:33 +04:00
|
|
|
this->rxh = rxh;
|
|
|
|
this->rxstat = rxstat;
|
2004-01-16 18:53:44 +03:00
|
|
|
|
2011-03-01 23:47:12 +03:00
|
|
|
memcpy(&dhcp.host_macaddr[0], macaddr, 6);
|
|
|
|
dhcp.host_macaddr[5] ^= 0x03;
|
2004-01-16 18:53:44 +03:00
|
|
|
|
2017-03-04 16:32:41 +03:00
|
|
|
memcpy(dhcp.host_ipv4addr, default_host_ipv4addr, 4);
|
2020-04-12 12:14:01 +03:00
|
|
|
memcpy(dhcp.dns_ipv4addr, default_dns_ipv4addr, 4);
|
|
|
|
vnet_server.init(dev, &dhcp, netif);
|
|
|
|
vnet_server.init_client(0, (Bit8u*)macaddr, (Bit8u*)&default_guest_ipv4addr);
|
2004-01-16 18:53:44 +03:00
|
|
|
|
2011-12-18 13:12:38 +04:00
|
|
|
Bit32u status = this->rxstat(this->netdev) & BX_NETDEV_SPEED;
|
|
|
|
this->netdev_speed = (status == BX_NETDEV_1GBIT) ? 1000 :
|
|
|
|
(status == BX_NETDEV_100MBIT) ? 100 : 10;
|
2008-01-27 01:24:03 +03:00
|
|
|
this->rx_timer_index =
|
2017-03-30 21:08:15 +03:00
|
|
|
DEV_register_timer(this, this->rx_timer_handler, 1000, 0, 0, "eth_vnet");
|
2020-05-18 22:25:27 +03:00
|
|
|
rx_timer_pending = 0;
|
2004-08-27 12:23:50 +04:00
|
|
|
|
2013-09-16 21:06:03 +04:00
|
|
|
BX_INFO(("'vnet' network driver initialized"));
|
|
|
|
bx_vnet_instances++;
|
|
|
|
|
2017-03-04 13:26:22 +03:00
|
|
|
if ((strlen(script) > 0) && (strcmp(script, "none"))) {
|
|
|
|
pktlog_txt = fopen(script, "wb");
|
2020-05-03 00:21:53 +03:00
|
|
|
vnet_logging = (pktlog_txt != NULL);
|
2017-03-04 13:26:22 +03:00
|
|
|
} else {
|
2020-05-03 00:21:53 +03:00
|
|
|
vnet_logging = 0;
|
|
|
|
}
|
|
|
|
if (vnet_logging) {
|
|
|
|
fprintf(pktlog_txt, "vnet packetmover readable log file\n");
|
|
|
|
fprintf(pktlog_txt, "TFTP root = %s\n", netif);
|
|
|
|
fprintf(pktlog_txt, "host MAC address = ");
|
|
|
|
int i;
|
|
|
|
for (i=0; i<6; i++)
|
|
|
|
fprintf(pktlog_txt, "%02x%s", 0xff & dhcp.host_macaddr[i], i<5?":" : "\n");
|
|
|
|
fprintf(pktlog_txt, "guest MAC address = ");
|
|
|
|
for (i=0; i<6; i++)
|
|
|
|
fprintf(pktlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "\n");
|
|
|
|
fprintf(pktlog_txt, "--\n");
|
|
|
|
fflush(pktlog_txt);
|
2017-03-04 13:26:22 +03:00
|
|
|
}
|
2007-07-01 11:28:14 +04:00
|
|
|
#if BX_ETH_VNET_PCAP_LOGGING
|
2009-04-13 17:33:11 +04:00
|
|
|
pcapp = pcap_open_dead(DLT_EN10MB, BX_PACKET_BUFSIZE);
|
2017-03-04 13:26:22 +03:00
|
|
|
pktlog_pcap = pcap_dump_open(pcapp, "vnet-pktlog.pcap");
|
|
|
|
if (pktlog_pcap == NULL) BX_PANIC(("vnet-pktlog.pcap failed"));
|
2007-07-01 11:28:14 +04:00
|
|
|
#endif
|
2004-01-16 18:53:44 +03:00
|
|
|
}
|
|
|
|
|
2013-09-16 21:06:03 +04:00
|
|
|
bx_vnet_pktmover_c::~bx_vnet_pktmover_c()
|
|
|
|
{
|
2020-05-03 00:21:53 +03:00
|
|
|
if (vnet_logging) {
|
|
|
|
fclose(pktlog_txt);
|
|
|
|
}
|
2013-09-16 21:06:03 +04:00
|
|
|
bx_vnet_instances--;
|
|
|
|
}
|
|
|
|
|
2007-07-01 11:28:14 +04:00
|
|
|
void bx_vnet_pktmover_c::sendpkt(void *buf, unsigned io_len)
|
2004-01-16 18:53:44 +03:00
|
|
|
{
|
|
|
|
guest_to_host((const Bit8u *)buf,io_len);
|
|
|
|
}
|
|
|
|
|
2007-07-01 11:28:14 +04:00
|
|
|
void bx_vnet_pktmover_c::guest_to_host(const Bit8u *buf, unsigned io_len)
|
2004-01-16 18:53:44 +03:00
|
|
|
{
|
2020-05-03 00:21:53 +03:00
|
|
|
if (vnet_logging) {
|
|
|
|
write_pktlog_txt(pktlog_txt, buf, io_len, 0);
|
|
|
|
}
|
2007-07-01 11:28:14 +04:00
|
|
|
#if BX_ETH_VNET_PCAP_LOGGING
|
|
|
|
if (pktlog_pcap && !ferror((FILE *)pktlog_pcap)) {
|
|
|
|
Bit64u time = bx_pc_system.time_usec();
|
|
|
|
pcaphdr.ts.tv_usec = time % 1000000;
|
|
|
|
pcaphdr.ts.tv_sec = time / 1000000;
|
|
|
|
pcaphdr.caplen = io_len;
|
|
|
|
pcaphdr.len = io_len;
|
|
|
|
pcap_dump((u_char *)pktlog_pcap, &pcaphdr, buf);
|
|
|
|
fflush((FILE *)pktlog_pcap);
|
2008-01-27 01:24:03 +03:00
|
|
|
}
|
2007-07-01 11:28:14 +04:00
|
|
|
#endif
|
2004-01-16 18:53:44 +03:00
|
|
|
|
2011-12-18 13:12:38 +04:00
|
|
|
this->tx_time = (64 + 96 + 4 * 8 + io_len * 8) / this->netdev_speed;
|
2020-05-12 23:51:26 +03:00
|
|
|
vnet_server.handle_packet(buf, io_len);
|
|
|
|
|
|
|
|
host_to_guest();
|
|
|
|
}
|
|
|
|
|
|
|
|
void bx_vnet_pktmover_c::host_to_guest(void)
|
|
|
|
{
|
2020-05-18 22:25:27 +03:00
|
|
|
if (!rx_timer_pending) {
|
|
|
|
packet_len = vnet_server.get_packet(packet_buffer);
|
|
|
|
if (packet_len > 0) {
|
|
|
|
unsigned rx_time = (64 + 96 + 4 * 8 + packet_len * 8) / this->netdev_speed;
|
|
|
|
bx_pc_system.activate_timer(this->rx_timer_index, this->tx_time + rx_time + 100, 0);
|
|
|
|
rx_timer_pending = 1;
|
|
|
|
}
|
2020-05-03 00:21:53 +03:00
|
|
|
}
|
2004-01-16 18:53:44 +03:00
|
|
|
}
|
|
|
|
|
2004-08-27 12:23:50 +04:00
|
|
|
// The receive poll process
|
2007-07-01 11:28:14 +04:00
|
|
|
void bx_vnet_pktmover_c::rx_timer_handler(void *this_ptr)
|
2004-08-27 12:23:50 +04:00
|
|
|
{
|
|
|
|
bx_vnet_pktmover_c *class_ptr = (bx_vnet_pktmover_c *) this_ptr;
|
|
|
|
|
|
|
|
class_ptr->rx_timer();
|
|
|
|
}
|
|
|
|
|
2007-07-01 11:28:14 +04:00
|
|
|
void bx_vnet_pktmover_c::rx_timer(void)
|
2004-08-27 12:23:50 +04:00
|
|
|
{
|
2011-12-18 13:12:38 +04:00
|
|
|
if (this->rxstat(this->netdev) & BX_NETDEV_RXREADY) {
|
|
|
|
this->rxh(this->netdev, (void *)packet_buffer, packet_len);
|
2020-05-03 00:21:53 +03:00
|
|
|
if (vnet_logging) {
|
|
|
|
write_pktlog_txt(pktlog_txt, packet_buffer, packet_len, 1);
|
|
|
|
}
|
2007-07-01 11:28:14 +04:00
|
|
|
#if BX_ETH_VNET_PCAP_LOGGING
|
2011-12-18 13:12:38 +04:00
|
|
|
if (pktlog_pcap && !ferror((FILE *)pktlog_pcap)) {
|
|
|
|
Bit64u time = bx_pc_system.time_usec();
|
|
|
|
pcaphdr.ts.tv_usec = time % 1000000;
|
|
|
|
pcaphdr.ts.tv_sec = time / 1000000;
|
|
|
|
pcaphdr.caplen = packet_len;
|
|
|
|
pcaphdr.len = packet_len;
|
|
|
|
pcap_dump((u_char *)pktlog_pcap, &pcaphdr, packet_buffer);
|
|
|
|
fflush((FILE *)pktlog_pcap);
|
|
|
|
}
|
2007-07-01 11:28:14 +04:00
|
|
|
#endif
|
2020-05-18 22:25:27 +03:00
|
|
|
rx_timer_pending = 0;
|
2020-05-12 23:51:26 +03:00
|
|
|
// check for another pending packet
|
|
|
|
host_to_guest();
|
2011-12-18 13:12:38 +04:00
|
|
|
} else {
|
|
|
|
BX_ERROR(("device not ready to receive data"));
|
|
|
|
}
|
2004-08-27 12:23:50 +04:00
|
|
|
}
|
|
|
|
|
2004-10-04 00:06:12 +04:00
|
|
|
#endif /* if BX_NETWORKING */
|