Crude mac address translation, fixes networking in Windows 2000 and SerenityOS
This commit is contained in:
parent
bca3648fd2
commit
f33c7ca70b
|
@ -223,6 +223,7 @@
|
|||
memory_size: 512 * 1024 * 1024,
|
||||
state: { url: host + "serenity_state-v3.bin.zst", },
|
||||
homepage: "https://serenityos.org/",
|
||||
mac_address_translation: true,
|
||||
},
|
||||
{
|
||||
id: "serenity-boot",
|
||||
|
@ -577,7 +578,7 @@
|
|||
state: {
|
||||
"url": host + "windows98_state.bin.zst",
|
||||
},
|
||||
preserve_mac_from_state_image: true,
|
||||
mac_address_translation: true,
|
||||
},
|
||||
{
|
||||
id: "windows98-boot",
|
||||
|
@ -683,7 +684,7 @@
|
|||
state: {
|
||||
"url": host + "reactos_state.bin.zst",
|
||||
},
|
||||
preserve_mac_from_state_image: true,
|
||||
mac_address_translation: true,
|
||||
name: "ReactOS",
|
||||
homepage: "https://reactos.org/",
|
||||
},
|
||||
|
@ -1002,7 +1003,7 @@
|
|||
settings.initrd = infos.initrd;
|
||||
settings.cmdline = infos.cmdline;
|
||||
settings.bzimage_initrd_from_filesystem = infos.bzimage_initrd_from_filesystem;
|
||||
settings.preserve_mac_from_state_image = infos.preserve_mac_from_state_image;
|
||||
settings.mac_address_translation = infos.mac_address_translation;
|
||||
|
||||
settings.acpi = (!infos.state && settings.acpi !== undefined) ? settings.acpi : infos.acpi;
|
||||
settings.memory_size = (!infos.state && settings.memory_size) ? settings.memory_size : infos.memory_size;
|
||||
|
@ -1238,7 +1239,7 @@
|
|||
"initial_state": settings.initial_state,
|
||||
"filesystem": settings.filesystem || {},
|
||||
"disable_speaker": disable_audio,
|
||||
"preserve_mac_from_state_image": settings.preserve_mac_from_state_image,
|
||||
"mac_address_translation": settings.mac_address_translation,
|
||||
|
||||
"autostart": true,
|
||||
});
|
||||
|
|
|
@ -265,6 +265,7 @@ V86Starter.prototype.continue_init = async function(emulator, options)
|
|||
settings.uart3 = options["uart3"];
|
||||
settings.cmdline = options["cmdline"];
|
||||
settings.preserve_mac_from_state_image = options["preserve_mac_from_state_image"];
|
||||
settings.mac_address_translation = options["mac_address_translation"];
|
||||
|
||||
if(options["network_adapter"])
|
||||
{
|
||||
|
|
|
@ -874,7 +874,7 @@ CPU.prototype.init = function(settings, device_bus)
|
|||
|
||||
if(settings.enable_ne2k)
|
||||
{
|
||||
this.devices.net = new Ne2k(this, device_bus, settings.preserve_mac_from_state_image);
|
||||
this.devices.net = new Ne2k(this, device_bus, settings.preserve_mac_from_state_image, settings.mac_address_translation);
|
||||
}
|
||||
|
||||
if(settings.fs9p)
|
||||
|
|
174
src/ne2k.js
174
src/ne2k.js
|
@ -56,13 +56,154 @@ const NE2K_LOG_PACKETS = false;
|
|||
/** @const */ var STOP_PAGE = 0x80;
|
||||
|
||||
|
||||
// Search and replace MAC addresses in ethernet, arp and dhcp packets.
|
||||
// Used after restoring an OS from memory dump, so that multiple instances of
|
||||
// that OS can run at the same time with different external MAC addresses.
|
||||
// Crude but seems to work.
|
||||
function translate_mac_address(packet, search_mac, replacement_mac)
|
||||
{
|
||||
if(packet[0] === search_mac[0] &&
|
||||
packet[1] === search_mac[1] &&
|
||||
packet[2] === search_mac[2] &&
|
||||
packet[3] === search_mac[3] &&
|
||||
packet[4] === search_mac[4] &&
|
||||
packet[5] === search_mac[5])
|
||||
{
|
||||
dbg_log("Replace mac in eth destination field", LOG_NET);
|
||||
|
||||
packet[0] = replacement_mac[0];
|
||||
packet[1] = replacement_mac[1];
|
||||
packet[2] = replacement_mac[2];
|
||||
packet[3] = replacement_mac[3];
|
||||
packet[4] = replacement_mac[4];
|
||||
packet[5] = replacement_mac[5];
|
||||
}
|
||||
|
||||
if(packet[6 + 0] === search_mac[0] &&
|
||||
packet[6 + 1] === search_mac[1] &&
|
||||
packet[6 + 2] === search_mac[2] &&
|
||||
packet[6 + 3] === search_mac[3] &&
|
||||
packet[6 + 4] === search_mac[4] &&
|
||||
packet[6 + 5] === search_mac[5])
|
||||
{
|
||||
dbg_log("Replace mac in eth source field", LOG_NET);
|
||||
|
||||
packet[6 + 0] = replacement_mac[0];
|
||||
packet[6 + 1] = replacement_mac[1];
|
||||
packet[6 + 2] = replacement_mac[2];
|
||||
packet[6 + 3] = replacement_mac[3];
|
||||
packet[6 + 4] = replacement_mac[4];
|
||||
packet[6 + 5] = replacement_mac[5];
|
||||
}
|
||||
|
||||
const ethertype = packet[12] << 8 | packet[13];
|
||||
|
||||
if(ethertype === 0x0800)
|
||||
{
|
||||
// ipv4
|
||||
const ipv4_packet = packet.subarray(14);
|
||||
const ipv4_version = ipv4_packet[0] >> 4;
|
||||
|
||||
if(ipv4_version !== 4)
|
||||
{
|
||||
dbg_log("Expected ipv4.version==4 but got: " + ipv4_version, LOG_NET);
|
||||
return;
|
||||
}
|
||||
|
||||
const ipv4_ihl = ipv4_packet[0] & 0xF;
|
||||
dbg_assert(ipv4_ihl === 5, "TODO: ihl!=5");
|
||||
|
||||
const ipv4_proto = ipv4_packet[9];
|
||||
if(ipv4_proto === 0x11)
|
||||
{
|
||||
// udp
|
||||
const udp_packet = ipv4_packet.subarray(5 * 4);
|
||||
const source_port = udp_packet[0] << 8 | udp_packet[1];
|
||||
const destination_port = udp_packet[2] << 8 | udp_packet[3];
|
||||
const checksum = udp_packet[6] << 8 | udp_packet[7];
|
||||
|
||||
dbg_log("udp srcport=" + source_port + " dstport=" + destination_port + " checksum=" + h(checksum, 4), LOG_NET);
|
||||
|
||||
if(source_port === 67 || destination_port === 67)
|
||||
{
|
||||
// dhcp
|
||||
const dhcp_packet = udp_packet.subarray(8);
|
||||
|
||||
if(dhcp_packet[28 + 0] === search_mac[0] &&
|
||||
dhcp_packet[28 + 1] === search_mac[1] &&
|
||||
dhcp_packet[28 + 2] === search_mac[2] &&
|
||||
dhcp_packet[28 + 3] === search_mac[3] &&
|
||||
dhcp_packet[28 + 4] === search_mac[4] &&
|
||||
dhcp_packet[28 + 5] === search_mac[5])
|
||||
{
|
||||
dbg_log("Replace mac in dhcp.chaddr", LOG_NET);
|
||||
|
||||
dhcp_packet[28 + 0] = replacement_mac[0];
|
||||
dhcp_packet[28 + 1] = replacement_mac[1];
|
||||
dhcp_packet[28 + 2] = replacement_mac[2];
|
||||
dhcp_packet[28 + 3] = replacement_mac[3];
|
||||
dhcp_packet[28 + 4] = replacement_mac[4];
|
||||
dhcp_packet[28 + 5] = replacement_mac[5];
|
||||
|
||||
udp_packet[6] = udp_packet[7] = 0; // zero udp checksum
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// tcp, ...
|
||||
}
|
||||
}
|
||||
else if(ethertype === 0x0806)
|
||||
{
|
||||
// arp
|
||||
const arp_packet = packet.subarray(14);
|
||||
dbg_log("arp oper=" + arp_packet[7] + " " + format_mac(arp_packet.subarray(8, 8+6)) + " " + format_mac(arp_packet.subarray(18, 18+6)), LOG_NET);
|
||||
|
||||
if(arp_packet[8 + 0] === search_mac[0] &&
|
||||
arp_packet[8 + 1] === search_mac[1] &&
|
||||
arp_packet[8 + 2] === search_mac[2] &&
|
||||
arp_packet[8 + 3] === search_mac[3] &&
|
||||
arp_packet[8 + 4] === search_mac[4] &&
|
||||
arp_packet[8 + 5] === search_mac[5])
|
||||
{
|
||||
dbg_log("Replace mac in arp.sha", LOG_NET);
|
||||
|
||||
arp_packet[8 + 0] = replacement_mac[0];
|
||||
arp_packet[8 + 1] = replacement_mac[1];
|
||||
arp_packet[8 + 2] = replacement_mac[2];
|
||||
arp_packet[8 + 3] = replacement_mac[3];
|
||||
arp_packet[8 + 4] = replacement_mac[4];
|
||||
arp_packet[8 + 5] = replacement_mac[5];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: ipv6, ...
|
||||
}
|
||||
}
|
||||
|
||||
function format_mac(mac)
|
||||
{
|
||||
return [
|
||||
mac[0].toString(16).padStart(2, "0"),
|
||||
mac[1].toString(16).padStart(2, "0"),
|
||||
mac[2].toString(16).padStart(2, "0"),
|
||||
mac[3].toString(16).padStart(2, "0"),
|
||||
mac[4].toString(16).padStart(2, "0"),
|
||||
mac[5].toString(16).padStart(2, "0"),
|
||||
].join(":");
|
||||
}
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {CPU} cpu
|
||||
* @param {BusConnector} bus
|
||||
* @param {Boolean} preserve_mac_from_state_image
|
||||
* @param {Boolean} mac_address_translation
|
||||
*/
|
||||
function Ne2k(cpu, bus, preserve_mac_from_state_image)
|
||||
function Ne2k(cpu, bus, preserve_mac_from_state_image, mac_address_translation)
|
||||
{
|
||||
/** @const @type {CPU} */
|
||||
this.cpu = cpu;
|
||||
|
@ -71,6 +212,7 @@ function Ne2k(cpu, bus, preserve_mac_from_state_image)
|
|||
this.pci = cpu.devices.pci;
|
||||
|
||||
this.preserve_mac_from_state_image = preserve_mac_from_state_image;
|
||||
this.mac_address_translation = mac_address_translation;
|
||||
|
||||
/** @const @type {BusConnector} */
|
||||
this.bus = bus;
|
||||
|
@ -127,6 +269,10 @@ function Ne2k(cpu, bus, preserve_mac_from_state_image)
|
|||
Math.random() * 255 | 0,
|
||||
]);
|
||||
|
||||
// Used for mac address translation
|
||||
// The mac the OS thinks it has
|
||||
this.mac_address_in_state = null;
|
||||
|
||||
for(var i = 0; i < 6; i++)
|
||||
{
|
||||
this.memory[i << 1] = this.memory[i << 1 | 1] = this.mac[i];
|
||||
|
@ -137,12 +283,7 @@ function Ne2k(cpu, bus, preserve_mac_from_state_image)
|
|||
this.memory[14 << 1] = this.memory[14 << 1 | 1] = 0x57;
|
||||
this.memory[15 << 1] = this.memory[15 << 1 | 1] = 0x57;
|
||||
|
||||
dbg_log("Mac: " + h(this.mac[0], 2) + ":" +
|
||||
h(this.mac[1], 2) + ":" +
|
||||
h(this.mac[2], 2) + ":" +
|
||||
h(this.mac[3], 2) + ":" +
|
||||
h(this.mac[4], 2) + ":" +
|
||||
h(this.mac[5], 2), LOG_NET);
|
||||
dbg_log("Mac: " + format_mac(this.mac), LOG_NET);
|
||||
|
||||
this.rsar = 0;
|
||||
|
||||
|
@ -186,6 +327,11 @@ function Ne2k(cpu, bus, preserve_mac_from_state_image)
|
|||
dbg_log(hex_dump(data));
|
||||
}
|
||||
|
||||
if(this.mac_address_in_state)
|
||||
{
|
||||
translate_mac_address(data, this.mac_address_in_state, this.mac);
|
||||
}
|
||||
|
||||
this.bus.send("net0-send", data);
|
||||
this.bus.send("eth-transmit-end", [data.length]);
|
||||
this.cr &= ~4;
|
||||
|
@ -803,6 +949,15 @@ Ne2k.prototype.set_state = function(state)
|
|||
this.mac = state[15];
|
||||
this.memory = state[16];
|
||||
}
|
||||
else if(this.mac_address_translation)
|
||||
{
|
||||
this.mac_address_in_state = state[15];
|
||||
this.memory = state[16];
|
||||
|
||||
dbg_log("Using mac address translation" +
|
||||
" guest_os_mac=" + format_mac(this.mac_address_in_state) +
|
||||
" real_mac=" + format_mac(this.mac), LOG_NET);
|
||||
}
|
||||
};
|
||||
|
||||
Ne2k.prototype.do_interrupt = function(ir_mask)
|
||||
|
@ -969,6 +1124,11 @@ Ne2k.prototype.receive = function(data)
|
|||
return;
|
||||
}
|
||||
|
||||
if(this.mac_address_in_state)
|
||||
{
|
||||
translate_mac_address(data, this.mac, this.mac_address_in_state);
|
||||
}
|
||||
|
||||
var packet_length = Math.max(60, data.length);
|
||||
|
||||
var offset = this.curpg << 8;
|
||||
|
|
Loading…
Reference in a new issue