Some work on the eth_vnet and bxhub code to reduce code duplication. Moved some
shared functions to netmod.cc and modified ARP, IPv4 and ICMP code.
This commit is contained in:
parent
b25d050676
commit
0011092ddb
@ -2,7 +2,7 @@
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2005-2014 The Bochs Project
|
||||
// Copyright (C) 2005-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
|
||||
@ -110,7 +110,7 @@ public:
|
||||
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);
|
||||
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);
|
||||
@ -342,7 +342,7 @@ void bx_vnet_pktmover_c::rx_timer(void)
|
||||
}
|
||||
}
|
||||
|
||||
void bx_vnet_pktmover_c::host_to_guest(Bit8u *buf, unsigned io_len)
|
||||
void bx_vnet_pktmover_c::host_to_guest(Bit8u *buf, unsigned io_len, unsigned l3type)
|
||||
{
|
||||
Bit8u localbuf[60];
|
||||
|
||||
@ -351,15 +351,16 @@ void bx_vnet_pktmover_c::host_to_guest(Bit8u *buf, unsigned io_len)
|
||||
return;
|
||||
}
|
||||
|
||||
if (io_len < 60) {
|
||||
memcpy(&localbuf[0],&buf[0],io_len);
|
||||
memset(&localbuf[io_len],0,60-io_len);
|
||||
buf=localbuf;
|
||||
io_len=60;
|
||||
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);
|
||||
}
|
||||
@ -370,69 +371,48 @@ void bx_vnet_pktmover_c::host_to_guest(Bit8u *buf, unsigned io_len)
|
||||
|
||||
void bx_vnet_pktmover_c::process_arp(const Bit8u *buf, unsigned io_len)
|
||||
{
|
||||
unsigned opcode;
|
||||
unsigned protocol;
|
||||
Bit8u replybuf[MIN_RX_PACKET_LEN];
|
||||
|
||||
if (io_len < 22) return;
|
||||
if (io_len < (unsigned)(22+buf[18]*2+buf[19]*2)) return;
|
||||
// hardware:Ethernet
|
||||
if (buf[14] != 0x00 || buf[15] != 0x01 || buf[18] != 0x06) return;
|
||||
opcode = get_net2(&buf[20]);
|
||||
protocol = get_net2(&buf[16]);
|
||||
memset(&replybuf[0], 0, MIN_RX_PACKET_LEN);
|
||||
|
||||
// protocol
|
||||
switch (protocol) {
|
||||
case 0x0800: // IPv4
|
||||
if (buf[19] == 0x04) {
|
||||
switch (opcode) {
|
||||
case 0x0001: // ARP REQUEST
|
||||
if (!memcmp(&buf[22],&dhcp.guest_macaddr[0],6)) {
|
||||
memcpy(&dhcp.guest_ipv4addr[0],&buf[28],4);
|
||||
if (!memcmp(&buf[38],&dhcp.host_ipv4addr[0],4)) {
|
||||
memcpy(&replybuf[14],&buf[14],6);
|
||||
replybuf[20]=0x00;
|
||||
replybuf[21]=0x02;
|
||||
memcpy(&replybuf[22],&dhcp.host_macaddr[0],6);
|
||||
memcpy(&replybuf[28],&dhcp.host_ipv4addr[0],4);
|
||||
memcpy(&replybuf[32],&dhcp.guest_macaddr[0],6);
|
||||
memcpy(&replybuf[38],&dhcp.guest_ipv4addr[0],4);
|
||||
arp_header_t *arphdr = (arp_header_t *)((Bit8u *)buf +
|
||||
sizeof(ethernet_header_t));
|
||||
|
||||
host_to_guest_arp(replybuf, MIN_RX_PACKET_LEN);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x0002: // ARP REPLY
|
||||
BX_INFO(("unexpected ARP REPLY"));
|
||||
break;
|
||||
case 0x0003: // RARP REQUEST
|
||||
BX_ERROR(("RARP is not implemented"));
|
||||
break;
|
||||
case 0x0004: // RARP REPLY
|
||||
BX_INFO(("unexpected RARP REPLY"));
|
||||
break;
|
||||
default:
|
||||
BX_INFO(("arp: unknown ARP opcode %04x", opcode));
|
||||
break;
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
BX_INFO(("arp: unknown address length %u", (unsigned)buf[19]));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BX_INFO(("arp: unknown protocol 0x%04x", protocol));
|
||||
break;
|
||||
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)
|
||||
{
|
||||
memcpy(&buf[0],&dhcp.guest_macaddr[0],6);
|
||||
memcpy(&buf[6],&dhcp.host_macaddr[0],6);
|
||||
buf[12]=0x08;
|
||||
buf[13]=0x06;
|
||||
host_to_guest(buf,io_len);
|
||||
host_to_guest(buf, io_len, ETHERNET_TYPE_ARP);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
@ -442,23 +422,21 @@ void bx_vnet_pktmover_c::host_to_guest_arp(Bit8u *buf, unsigned io_len)
|
||||
void bx_vnet_pktmover_c::process_ipv4(const Bit8u *buf, unsigned io_len)
|
||||
{
|
||||
unsigned total_len;
|
||||
// unsigned packet_id;
|
||||
unsigned fragment_flags;
|
||||
unsigned fragment_offset;
|
||||
unsigned ipproto;
|
||||
unsigned l3header_len;
|
||||
const Bit8u *l4pkt;
|
||||
unsigned l4pkt_len;
|
||||
|
||||
if (io_len < (14U+20U)) {
|
||||
BX_INFO(("ip packet - too small packet"));
|
||||
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_INFO(("ipv%u packet - not implemented", iphdr->version));
|
||||
BX_ERROR(("ipv%u packet - not implemented", iphdr->version));
|
||||
return;
|
||||
}
|
||||
l3header_len = (iphdr->header_len << 2);
|
||||
@ -466,24 +444,19 @@ void bx_vnet_pktmover_c::process_ipv4(const Bit8u *buf, unsigned io_len)
|
||||
BX_ERROR(("ip: option header is not implemented"));
|
||||
return;
|
||||
}
|
||||
if (io_len < (14U+l3header_len)) return;
|
||||
if (ip_checksum((Bit8u*)iphdr, l3header_len) != (Bit16u)0xffff) {
|
||||
BX_INFO(("ip: invalid checksum"));
|
||||
BX_ERROR(("ip: invalid checksum"));
|
||||
return;
|
||||
}
|
||||
|
||||
total_len = ntohs(iphdr->total_len);
|
||||
|
||||
// FIXED By EaseWay
|
||||
// Ignore this check to tolerant some cases
|
||||
//if (io_len > (14U+total_len)) return;
|
||||
|
||||
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_INFO(("target IP address %u.%u.%u.%u is unknown",
|
||||
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;
|
||||
@ -491,29 +464,28 @@ void bx_vnet_pktmover_c::process_ipv4(const Bit8u *buf, unsigned io_len)
|
||||
|
||||
fragment_flags = ntohs(iphdr->frag_offs) >> 13;
|
||||
fragment_offset = (ntohs(iphdr->frag_offs) & 0x1fff) << 3;
|
||||
ipproto = iphdr->protocol;
|
||||
|
||||
if ((fragment_flags & 0x1) || (fragment_offset != 0)) {
|
||||
BX_INFO(("ignore fragmented packet!"));
|
||||
BX_ERROR(("ignore fragmented packet!"));
|
||||
return;
|
||||
} else {
|
||||
l4pkt = &buf[14 + l3header_len];
|
||||
l4pkt_len = total_len - l3header_len;
|
||||
}
|
||||
|
||||
switch (ipproto) {
|
||||
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_INFO(("unknown IP protocol %02x",ipproto));
|
||||
break;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -521,10 +493,6 @@ void bx_vnet_pktmover_c::host_to_guest_ipv4(Bit8u *buf, unsigned io_len)
|
||||
{
|
||||
unsigned l3header_len;
|
||||
|
||||
memcpy(&buf[0],&dhcp.guest_macaddr[0],6);
|
||||
memcpy(&buf[6],&dhcp.host_macaddr[0],6);
|
||||
buf[12]=0x08;
|
||||
buf[13]=0x00;
|
||||
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);
|
||||
@ -532,7 +500,7 @@ void bx_vnet_pktmover_c::host_to_guest_ipv4(Bit8u *buf, unsigned io_len)
|
||||
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);
|
||||
host_to_guest(buf, io_len, ETHERNET_TYPE_IPV4);
|
||||
}
|
||||
|
||||
layer4_handler_t bx_vnet_pktmover_c::get_layer4_handler(
|
||||
@ -552,8 +520,8 @@ 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_INFO(("IP protocol 0x%02x port %u is already in use",
|
||||
ipprotocol,port));
|
||||
BX_ERROR(("IP protocol 0x%02x port %u is already in use",
|
||||
ipprotocol, port));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -608,7 +576,7 @@ void bx_vnet_pktmover_c::process_icmpipv4(
|
||||
icmptype = l4pkt[0];
|
||||
icmpcode = l4pkt[1];
|
||||
if (ip_checksum(l4pkt,l4pkt_len) != (Bit16u)0xffff) {
|
||||
BX_INFO(("icmp: invalid checksum"));
|
||||
BX_ERROR(("icmp: invalid checksum"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -619,8 +587,8 @@ void bx_vnet_pktmover_c::process_icmpipv4(
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BX_INFO(("unhandled icmp packet: type=%u code=%u",
|
||||
icmptype, icmpcode));
|
||||
BX_ERROR(("unhandled icmp packet: type=%u code=%u",
|
||||
icmptype, icmpcode));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -631,7 +599,7 @@ void bx_vnet_pktmover_c::process_tcpipv4(
|
||||
{
|
||||
if (l4pkt_len < 20) return;
|
||||
|
||||
BX_INFO(("tcp packet - not implemented"));
|
||||
BX_ERROR(("tcp packet - not implemented"));
|
||||
}
|
||||
|
||||
void bx_vnet_pktmover_c::process_udpipv4(
|
||||
@ -654,7 +622,7 @@ void bx_vnet_pktmover_c::process_udpipv4(
|
||||
(*func)((void *)this,ipheader, ipheader_len,
|
||||
udp_sourceport, udp_targetport, &l4pkt[8], l4pkt_len-8);
|
||||
} else {
|
||||
BX_INFO(("udp - unhandled port %u", udp_targetport));
|
||||
BX_ERROR(("udp - unhandled port %u", udp_targetport));
|
||||
}
|
||||
}
|
||||
|
||||
@ -706,20 +674,9 @@ void bx_vnet_pktmover_c::process_icmpipv4_echo(
|
||||
{
|
||||
Bit8u replybuf[ICMP_ECHO_PACKET_MAX];
|
||||
|
||||
if ((14U+ipheader_len+l4pkt_len) > ICMP_ECHO_PACKET_MAX) {
|
||||
BX_ERROR(("icmp echo: size of an echo packet is too long"));
|
||||
return;
|
||||
if (vnet_process_icmp_echo(ipheader, ipheader_len, l4pkt, l4pkt_len, replybuf)) {
|
||||
host_to_guest_ipv4(replybuf, 14U+ipheader_len+l4pkt_len);
|
||||
}
|
||||
|
||||
memcpy(&replybuf[14],ipheader,ipheader_len);
|
||||
memcpy(&replybuf[14+ipheader_len],l4pkt,l4pkt_len);
|
||||
|
||||
replybuf[14+ipheader_len+0] = 0x00; // echo reply
|
||||
put_net2(&replybuf[14+ipheader_len+2],0);
|
||||
put_net2(&replybuf[14+ipheader_len+2],
|
||||
ip_checksum(&replybuf[14+ipheader_len],l4pkt_len) ^ (Bit16u)0xffff);
|
||||
|
||||
host_to_guest_ipv4(replybuf,14U+ipheader_len+l4pkt_len);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
@ -744,7 +701,7 @@ void bx_vnet_pktmover_c::udpipv4_dhcp_handler_ns(
|
||||
Bit8u replybuf[576];
|
||||
unsigned opts_len;
|
||||
|
||||
opts_len = process_dhcp(netdev, data, data_len, replybuf, &dhcp);
|
||||
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);
|
||||
}
|
||||
@ -768,7 +725,7 @@ void bx_vnet_pktmover_c::udpipv4_tftp_handler_ns(
|
||||
Bit8u replybuf[TFTP_BUFFER_SIZE + 4];
|
||||
int len;
|
||||
|
||||
len = process_tftp(netdev, data, data_len, sourceport, replybuf, tftp_rootdir);
|
||||
len = vnet_process_tftp(netdev, data, data_len, sourceport, replybuf, tftp_rootdir);
|
||||
if (len > 0) {
|
||||
host_to_guest_udpipv4_packet(sourceport, targetport, replybuf, len);
|
||||
}
|
||||
|
@ -376,10 +376,55 @@ Bit16u ip_checksum(const Bit8u *buf, unsigned buf_len)
|
||||
static const Bit8u subnetmask_ipv4addr[4] = {0xff,0xff,0xff,0x00};
|
||||
static const Bit8u broadcast_ipv4addr1[4] = {0xff,0xff,0xff,0xff};
|
||||
|
||||
void vnet_prepare_reply(Bit8u *replybuf, unsigned l3type, dhcp_cfg_t *dhcpc)
|
||||
{
|
||||
ethernet_header_t *ethhdr = (ethernet_header_t *)replybuf;
|
||||
|
||||
memcpy(ethhdr->dst_mac_addr, dhcpc->guest_macaddr, ETHERNET_MAC_ADDR_LEN);
|
||||
memcpy(ethhdr->src_mac_addr, dhcpc->host_macaddr, ETHERNET_MAC_ADDR_LEN);
|
||||
ethhdr->type = htons(l3type);
|
||||
}
|
||||
|
||||
bx_bool vnet_process_arp_request(const Bit8u *buf, Bit8u *reply, dhcp_cfg_t *dhcp)
|
||||
{
|
||||
arp_header_t *arprhdr = (arp_header_t *)(reply + sizeof(ethernet_header_t));
|
||||
|
||||
if (!memcmp(&buf[22], dhcp->guest_macaddr, 6)) {
|
||||
memcpy(dhcp->guest_ipv4addr, &buf[28], 4);
|
||||
if (!memcmp(&buf[38], dhcp->host_ipv4addr, 4)) {
|
||||
memset(reply, 0, MIN_RX_PACKET_LEN);
|
||||
memcpy(arprhdr, &buf[14], 6);
|
||||
arprhdr->opcode = htons(ARP_OPCODE_REPLY);
|
||||
memcpy((Bit8u *)arprhdr+8, dhcp->host_macaddr, ETHERNET_MAC_ADDR_LEN);
|
||||
memcpy((Bit8u *)arprhdr+14, dhcp->host_ipv4addr, 4);
|
||||
memcpy((Bit8u *)arprhdr+18, dhcp->guest_macaddr, ETHERNET_MAC_ADDR_LEN);
|
||||
memcpy((Bit8u *)arprhdr+24, dhcp->guest_ipv4addr, 4);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bx_bool vnet_process_icmp_echo(const Bit8u *l3pkt, unsigned l3header_len,
|
||||
const Bit8u *l4pkt, unsigned l4pkt_len,
|
||||
Bit8u *reply)
|
||||
{
|
||||
if ((14U+l3header_len+l4pkt_len) > ICMP_ECHO_PACKET_MAX) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(&reply[14], l3pkt, l3header_len);
|
||||
memcpy(&reply[14+l3header_len], l4pkt, l4pkt_len);
|
||||
reply[14+l3header_len+0] = 0x00; // echo reply
|
||||
put_net2(&reply[14+l3header_len+2],0);
|
||||
put_net2(&reply[14+l3header_len+2],
|
||||
ip_checksum(&reply[14+l3header_len],l4pkt_len) ^ (Bit16u)0xffff);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef BXHUB
|
||||
int process_dhcp(bx_devmodel_c *netdev, const Bit8u *data, unsigned data_len, Bit8u *reply, dhcp_cfg_t *dhcp)
|
||||
int vnet_process_dhcp(bx_devmodel_c *netdev, const Bit8u *data, unsigned data_len, Bit8u *reply, dhcp_cfg_t *dhcp)
|
||||
#else
|
||||
int process_dhcp(const Bit8u *data, unsigned data_len, Bit8u *reply, dhcp_cfg_t *dhcp)
|
||||
int vnet_process_dhcp(const Bit8u *data, unsigned data_len, Bit8u *reply, dhcp_cfg_t *dhcp)
|
||||
#endif
|
||||
{
|
||||
const Bit8u *opts;
|
||||
@ -926,9 +971,9 @@ void tftp_parse_options(const char *mode, const Bit8u *data, unsigned data_len,
|
||||
}
|
||||
|
||||
#ifndef BXHUB
|
||||
int process_tftp(bx_devmodel_c *netdev, const Bit8u *data, unsigned data_len, Bit16u req_tid, Bit8u *reply, const char *tftp_rootdir)
|
||||
int vnet_process_tftp(bx_devmodel_c *netdev, const Bit8u *data, unsigned data_len, Bit16u req_tid, Bit8u *reply, const char *tftp_rootdir)
|
||||
#else
|
||||
int process_tftp(const Bit8u *data, unsigned data_len, Bit16u req_tid, Bit8u *reply, const char *tftp_rootdir)
|
||||
int vnet_process_tftp(const Bit8u *data, unsigned data_len, Bit16u req_tid, Bit8u *reply, const char *tftp_rootdir)
|
||||
#endif
|
||||
{
|
||||
FILE *fp;
|
||||
|
@ -2,7 +2,7 @@
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2013 The Bochs Project
|
||||
// Copyright (C) 2001-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
|
||||
@ -53,6 +53,13 @@ public:
|
||||
#define ETHERNET_TYPE_IPV4 0x0800
|
||||
#define ETHERNET_TYPE_ARP 0x0806
|
||||
|
||||
#define ARP_OPCODE_REQUEST 1
|
||||
#define ARP_OPCODE_REPLY 2
|
||||
#define ARP_OPCODE_REV_REQUEST 3
|
||||
#define ARP_OPCODE_REV_REPLY 4
|
||||
|
||||
#define ICMP_ECHO_PACKET_MAX 128
|
||||
|
||||
#define TFTP_BUFFER_SIZE 1024
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
@ -74,6 +81,25 @@ typedef struct ethernet_header {
|
||||
#endif
|
||||
ethernet_header_t;
|
||||
|
||||
typedef struct arp_header {
|
||||
#if defined(_MSC_VER) && (_MSC_VER>=1300)
|
||||
__declspec(align(1))
|
||||
#endif
|
||||
Bit16u hw_addr_space;
|
||||
Bit16u proto_addr_space;
|
||||
Bit8u hw_addr_len;
|
||||
Bit8u proto_addr_len;
|
||||
Bit16u opcode;
|
||||
/* HW address of sender */
|
||||
/* Protocol address of sender */
|
||||
/* HW address of target*/
|
||||
/* Protocol address of target */
|
||||
}
|
||||
#if !defined(_MSC_VER)
|
||||
GCC_ATTRIBUTE((packed))
|
||||
#endif
|
||||
arp_header_t;
|
||||
|
||||
typedef struct ip_header {
|
||||
#if defined(_MSC_VER) && (_MSC_VER>=1300)
|
||||
__declspec(align(1))
|
||||
@ -167,13 +193,23 @@ BX_CPP_INLINE void put_net4(Bit8u *buf,Bit32u data)
|
||||
*(buf+3) = (Bit8u)(data & 0xff);
|
||||
}
|
||||
|
||||
// vnet code shared with bxhub
|
||||
Bit16u ip_checksum(const Bit8u *buf, unsigned buf_len);
|
||||
void vnet_prepare_reply(Bit8u *replybuf, unsigned l3type, dhcp_cfg_t *dhcpc);
|
||||
bx_bool vnet_process_arp_request(const Bit8u *buf, Bit8u *reply, dhcp_cfg_t *dhcp);
|
||||
bx_bool vnet_process_icmp_echo(const Bit8u *l3pkt, unsigned l3header_len,
|
||||
const Bit8u *l4pkt, unsigned l4pkt_len,
|
||||
Bit8u *reply);
|
||||
#ifdef BXHUB
|
||||
int process_dhcp(const Bit8u *data, unsigned data_len, Bit8u *reply, dhcp_cfg_t *dhcp);
|
||||
int process_tftp(const Bit8u *data, unsigned data_len, Bit16u req_tid, Bit8u *reply, const char *tftp_rootdir);
|
||||
int vnet_process_dhcp(const Bit8u *data, unsigned data_len, Bit8u *reply,
|
||||
dhcp_cfg_t *dhcp);
|
||||
int vnet_process_tftp(const Bit8u *data, unsigned data_len, Bit16u req_tid,
|
||||
Bit8u *reply, const char *tftp_rootdir);
|
||||
#else
|
||||
int process_dhcp(bx_devmodel_c *netdev, const Bit8u *data, unsigned data_len, Bit8u *reply, dhcp_cfg_t *dhcp);
|
||||
int process_tftp(bx_devmodel_c *netdev, const Bit8u *data, unsigned data_len, Bit16u req_tid, Bit8u *reply, const char *tftp_rootdir);
|
||||
int vnet_process_dhcp(bx_devmodel_c *netdev, const Bit8u *data, unsigned data_len,
|
||||
Bit8u *reply, dhcp_cfg_t *dhcp);
|
||||
int vnet_process_tftp(bx_devmodel_c *netdev, const Bit8u *data, unsigned data_len,
|
||||
Bit16u req_tid, Bit8u *reply, const char *tftp_rootdir);
|
||||
|
||||
//
|
||||
// The eth_pktmover class is used by ethernet chip emulations
|
||||
|
@ -60,30 +60,6 @@ typedef int SOCKET;
|
||||
|
||||
#define BUFSIZE 4096
|
||||
|
||||
#define ICMP_ECHO_PACKET_MAX 128
|
||||
|
||||
#define ARP_OPCODE_REQUEST 1
|
||||
#define ARP_OPCODE_REPLY 2
|
||||
|
||||
typedef struct arp_header {
|
||||
#if defined(_MSC_VER) && (_MSC_VER>=1300)
|
||||
__declspec(align(1))
|
||||
#endif
|
||||
Bit16u hw_addr_space;
|
||||
Bit16u proto_addr_space;
|
||||
Bit8u hw_addr_len;
|
||||
Bit8u proto_addr_len;
|
||||
Bit16u opcode;
|
||||
/* HW address of sender */
|
||||
/* Protocol address of sender */
|
||||
/* HW address of target*/
|
||||
/* Protocol address of target */
|
||||
}
|
||||
#if !defined(_MSC_VER)
|
||||
GCC_ATTRIBUTE((packed))
|
||||
#endif
|
||||
arp_header_t;
|
||||
|
||||
typedef struct {
|
||||
SOCKET so;
|
||||
struct sockaddr_in sin, sout;
|
||||
@ -95,7 +71,6 @@ typedef struct {
|
||||
|
||||
const Bit8u default_host_macaddr[6] = {0xb0, 0xc4, 0x20, 0x00, 0x00, 0x03};
|
||||
const Bit8u default_host_ipv4addr[4] = {10, 0, 2, 2};
|
||||
const Bit8u default_dns_ipv4addr[4] = {10, 0, 2, 3};
|
||||
|
||||
const Bit8u default_guest_ipv4addr[2][4] =
|
||||
{
|
||||
@ -116,22 +91,11 @@ static Bit8u host_macaddr[6];
|
||||
static int client_count;
|
||||
|
||||
|
||||
void prepare_builtin_reply(hub_client_t *client, unsigned type)
|
||||
{
|
||||
dhcp_cfg_t *dhcpc = &client->dhcp;
|
||||
ethernet_header_t *ethhdr = (ethernet_header_t *)client->reply_buffer;
|
||||
|
||||
memcpy(ethhdr->dst_mac_addr, dhcpc->guest_macaddr, ETHERNET_MAC_ADDR_LEN);
|
||||
memcpy(ethhdr->src_mac_addr, dhcpc->host_macaddr, ETHERNET_MAC_ADDR_LEN);
|
||||
ethhdr->type = htons(type);
|
||||
}
|
||||
|
||||
bx_bool handle_ipv4(hub_client_t *client, Bit8u *buf, unsigned len)
|
||||
{
|
||||
unsigned total_len;
|
||||
unsigned fragment_flags;
|
||||
unsigned fragment_offset;
|
||||
unsigned ipproto;
|
||||
unsigned l3header_len;
|
||||
const Bit8u *l4pkt;
|
||||
unsigned l4pkt_len;
|
||||
@ -147,49 +111,50 @@ bx_bool handle_ipv4(hub_client_t *client, Bit8u *buf, unsigned len)
|
||||
if (len < (14U+20U)) {
|
||||
return 0;
|
||||
}
|
||||
if ((buf[14+0] & 0xf0) != 0x40) {
|
||||
|
||||
ip_header_t *iphdr = (ip_header_t *)((Bit8u *)buf +
|
||||
sizeof(ethernet_header_t));
|
||||
if (iphdr->version != 4) {
|
||||
return 0;
|
||||
}
|
||||
l3header_len = ((unsigned)(buf[14+0] & 0x0f) << 2);
|
||||
l3header_len = (iphdr->header_len << 2);
|
||||
if (l3header_len != 20) {
|
||||
return 0;
|
||||
}
|
||||
if (len < (14U+l3header_len)) return 0;
|
||||
if (ip_checksum(&buf[14],l3header_len) != (Bit16u)0xffff) {
|
||||
if (ip_checksum((Bit8u*)iphdr, l3header_len) != (Bit16u)0xffff) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
total_len = get_net2(&buf[14+2]);
|
||||
total_len = ntohs(iphdr->total_len);
|
||||
|
||||
if (memcmp(&buf[14+16],dhcpc->host_ipv4addr, 4) &&
|
||||
memcmp(&buf[14+16],broadcast_ipv4addr[0],4) &&
|
||||
memcmp(&buf[14+16],broadcast_ipv4addr[1],4) &&
|
||||
memcmp(&buf[14+16],broadcast_ipv4addr[2],4))
|
||||
if (memcmp(&iphdr->dst_addr, dhcpc->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))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
fragment_flags = (unsigned)buf[14+6] >> 5;
|
||||
fragment_offset = ((unsigned)get_net2(&buf[14+6]) & 0x1fff) << 3;
|
||||
ipproto = buf[14+9];
|
||||
fragment_flags = ntohs(iphdr->frag_offs) >> 13;
|
||||
fragment_offset = (ntohs(iphdr->frag_offs) & 0x1fff) << 3;
|
||||
|
||||
if ((fragment_flags & 0x1) || (fragment_offset != 0)) {
|
||||
return 0;
|
||||
} else {
|
||||
l4pkt = &buf[14 + l3header_len];
|
||||
l4pkt_len = total_len - l3header_len;
|
||||
}
|
||||
|
||||
if (ipproto == 0x11) {
|
||||
l4pkt = &buf[14 + l3header_len];
|
||||
l4pkt_len = total_len - l3header_len;
|
||||
|
||||
if (iphdr->protocol == 0x11) {
|
||||
// guest-to-host UDP IPv4
|
||||
if (l4pkt_len < 8) return 0;
|
||||
udp_sourceport = get_net2(&l4pkt[0]);
|
||||
udp_targetport = get_net2(&l4pkt[2]);
|
||||
if ((udp_targetport == 67) || (udp_targetport == 69)) { // BOOTP & TFTP
|
||||
if (udp_targetport == 67) { // BOOTP
|
||||
udp_reply_size = process_dhcp(&l4pkt[8], l4pkt_len-8, &replybuf[42], dhcpc);
|
||||
udp_reply_size = vnet_process_dhcp(&l4pkt[8], l4pkt_len-8, &replybuf[42], dhcpc);
|
||||
} else if (strlen(tftp_root) > 0) {
|
||||
udp_reply_size = process_tftp(&l4pkt[8], l4pkt_len-8, udp_sourceport, &replybuf[42], tftp_root);
|
||||
udp_reply_size = vnet_process_tftp(&l4pkt[8], l4pkt_len-8, udp_sourceport, &replybuf[42], tftp_root);
|
||||
}
|
||||
if (udp_reply_size > 0) {
|
||||
// host-to-guest UDP IPv4: pseudo-header
|
||||
@ -215,61 +180,45 @@ bx_bool handle_ipv4(hub_client_t *client, Bit8u *buf, unsigned len)
|
||||
replybuf[21] = 0x00;
|
||||
replybuf[22] = 0x07; // TTL
|
||||
replybuf[23] = 0x11; // UDP
|
||||
// host-to-guest IPv4
|
||||
replybuf[14] = (replybuf[14] & 0x0f) | 0x40;
|
||||
l3header_len = ((unsigned)(replybuf[14] & 0x0f) << 2);
|
||||
memcpy(&replybuf[26], dhcpc->host_ipv4addr, 4);
|
||||
memcpy(&replybuf[30], dhcpc->guest_ipv4addr, 4);
|
||||
put_net2(&replybuf[24], 0);
|
||||
put_net2(&replybuf[24], ip_checksum(&replybuf[14], l3header_len) ^ (Bit16u)0xffff);
|
||||
client->pending_reply_size = udp_reply_size + 42;
|
||||
prepare_builtin_reply(client, ETHERNET_TYPE_IPV4);
|
||||
}
|
||||
// don't forward DHCP / TFTP requests to other client
|
||||
return 1;
|
||||
}
|
||||
} else if (ipproto == 0x01) {
|
||||
} else if (iphdr->protocol == 0x01) {
|
||||
// guest-to-host ICMP
|
||||
if (l4pkt_len < 8) return 0;
|
||||
icmptype = l4pkt[0];
|
||||
icmpcode = l4pkt[1];
|
||||
if (ip_checksum(l4pkt,l4pkt_len) != (Bit16u)0xffff) {
|
||||
BX_ERROR(("icmp: invalid checksum"));
|
||||
if (ip_checksum(l4pkt, l4pkt_len) != (Bit16u)0xffff) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (icmptype) {
|
||||
case 0x08: // ECHO
|
||||
if (icmpcode == 0) {
|
||||
if ((14U+l3header_len+l4pkt_len) > ICMP_ECHO_PACKET_MAX) {
|
||||
BX_ERROR(("icmp echo: size of an echo packet is too long"));
|
||||
return 0;
|
||||
if (vnet_process_icmp_echo(&buf[14], l3header_len, l4pkt, l4pkt_len,
|
||||
replybuf)) {
|
||||
client->pending_reply_size = 14U+l3header_len+l4pkt_len;
|
||||
}
|
||||
memcpy(&replybuf[14], &buf[14], l3header_len);
|
||||
memcpy(&replybuf[14+l3header_len], l4pkt, l4pkt_len);
|
||||
replybuf[14+l3header_len+0] = 0x00; // echo reply
|
||||
put_net2(&replybuf[14+l3header_len+2],0);
|
||||
put_net2(&replybuf[14+l3header_len+2],
|
||||
ip_checksum(&replybuf[14+l3header_len],l4pkt_len) ^ (Bit16u)0xffff);
|
||||
// host-to-guest IPv4
|
||||
replybuf[14] = (replybuf[14] & 0x0f) | 0x40;
|
||||
l3header_len = ((unsigned)(replybuf[14] & 0x0f) << 2);
|
||||
memcpy(&replybuf[26], dhcpc->host_ipv4addr, 4);
|
||||
memcpy(&replybuf[30], dhcpc->guest_ipv4addr, 4);
|
||||
put_net2(&replybuf[24], 0);
|
||||
put_net2(&replybuf[24], ip_checksum(&replybuf[14], l3header_len) ^ (Bit16u)0xffff);
|
||||
client->pending_reply_size = 14U+l3header_len+l4pkt_len;
|
||||
prepare_builtin_reply(client, ETHERNET_TYPE_IPV4);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BX_INFO(("unhandled icmp packet: type=%u code=%u",
|
||||
icmptype, icmpcode));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
if (client->pending_reply_size > 0) {
|
||||
// host-to-guest IPv4
|
||||
replybuf[14] = (replybuf[14] & 0x0f) | 0x40;
|
||||
l3header_len = ((unsigned)(replybuf[14] & 0x0f) << 2);
|
||||
memcpy(&replybuf[26], dhcpc->host_ipv4addr, 4);
|
||||
memcpy(&replybuf[30], dhcpc->guest_ipv4addr, 4);
|
||||
put_net2(&replybuf[24], 0);
|
||||
put_net2(&replybuf[24], ip_checksum(&replybuf[14], l3header_len) ^ (Bit16u)0xffff);
|
||||
vnet_prepare_reply(replybuf, ETHERNET_TYPE_IPV4, dhcpc);
|
||||
// don't forward to other client
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bx_bool handle_arp(hub_client_t *client, Bit8u *buf, unsigned len)
|
||||
@ -277,38 +226,25 @@ bx_bool handle_arp(hub_client_t *client, Bit8u *buf, unsigned len)
|
||||
dhcp_cfg_t *dhcpc = &client->dhcp;
|
||||
arp_header_t *arphdr = (arp_header_t *)((Bit8u *)buf +
|
||||
sizeof(ethernet_header_t));
|
||||
arp_header_t *arprhdr = (arp_header_t *)((Bit8u *)client->reply_buffer +
|
||||
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)) {
|
||||
fprintf(stderr, "Unhandled ARP message hw: %04x (%d) proto: %04x (%d)\n",
|
||||
ntohs(arphdr->hw_addr_space), arphdr->hw_addr_len,
|
||||
ntohs(arphdr->proto_addr_space), arphdr->proto_addr_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch(ntohs(arphdr->opcode)) {
|
||||
case ARP_OPCODE_REQUEST:
|
||||
if (((Bit8u *)arphdr)[27] > 3)
|
||||
break;
|
||||
memset(client->reply_buffer, 0, MIN_RX_PACKET_LEN);
|
||||
arprhdr->hw_addr_space = htons(0x0001);
|
||||
arprhdr->proto_addr_space = htons(0x0800);
|
||||
arprhdr->hw_addr_len = ETHERNET_MAC_ADDR_LEN;
|
||||
arprhdr->proto_addr_len = 4;
|
||||
arprhdr->opcode = htons(ARP_OPCODE_REPLY);
|
||||
memcpy((Bit8u *)arprhdr+8, dhcpc->host_macaddr, ETHERNET_MAC_ADDR_LEN);
|
||||
memcpy((Bit8u *)arprhdr+14, (Bit8u *)arphdr+24, 4);
|
||||
memcpy((Bit8u *)arprhdr+18, dhcpc->guest_macaddr, ETHERNET_MAC_ADDR_LEN);
|
||||
memcpy((Bit8u *)arprhdr+24, (Bit8u *)arphdr+14, 4);
|
||||
client->pending_reply_size = MIN_RX_PACKET_LEN;
|
||||
prepare_builtin_reply(client, ETHERNET_TYPE_ARP);
|
||||
return 1;
|
||||
case ARP_OPCODE_REPLY:
|
||||
if (vnet_process_arp_request(buf, client->reply_buffer, dhcpc)) {
|
||||
client->pending_reply_size = MIN_RX_PACKET_LEN;
|
||||
vnet_prepare_reply(client->reply_buffer, ETHERNET_TYPE_ARP, dhcpc);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case ARP_OPCODE_REPLY:
|
||||
case ARP_OPCODE_REV_REQUEST:
|
||||
case ARP_OPCODE_REV_REPLY:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -330,7 +266,6 @@ int handle_packet(hub_client_t *client, Bit8u *buf, unsigned len)
|
||||
memcpy(dhcpc->host_ipv4addr, &default_host_ipv4addr[0], 4);
|
||||
memcpy(dhcpc->guest_ipv4addr, &broadcast_ipv4addr[1][0], 4);
|
||||
dhcpc->default_guest_ipv4addr = default_guest_ipv4addr[client_count++];
|
||||
memcpy(dhcpc->dns_ipv4addr, &default_dns_ipv4addr[0], 4);
|
||||
client->reply_buffer = new Bit8u[BUFSIZE];
|
||||
client->init = 1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user