Bochs/bochs/iodev/network/eth_vnet.cc
Volker Ruppert 758f4de4d4 Rewrite of the network driver plugin code.
- Removed "pseudo device plugin" containing common code and specific drivers.
- Moved network module base classes and module handling to the Bochs core.
  Now loading network driver plugins in netmod.cc.
- Moved shared networking code used by the 'vnet' driver and 'bxhub' from
  netmod.cc/.h to new files netutil.cc/.h.
- Created separate plugins for each network driver implementation.
- Modified Bochs plugin system to support new plugin type PLUGTYPE_NETWORK.
2017-03-12 07:48:08 +00:00

754 lines
22 KiB
C++

/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2004-2017 The Bochs Project
//
// 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
// virtual Ethernet locator
//
// An implementation of ARP, ping(ICMP-echo), DHCP and read/write TFTP.
// Virtual host acts as a DHCP server for guest.
// There are no connections between the virtual host and real ethernets.
//
// Virtual host name: vnet
// Virtual host IP: 192.168.10.1
// Guest IP: 192.168.10.2
// Guest netmask: 255.255.255.0
// Guest broadcast: 192.168.10.255
// TFTP server uses ethdev value for the root directory and doesn't overwrite files
#define BX_PLUGGABLE
#include "iodev.h"
#include "netmod.h"
#include "netutil.h"
#if BX_NETWORKING
static unsigned int bx_vnet_instances;
// network driver plugin entry points
int CDECL libvnet_net_plugin_init(plugin_t *plugin, plugintype_t type)
{
bx_vnet_instances = 0;
return 0; // Success
}
void CDECL libvnet_net_plugin_fini(void)
{
// Nothing here yet
}
// network driver implementation
#define LOG_THIS netdev->
#define BX_ETH_VNET_LOGGING 1
#define BX_ETH_VNET_PCAP_LOGGING 0
#if !defined(WIN32) || defined(__CYGWIN__)
#include <arpa/inet.h> /* ntohs, htons */
#else
#include <winsock2.h>
#endif
#if BX_ETH_VNET_PCAP_LOGGING
#include <pcap.h>
#endif
/////////////////////////////////////////////////////////////////////////
// handler to send/receive packets
/////////////////////////////////////////////////////////////////////////
static const Bit8u default_host_ipv4addr[4] = {192,168,10,1};
static const Bit8u subnetmask_ipv4addr[4] = {0xff,0xff,0xff,0x00};
static const Bit8u default_guest_ipv4addr[4] = {192,168,10,2};
static const Bit8u broadcast_ipv4addr[3][4] =
{
{ 0, 0, 0, 0},
{255,255,255,255},
{192,168, 10,255},
};
#define LAYER4_LISTEN_MAX 128
static Bit8u packet_buffer[BX_PACKET_BUFSIZE];
static unsigned packet_len;
typedef void (*layer4_handler_t)(
void *this_ptr,
const Bit8u *ipheader,
unsigned ipheader_len,
unsigned sourceport,
unsigned targetport,
const Bit8u *data,
unsigned data_len
);
#define INET_PORT_FTPDATA 20
#define INET_PORT_FTP 21
#define INET_PORT_TIME 37
#define INET_PORT_NAME 42
#define INET_PORT_DOMAIN 53
#define INET_PORT_BOOTP_SERVER 67
#define INET_PORT_BOOTP_CLIENT 68
#define INET_PORT_HTTP 80
#define INET_PORT_NTP 123
// TFTP server support by EaseWay <easeway@123.com>
#define INET_PORT_TFTP_SERVER 69
class bx_vnet_pktmover_c : public eth_pktmover_c {
public:
bx_vnet_pktmover_c();
virtual ~bx_vnet_pktmover_c();
void pktmover_init(
const char *netif, const char *macaddr,
eth_rx_handler_t rxh, eth_rx_status_t rxstat,
bx_devmodel_c *dev, const char *script);
void sendpkt(void *buf, unsigned io_len);
private:
void guest_to_host(const Bit8u *buf, unsigned io_len);
void host_to_guest(Bit8u *buf, unsigned io_len, unsigned l3type);
void process_arp(const Bit8u *buf, unsigned io_len);
void host_to_guest_arp(Bit8u *buf, unsigned io_len);
void process_ipv4(const Bit8u *buf, unsigned io_len);
void host_to_guest_ipv4(Bit8u *buf, unsigned io_len);
layer4_handler_t get_layer4_handler(
unsigned ipprotocol, unsigned port);
bx_bool register_layer4_handler(
unsigned ipprotocol, unsigned port,layer4_handler_t func);
bx_bool unregister_layer4_handler(
unsigned ipprotocol, unsigned port);
void process_icmpipv4(
const Bit8u *ipheader, unsigned ipheader_len,
const Bit8u *l4pkt, unsigned l4pkt_len);
void process_tcpipv4(
const Bit8u *ipheader, unsigned ipheader_len,
const Bit8u *l4pkt, unsigned l4pkt_len);
void process_udpipv4(
const Bit8u *ipheader, unsigned ipheader_len,
const Bit8u *l4pkt, unsigned l4pkt_len);
void host_to_guest_udpipv4_packet(
unsigned target_port, unsigned source_port,
const Bit8u *udpdata, unsigned udpdata_len);
void process_icmpipv4_echo(
const Bit8u *ipheader, unsigned ipheader_len,
const Bit8u *l4pkt, unsigned l4pkt_len);
static void udpipv4_dhcp_handler(
void *this_ptr,
const Bit8u *ipheader, unsigned ipheader_len,
unsigned sourceport, unsigned targetport,
const Bit8u *data, unsigned data_len);
void udpipv4_dhcp_handler_ns(
const Bit8u *ipheader, unsigned ipheader_len,
unsigned sourceport, unsigned targetport,
const Bit8u *data, unsigned data_len);
static void udpipv4_tftp_handler(
void *this_ptr,
const Bit8u *ipheader, unsigned ipheader_len,
unsigned sourceport, unsigned targetport,
const Bit8u *data, unsigned data_len);
void udpipv4_tftp_handler_ns(
const Bit8u *ipheader, unsigned ipheader_len,
unsigned sourceport, unsigned targetport,
const Bit8u *data, unsigned data_len);
dhcp_cfg_t dhcp;
char tftp_rootdir[BX_PATHNAME_LEN];
struct {
unsigned ipprotocol;
unsigned port;
layer4_handler_t func;
} l4data[LAYER4_LISTEN_MAX];
unsigned l4data_used;
static void rx_timer_handler(void *);
void rx_timer(void);
int rx_timer_index;
unsigned netdev_speed;
unsigned tx_time;
#if BX_ETH_VNET_LOGGING
FILE *pktlog_txt;
#endif // BX_ETH_VNET_LOGGING
#if BX_ETH_VNET_PCAP_LOGGING
pcap_t *pcapp;
pcap_dumper_t *pktlog_pcap;
struct pcap_pkthdr pcaphdr;
#endif // BX_ETH_VNET_PCAP_LOGGING
};
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,
eth_rx_handler_t rxh, eth_rx_status_t rxstat,
bx_devmodel_c *dev, const char *script) {
bx_vnet_pktmover_c *pktmover;
pktmover = new bx_vnet_pktmover_c();
pktmover->pktmover_init(netif, macaddr, rxh, rxstat, dev, script);
return pktmover;
}
} bx_vnet_match;
bx_vnet_pktmover_c::bx_vnet_pktmover_c()
{
}
void bx_vnet_pktmover_c::pktmover_init(
const char *netif, const char *macaddr,
eth_rx_handler_t rxh, eth_rx_status_t rxstat,
bx_devmodel_c *dev, const char *script)
{
if (bx_vnet_instances > 0) {
BX_PANIC(("only one 'vnet' instance supported yet"));
}
this->netdev = dev;
this->rxh = rxh;
this->rxstat = rxstat;
strcpy(this->tftp_rootdir, netif);
memcpy(&dhcp.host_macaddr[0], macaddr, 6);
memcpy(&dhcp.guest_macaddr[0], macaddr, 6);
dhcp.host_macaddr[5] ^= 0x03;
memcpy(dhcp.host_ipv4addr, default_host_ipv4addr, 4);
memcpy(dhcp.guest_ipv4addr, &broadcast_ipv4addr[1][0], 4);
memcpy(dhcp.default_guest_ipv4addr, default_guest_ipv4addr, 4);
memcpy(&dhcp.dns_ipv4addr, &broadcast_ipv4addr[0][0], 4);
l4data_used = 0;
register_layer4_handler(0x11,INET_PORT_BOOTP_SERVER,udpipv4_dhcp_handler);
register_layer4_handler(0x11,INET_PORT_TFTP_SERVER,udpipv4_tftp_handler);
Bit32u status = this->rxstat(this->netdev) & BX_NETDEV_SPEED;
this->netdev_speed = (status == BX_NETDEV_1GBIT) ? 1000 :
(status == BX_NETDEV_100MBIT) ? 100 : 10;
this->rx_timer_index =
bx_pc_system.register_timer(this, this->rx_timer_handler, 1000,
0, 0, "eth_vnet");
BX_INFO(("'vnet' network driver initialized"));
bx_vnet_instances++;
#if BX_ETH_VNET_LOGGING
if ((strlen(script) > 0) && (strcmp(script, "none"))) {
pktlog_txt = fopen(script, "wb");
} else {
pktlog_txt = fopen("vnet-pktlog.txt", "wb");
}
if (!pktlog_txt) BX_PANIC(("vnet-pktlog.txt failed"));
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 & dhcp.guest_macaddr[i], i<5?":" : "\n");
fprintf(pktlog_txt, "--\n");
fflush(pktlog_txt);
#endif
#if BX_ETH_VNET_PCAP_LOGGING
pcapp = pcap_open_dead(DLT_EN10MB, BX_PACKET_BUFSIZE);
pktlog_pcap = pcap_dump_open(pcapp, "vnet-pktlog.pcap");
if (pktlog_pcap == NULL) BX_PANIC(("vnet-pktlog.pcap failed"));
#endif
}
bx_vnet_pktmover_c::~bx_vnet_pktmover_c()
{
bx_vnet_instances--;
}
void bx_vnet_pktmover_c::sendpkt(void *buf, unsigned io_len)
{
guest_to_host((const Bit8u *)buf,io_len);
}
void bx_vnet_pktmover_c::guest_to_host(const Bit8u *buf, unsigned io_len)
{
#if BX_ETH_VNET_LOGGING
write_pktlog_txt(pktlog_txt, buf, io_len, 0);
#endif
#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);
}
#endif
this->tx_time = (64 + 96 + 4 * 8 + io_len * 8) / this->netdev_speed;
if ((io_len >= 14) &&
(!memcmp(&buf[6],&dhcp.guest_macaddr[0],6)) &&
(!memcmp(&buf[0],&dhcp.host_macaddr[0],6) ||
!memcmp(&buf[0],&broadcast_macaddr[0],6))) {
switch (get_net2(&buf[12])) {
case ETHERNET_TYPE_IPV4:
process_ipv4(buf, io_len);
break;
case ETHERNET_TYPE_ARP:
process_arp(buf, io_len);
break;
default: // unknown packet type.
break;
}
}
}
// The receive poll process
void bx_vnet_pktmover_c::rx_timer_handler(void *this_ptr)
{
bx_vnet_pktmover_c *class_ptr = (bx_vnet_pktmover_c *) this_ptr;
class_ptr->rx_timer();
}
void bx_vnet_pktmover_c::rx_timer(void)
{
if (this->rxstat(this->netdev) & BX_NETDEV_RXREADY) {
this->rxh(this->netdev, (void *)packet_buffer, packet_len);
#if BX_ETH_VNET_LOGGING
write_pktlog_txt(pktlog_txt, packet_buffer, packet_len, 1);
#endif
#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 = packet_len;
pcaphdr.len = packet_len;
pcap_dump((u_char *)pktlog_pcap, &pcaphdr, packet_buffer);
fflush((FILE *)pktlog_pcap);
}
#endif
} else {
BX_ERROR(("device not ready to receive data"));
}
}
void bx_vnet_pktmover_c::host_to_guest(Bit8u *buf, unsigned io_len, unsigned l3type)
{
Bit8u localbuf[MIN_RX_PACKET_LEN];
if (io_len < 14) {
BX_PANIC(("host_to_guest: io_len < 14!"));
return;
}
if (io_len < MIN_RX_PACKET_LEN) {
memcpy(&localbuf[0], &buf[0], io_len);
memset(&localbuf[io_len], 0, MIN_RX_PACKET_LEN-io_len);
buf = localbuf;
io_len = MIN_RX_PACKET_LEN;
}
packet_len = io_len;
memcpy(&packet_buffer, &buf[0], io_len);
vnet_prepare_reply(packet_buffer, l3type, &dhcp);
unsigned rx_time = (64 + 96 + 4 * 8 + io_len * 8) / this->netdev_speed;
bx_pc_system.activate_timer(this->rx_timer_index, this->tx_time + rx_time + 100, 0);
}
/////////////////////////////////////////////////////////////////////////
// ARP
/////////////////////////////////////////////////////////////////////////
void bx_vnet_pktmover_c::process_arp(const Bit8u *buf, unsigned io_len)
{
Bit8u replybuf[MIN_RX_PACKET_LEN];
if (io_len < 22) return;
if (io_len < (unsigned)(22+buf[18]*2+buf[19]*2)) return;
arp_header_t *arphdr = (arp_header_t *)((Bit8u *)buf +
sizeof(ethernet_header_t));
if ((ntohs(arphdr->hw_addr_space) != 0x0001) ||
(ntohs(arphdr->proto_addr_space) != 0x0800) ||
(arphdr->hw_addr_len != ETHERNET_MAC_ADDR_LEN) ||
(arphdr->proto_addr_len != 4)) {
BX_ERROR(("Unhandled ARP message hw: 0x%04x (%d) proto: 0x%04x (%d)",
ntohs(arphdr->hw_addr_space), arphdr->hw_addr_len,
ntohs(arphdr->proto_addr_space), arphdr->proto_addr_len));
return;
}
switch (ntohs(arphdr->opcode)) {
case ARP_OPCODE_REQUEST:
if (vnet_process_arp_request(buf, replybuf, &dhcp)) {
host_to_guest_arp(replybuf, MIN_RX_PACKET_LEN);
}
break;
case ARP_OPCODE_REPLY:
BX_ERROR(("unexpected ARP REPLY"));
break;
case ARP_OPCODE_REV_REQUEST:
BX_ERROR(("RARP is not implemented"));
break;
case ARP_OPCODE_REV_REPLY:
BX_ERROR(("unexpected RARP REPLY"));
break;
default:
BX_ERROR(("arp: unknown ARP opcode 0x%04x", ntohs(arphdr->opcode)));
break;
}
}
void bx_vnet_pktmover_c::host_to_guest_arp(Bit8u *buf, unsigned io_len)
{
host_to_guest(buf, io_len, ETHERNET_TYPE_ARP);
}
/////////////////////////////////////////////////////////////////////////
// IPv4
/////////////////////////////////////////////////////////////////////////
void bx_vnet_pktmover_c::process_ipv4(const Bit8u *buf, unsigned io_len)
{
unsigned total_len;
unsigned fragment_flags;
unsigned fragment_offset;
unsigned l3header_len;
const Bit8u *l4pkt;
unsigned l4pkt_len;
if (io_len < (14U+20U)) {
BX_ERROR(("ip packet - too small packet"));
return;
}
ip_header_t *iphdr = (ip_header_t *)((Bit8u *)buf +
sizeof(ethernet_header_t));
if (iphdr->version != 4) {
BX_ERROR(("ipv%u packet - not implemented", iphdr->version));
return;
}
l3header_len = (iphdr->header_len << 2);
if (l3header_len != 20) {
BX_ERROR(("ip: option header is not implemented"));
return;
}
if (ip_checksum((Bit8u*)iphdr, l3header_len) != (Bit16u)0xffff) {
BX_ERROR(("ip: invalid checksum"));
return;
}
total_len = ntohs(iphdr->total_len);
if (memcmp(&iphdr->dst_addr, dhcp.host_ipv4addr, 4) &&
memcmp(&iphdr->dst_addr, broadcast_ipv4addr[0],4) &&
memcmp(&iphdr->dst_addr, broadcast_ipv4addr[1],4) &&
memcmp(&iphdr->dst_addr, broadcast_ipv4addr[2],4))
{
BX_ERROR(("target IP address %u.%u.%u.%u is unknown",
(unsigned)buf[14+16],(unsigned)buf[14+17],
(unsigned)buf[14+18],(unsigned)buf[14+19]));
return;
}
fragment_flags = ntohs(iphdr->frag_offs) >> 13;
fragment_offset = (ntohs(iphdr->frag_offs) & 0x1fff) << 3;
if ((fragment_flags & 0x1) || (fragment_offset != 0)) {
BX_ERROR(("ignore fragmented packet!"));
return;
}
l4pkt = &buf[14 + l3header_len];
l4pkt_len = total_len - l3header_len;
switch (iphdr->protocol) {
case 0x01: // ICMP
process_icmpipv4(&buf[14], l3header_len, l4pkt,l4pkt_len);
break;
case 0x06: // TCP
process_tcpipv4(&buf[14], l3header_len, l4pkt, l4pkt_len);
break;
case 0x11: // UDP
process_udpipv4(&buf[14], l3header_len, l4pkt, l4pkt_len);
break;
default:
BX_ERROR(("unknown IP protocol %02x", iphdr->protocol));
break;
}
}
void bx_vnet_pktmover_c::host_to_guest_ipv4(Bit8u *buf, unsigned io_len)
{
unsigned l3header_len;
buf[14+0] = (buf[14+0] & 0x0f) | 0x40;
l3header_len = ((unsigned)(buf[14+0] & 0x0f) << 2);
memcpy(&buf[14+12],&dhcp.host_ipv4addr[0],4);
memcpy(&buf[14+16],&dhcp.guest_ipv4addr[0],4);
put_net2(&buf[14+10], 0);
put_net2(&buf[14+10], ip_checksum(&buf[14],l3header_len) ^ (Bit16u)0xffff);
host_to_guest(buf, io_len, ETHERNET_TYPE_IPV4);
}
layer4_handler_t bx_vnet_pktmover_c::get_layer4_handler(
unsigned ipprotocol, unsigned port)
{
unsigned n;
for (n = 0; n < l4data_used; n++) {
if (l4data[n].ipprotocol == ipprotocol && l4data[n].port == port)
return l4data[n].func;
}
return (layer4_handler_t)NULL;
}
bx_bool bx_vnet_pktmover_c::register_layer4_handler(
unsigned ipprotocol, unsigned port,layer4_handler_t func)
{
if (get_layer4_handler(ipprotocol,port) != (layer4_handler_t)NULL) {
BX_ERROR(("IP protocol 0x%02x port %u is already in use",
ipprotocol, port));
return false;
}
unsigned n;
for (n = 0; n < l4data_used; n++) {
if (l4data[n].func == (layer4_handler_t)NULL) {
break;
}
}
if (n == l4data_used) {
if (n >= LAYER4_LISTEN_MAX) {
BX_ERROR(("vnet: LAYER4_LISTEN_MAX is too small"));
return false;
}
l4data_used++;
}
l4data[n].ipprotocol = ipprotocol;
l4data[n].port = port;
l4data[n].func = func;
return true;
}
bx_bool bx_vnet_pktmover_c::unregister_layer4_handler(
unsigned ipprotocol, unsigned port)
{
unsigned n;
for (n = 0; n < l4data_used; n++) {
if (l4data[n].ipprotocol == ipprotocol && l4data[n].port == port) {
l4data[n].func = (layer4_handler_t)NULL;
return true;
}
}
BX_ERROR(("IP protocol 0x%02x port %u is not registered",
ipprotocol,port));
return false;
}
void bx_vnet_pktmover_c::process_icmpipv4(
const Bit8u *ipheader, unsigned ipheader_len,
const Bit8u *l4pkt, unsigned l4pkt_len)
{
unsigned icmptype;
unsigned icmpcode;
if (l4pkt_len < 8) return;
icmptype = l4pkt[0];
icmpcode = l4pkt[1];
if (ip_checksum(l4pkt,l4pkt_len) != (Bit16u)0xffff) {
BX_ERROR(("icmp: invalid checksum"));
return;
}
switch (icmptype) {
case 0x08: // ECHO
if (icmpcode == 0) {
process_icmpipv4_echo(ipheader,ipheader_len,l4pkt,l4pkt_len);
}
break;
default:
BX_ERROR(("unhandled icmp packet: type=%u code=%u",
icmptype, icmpcode));
break;
}
}
void bx_vnet_pktmover_c::process_tcpipv4(
const Bit8u *ipheader, unsigned ipheader_len,
const Bit8u *l4pkt, unsigned l4pkt_len)
{
if (l4pkt_len < 20) return;
BX_ERROR(("tcp packet - not implemented"));
}
void bx_vnet_pktmover_c::process_udpipv4(
const Bit8u *ipheader, unsigned ipheader_len,
const Bit8u *l4pkt, unsigned l4pkt_len)
{
unsigned udp_dst_port;
unsigned udp_src_port;
// unsigned udp_len;
layer4_handler_t func;
if (l4pkt_len < 8) return;
udp_header_t *udphdr = (udp_header_t *)l4pkt;
udp_src_port = ntohs(udphdr->src_port);
udp_dst_port = ntohs(udphdr->dst_port);
// udp_len = ntohs(udphdr->length);
func = get_layer4_handler(0x11, udp_dst_port);
if (func != (layer4_handler_t)NULL) {
(*func)((void *)this,ipheader, ipheader_len,
udp_src_port, udp_dst_port, &l4pkt[8], l4pkt_len-8);
} else {
BX_ERROR(("udp - unhandled port %u", udp_dst_port));
}
}
void bx_vnet_pktmover_c::host_to_guest_udpipv4_packet(
unsigned target_port, unsigned source_port,
const Bit8u *udpdata, unsigned udpdata_len)
{
Bit8u ipbuf[BX_PACKET_BUFSIZE];
if ((udpdata_len + 42U) > BX_PACKET_BUFSIZE) {
BX_PANIC(("generated udp data is too long"));
return;
}
// udp pseudo-header
ipbuf[34U-12U]=0;
ipbuf[34U-11U]=0x11; // UDP
put_net2(&ipbuf[34U-10U],8U+udpdata_len);
memcpy(&ipbuf[34U-8U],dhcp.host_ipv4addr,4);
memcpy(&ipbuf[34U-4U],dhcp.guest_ipv4addr,4);
// udp header
put_net2(&ipbuf[34U+0],source_port);
put_net2(&ipbuf[34U+2],target_port);
put_net2(&ipbuf[34U+4],8U+udpdata_len);
put_net2(&ipbuf[34U+6],0);
memcpy(&ipbuf[42U],udpdata,udpdata_len);
put_net2(&ipbuf[34U+6], ip_checksum(&ipbuf[34U-12U],12U+8U+udpdata_len) ^ (Bit16u)0xffff);
// ip header
memset(&ipbuf[14U],0,20U);
ipbuf[14U+0] = 0x45;
ipbuf[14U+1] = 0x00;
put_net2(&ipbuf[14U+2],20U+8U+udpdata_len);
put_net2(&ipbuf[14U+4],1);
ipbuf[14U+6] = 0x00;
ipbuf[14U+7] = 0x00;
ipbuf[14U+8] = 0x07; // TTL
ipbuf[14U+9] = 0x11; // UDP
host_to_guest_ipv4(ipbuf,udpdata_len + 42U);
}
/////////////////////////////////////////////////////////////////////////
// ICMP/IPv4
/////////////////////////////////////////////////////////////////////////
void bx_vnet_pktmover_c::process_icmpipv4_echo(
const Bit8u *ipheader, unsigned ipheader_len,
const Bit8u *l4pkt, unsigned l4pkt_len)
{
Bit8u replybuf[ICMP_ECHO_PACKET_MAX];
if (vnet_process_icmp_echo(ipheader, ipheader_len, l4pkt, l4pkt_len, replybuf)) {
host_to_guest_ipv4(replybuf, 14U+ipheader_len+l4pkt_len);
}
}
/////////////////////////////////////////////////////////////////////////
// DHCP/UDP/IPv4
/////////////////////////////////////////////////////////////////////////
void bx_vnet_pktmover_c::udpipv4_dhcp_handler(
void *this_ptr,
const Bit8u *ipheader, unsigned ipheader_len,
unsigned sourceport, unsigned targetport,
const Bit8u *data, unsigned data_len)
{
((bx_vnet_pktmover_c *)this_ptr)->udpipv4_dhcp_handler_ns(
ipheader,ipheader_len,sourceport,targetport,data,data_len);
}
void bx_vnet_pktmover_c::udpipv4_dhcp_handler_ns(
const Bit8u *ipheader, unsigned ipheader_len,
unsigned sourceport, unsigned targetport,
const Bit8u *data, unsigned data_len)
{
Bit8u replybuf[576];
unsigned opts_len;
opts_len = vnet_process_dhcp(netdev, data, data_len, replybuf, &dhcp);
if (opts_len > 0) {
host_to_guest_udpipv4_packet(sourceport, targetport, replybuf, opts_len);
}
}
void bx_vnet_pktmover_c::udpipv4_tftp_handler(
void *this_ptr,
const Bit8u *ipheader, unsigned ipheader_len,
unsigned sourceport, unsigned targetport,
const Bit8u *data, unsigned data_len)
{
((bx_vnet_pktmover_c *)this_ptr)->udpipv4_tftp_handler_ns(
ipheader,ipheader_len,sourceport,targetport,data,data_len);
}
void bx_vnet_pktmover_c::udpipv4_tftp_handler_ns(
const Bit8u *ipheader, unsigned ipheader_len,
unsigned sourceport, unsigned targetport,
const Bit8u *data, unsigned data_len)
{
Bit8u replybuf[TFTP_BUFFER_SIZE + 4];
int len;
len = vnet_process_tftp(netdev, data, data_len, sourceport, replybuf, tftp_rootdir);
if (len > 0) {
host_to_guest_udpipv4_packet(sourceport, targetport, replybuf, len);
}
}
#endif /* if BX_NETWORKING */