From ba5e89a996206f62b88582f12156f0544bb030e9 Mon Sep 17 00:00:00 2001 From: win2kgamer <47463859+win2kgamer@users.noreply.github.com> Date: Mon, 9 Feb 2026 19:40:56 -0600 Subject: [PATCH 01/14] Headland: Add some basic logging --- src/chipset/headland.c | 45 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/chipset/headland.c b/src/chipset/headland.c index f52e3fe77..13dfe6799 100644 --- a/src/chipset/headland.c +++ b/src/chipset/headland.c @@ -18,11 +18,17 @@ * Copyright 2017-2019 Miran Grca. * Copyright 2017-2019 GreatPsycho. */ +#ifdef ENABLE_HEADLAND_LOG +#include +#endif #include #include #include #include #include +#ifdef ENABLE_HEADLAND_LOG +#define HAVE_STDARG_H +#endif #include <86box/86box.h> #include "cpu.h" #include "x86.h" @@ -35,6 +41,24 @@ #include <86box/plat_unused.h> #include <86box/port_92.h> #include <86box/chipset.h> +#include <86box/log.h> + +#ifdef ENABLE_HEADLAND_LOG +int headland_do_log = ENABLE_HEADLAND_LOG; + +static void +headland_log(void *priv, const char *fmt, ...) +{ + if (headland_do_log) { + va_list ap; + va_start(ap, fmt); + log_out(priv, fmt, ap); + va_end(ap); + } +} +#else +# define headland_log(fmt, ...) +#endif enum { HEADLAND_GC103 = 0x00, @@ -82,6 +106,8 @@ typedef struct headland_t { mem_mapping_t high_mapping; mem_mapping_t shadow_mapping[2]; mem_mapping_t upper_mapping[24]; + + void * log; /* New logging system */ } headland_t; /* TODO - Headland chipset's memory address mapping emulation isn't fully implemented yet, @@ -125,6 +151,8 @@ get_addr(headland_t *dev, uint32_t addr, headland_mr_t *mr) other_shift = (dev->cr[0] & 0x80) ? 21 : 19; } + headland_log(dev->log, "Headland shift values: shift = %i, other_shift = %i\n", shift, other_shift); + /* Bank size = 1 << (bank shift + 2) . */ bank_shift[0] = bank_shift[1] = shift; @@ -248,6 +276,7 @@ memmap_state_update(headland_t *dev) memmap_state_default(dev, ht_romcs); + headland_log(dev->log, "Headland 384K Remap %sabled\n", ht_cr0 & 0x04 ? "Dis" : "En"); if (mem_size > 640) { if (ht_cr0 & 0x04) { mem_mapping_set_addr(&dev->mid_mapping, 0xA0000, 0x40000); @@ -273,6 +302,7 @@ memmap_state_update(headland_t *dev) } } + headland_log(dev->log, "Headland shadow RAM val = %02X\n", ht_cr0 & 0x18); switch (ht_cr0 & 0x18) { case 0x18: if ((mem_size << 10) > 0xe0000) { @@ -331,6 +361,8 @@ hl_write(uint16_t addr, uint8_t val, void *priv) { headland_t *dev = (headland_t *) priv; + headland_log(dev->log, "[%04X:%08X] Headland: [W] addr = %04X, val = %02X\n", CS, cpu_state.pc, addr, val); + switch (addr) { case 0x01ec: dev->ems_mr[dev->ems_mar & 0x3f].mr = val | 0xff00; @@ -401,6 +433,8 @@ hl_writew(uint16_t addr, uint16_t val, void *priv) { headland_t *dev = (headland_t *) priv; + headland_log(dev->log, "[%04X:%08X] Headland: [W] addr = %04X, val = %04X\n", CS, cpu_state.pc, addr, val); + switch (addr) { case 0x01ec: dev->ems_mr[dev->ems_mar & 0x3f].mr = val; @@ -470,6 +504,8 @@ hl_read(uint16_t addr, void *priv) break; } + headland_log(dev->log, "[%04X:%08X] Headland [R] addr = %04X, val = %02X\n", CS, cpu_state.pc, addr, ret); + return ret; } @@ -490,6 +526,8 @@ hl_readw(uint16_t addr, void *priv) break; } + headland_log(dev->log, "[%04X:%08X] Headland [R] addr = %04X, val = %04X\n", CS, cpu_state.pc, addr, ret); + return ret; } @@ -584,6 +622,11 @@ headland_close(void *priv) { headland_t *dev = (headland_t *) priv; + if (dev->log != NULL) { + log_close(dev->log); + dev->log = NULL; + } + free(dev); } @@ -621,6 +664,8 @@ headland_init(const device_t *info) dev->ems_mr[i].headland = dev; } + dev->log = log_open("Headland"); + /* Turn off mem.c mappings. */ mem_mapping_disable(&ram_low_mapping); mem_mapping_disable(&ram_mid_mapping); From 4bf2bc7bce28c1346e340dd39b05c1e2dc21e93d Mon Sep 17 00:00:00 2001 From: win2kgamer <47463859+win2kgamer@users.noreply.github.com> Date: Mon, 9 Feb 2026 20:08:06 -0600 Subject: [PATCH 02/14] Headland: Fix incorrect memory bank handling, fixes Tandy 1000 RSX BIOS hang with 9MB RAM --- src/chipset/headland.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/chipset/headland.c b/src/chipset/headland.c index 13dfe6799..37ec8a1fe 100644 --- a/src/chipset/headland.c +++ b/src/chipset/headland.c @@ -143,12 +143,12 @@ get_addr(headland_t *dev, uint32_t addr, headland_mr_t *mr) else if ((addr >= 0xfe0000) && (addr <= 0xffffff)) return addr & 0x0fffff; - if (dev->revision == 8) { - shift = (dev->cr[0] & 0x80) ? 21 : ((dev->cr[6] & 0x01) ? 23 : 19); - other_shift = (dev->cr[0] & 0x80) ? ((dev->cr[6] & 0x01) ? 19 : 23) : 21; + if ((dev->revision == 8) && ((dev->cr[6] & 0x01) == 0x01)) { + shift = (dev->cr[0] & 0x80) ? 21 : ((dev->cr[1] & 0x40) ? 19 : 23); + other_shift = (dev->cr[0] & 0x80) ? 23 : ((dev->cr[1] & 0x40) ? 23 : 23); } else { shift = (dev->cr[0] & 0x80) ? 21 : 19; - other_shift = (dev->cr[0] & 0x80) ? 21 : 19; + other_shift = (dev->cr[0] & 0x80) ? 19 : 21; } headland_log(dev->log, "Headland shift values: shift = %i, other_shift = %i\n", shift, other_shift); @@ -158,14 +158,15 @@ get_addr(headland_t *dev, uint32_t addr, headland_mr_t *mr) bank_base[0] = 0x00000000; bank_base[1] = bank_base[0] + (1 << shift); - bank_base[2] = bank_base[1] + (1 << shift); - if ((dev->revision > 0) && (dev->revision < 8) && (dev->cr[1] & 0x40)) { + if ((dev->revision > 0) && (dev->cr[1] & 0x40)) { bank_shift[2] = bank_shift[3] = other_shift; + bank_base[2] = bank_base[1] + (1 << other_shift); bank_base[3] = bank_base[2] + (1 << other_shift); /* First address after the memory is bank_base[3] + (1 << other_shift) */ } else { bank_shift[2] = bank_shift[3] = shift; + bank_base[2] = bank_base[1] + (1 << shift); bank_base[3] = bank_base[2] + (1 << shift); /* First address after the memory is bank_base[3] + (1 << shift) */ } From 3a1845398b70c5175f2b0c2aefd8462452200f73 Mon Sep 17 00:00:00 2001 From: win2kgamer <47463859+win2kgamer@users.noreply.github.com> Date: Mon, 9 Feb 2026 20:15:06 -0600 Subject: [PATCH 03/14] Headland: Correctly set memory state when enabling/disabling 384K remap and add 384K remap handling for 640-1024K memory configs, fixes 384K remap on Tandy 1000 RSX --- src/chipset/headland.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/chipset/headland.c b/src/chipset/headland.c index 37ec8a1fe..337aefb00 100644 --- a/src/chipset/headland.c +++ b/src/chipset/headland.c @@ -284,9 +284,11 @@ memmap_state_update(headland_t *dev) mem_mapping_set_exec(&dev->mid_mapping, ram + 0xA0000); mem_mapping_disable(&dev->mid_mapping); if (mem_size > 1024) { - mem_set_mem_state((mem_size << 10), 0x60000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_set_mem_state((mem_size << 10), 0x60000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); mem_mapping_set_addr(&dev->high_mapping, 0x100000, (mem_size - 1024) << 10); mem_mapping_set_exec(&dev->high_mapping, ram + 0x100000); + } else if ((mem_size > 640) && (mem_size <=1024)) { + mem_set_mem_state(0x100000, (mem_size - 640) << 10, MEM_READ_EXTANY | MEM_WRITE_EXTANY); } } else { /* 1 MB - 1 MB + 384k: RAM pointing to A0000-FFFFF @@ -296,9 +298,11 @@ memmap_state_update(headland_t *dev) mem_mapping_set_exec(&dev->mid_mapping, ram + 0xA0000); if (mem_size > 1024) { /* We have ram above 1 MB, we need to relocate that. */ - mem_set_mem_state((mem_size << 10), 0x60000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + mem_set_mem_state((mem_size << 10), 0x60000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); mem_mapping_set_addr(&dev->high_mapping, 0x160000, (mem_size - 1024) << 10); mem_mapping_set_exec(&dev->high_mapping, ram + 0x100000); + } else if ((mem_size > 640) && (mem_size <=1024)) { + mem_set_mem_state(0x100000, (mem_size - 640) << 10, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); } } } From f3d22bbef3dbad7d198b280eeee908c46440c66a Mon Sep 17 00:00:00 2001 From: Mike Swanson Date: Mon, 9 Feb 2026 19:06:45 -0800 Subject: [PATCH 04/14] local switch: Implement shared-secret feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows for a “shared secret” to be entered for a network switch, segmenting traffic so that multiple people could use the feature simultaneously without accidentally entering into or interfering with each other's networks. Takes a string specified in the configuration file (using the net_%02i_secret key) and hashes it through SHA3-256 to prepend to each data packet. This hash is used to compare packets on reception and allow or discard them. --- src/config.c | 11 + src/include/86box/network.h | 1 + src/include/shathree.h | 481 ++++++++++++++++++++++++++++++++++++ src/network/net_switch.c | 49 +++- 4 files changed, 538 insertions(+), 4 deletions(-) create mode 100644 src/include/shathree.h diff --git a/src/config.c b/src/config.c index 06049713c..182b6bdf0 100644 --- a/src/config.c +++ b/src/config.c @@ -915,6 +915,11 @@ load_network(void) if (nc->switch_group < NET_SWITCH_GRP_MIN) nc->switch_group = NET_SWITCH_GRP_MIN; + sprintf(temp, "net_%02i_secret", c + 1); + p = ini_section_get_string(cat, temp, NULL); + strncpy(nc->secret, p ? p : "", sizeof(nc->secret) - 1); + nc->secret[sizeof(net_cards_conf[c].secret) - 1] = '\0'; + sprintf(temp, "net_%02i_promisc", c + 1); nc->promisc_mode = ini_section_get_int(cat, temp, 0); @@ -3025,6 +3030,12 @@ save_network(void) else ini_section_set_int(cat, temp, nc->switch_group); + sprintf(temp, "net_%02i_secret", c + 1); + if (nc->secret[0] == '\0') + ini_section_delete_var(cat, temp); + else + ini_section_set_string(cat, temp, net_cards_conf[c].secret); + sprintf(temp, "net_%02i_promisc", c + 1); if (nc->promisc_mode == 0) ini_section_delete_var(cat, temp); diff --git a/src/include/86box/network.h b/src/include/86box/network.h index f3f1b1f8a..78b03e439 100644 --- a/src/include/86box/network.h +++ b/src/include/86box/network.h @@ -98,6 +98,7 @@ typedef struct netcard_conf_t { char host_dev_name[128]; uint32_t link_state; uint8_t switch_group; + char secret[256]; uint8_t promisc_mode; char slirp_net[16]; char nrs_hostname[128]; diff --git a/src/include/shathree.h b/src/include/shathree.h new file mode 100644 index 000000000..98e804b33 --- /dev/null +++ b/src/include/shathree.h @@ -0,0 +1,481 @@ +/* +** This code is from SQLite +** (https://sqlite.org/src/info/2025-02-27T21:17:55z), at file path +** ext/misc/shathree.c. The SQLite functions have been removed, but +** it is the same code written by D. Richard Hipp. +*/ + +#ifndef SHATHREE_H + +/* +** 2017-03-08 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +*/ +#include +#include +#include + +/****************************************************************************** +** The Hash Engine +*/ +/* +** Macros to determine whether the machine is big or little endian, +** and whether or not that determination is run-time or compile-time. +** +** For best performance, an attempt is made to guess at the byte-order +** using C-preprocessor macros. If that is unsuccessful, or if +** -DSHA3_BYTEORDER=0 is set, then byte-order is determined +** at run-time. +*/ +#ifndef SHA3_BYTEORDER +# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ + defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ + defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ + defined(__arm__) +# define SHA3_BYTEORDER 1234 +# elif defined(sparc) || defined(__ppc__) +# define SHA3_BYTEORDER 4321 +# else +# define SHA3_BYTEORDER 0 +# endif +#endif + +#define u64 uint64_t + + +/* +** State structure for a SHA3 hash in progress +*/ +typedef struct SHA3Context SHA3Context; +struct SHA3Context { + union { + u64 s[25]; /* Keccak state. 5x5 lines of 64 bits each */ + unsigned char x[1600]; /* ... or 1600 bytes */ + } u; + unsigned nRate; /* Bytes of input accepted per Keccak iteration */ + unsigned nLoaded; /* Input bytes loaded into u.x[] so far this cycle */ + unsigned ixMask; /* Insert next input into u.x[nLoaded^ixMask]. */ + unsigned iSize; /* 224, 256, 358, or 512 */ +}; + +/* +** A single step of the Keccak mixing function for a 1600-bit state +*/ +static void KeccakF1600Step(SHA3Context *p){ + int i; + u64 b0, b1, b2, b3, b4; + u64 c0, c1, c2, c3, c4; + u64 d0, d1, d2, d3, d4; + static const u64 RC[] = { + 0x0000000000000001ULL, 0x0000000000008082ULL, + 0x800000000000808aULL, 0x8000000080008000ULL, + 0x000000000000808bULL, 0x0000000080000001ULL, + 0x8000000080008081ULL, 0x8000000000008009ULL, + 0x000000000000008aULL, 0x0000000000000088ULL, + 0x0000000080008009ULL, 0x000000008000000aULL, + 0x000000008000808bULL, 0x800000000000008bULL, + 0x8000000000008089ULL, 0x8000000000008003ULL, + 0x8000000000008002ULL, 0x8000000000000080ULL, + 0x000000000000800aULL, 0x800000008000000aULL, + 0x8000000080008081ULL, 0x8000000000008080ULL, + 0x0000000080000001ULL, 0x8000000080008008ULL + }; +# define a00 (p->u.s[0]) +# define a01 (p->u.s[1]) +# define a02 (p->u.s[2]) +# define a03 (p->u.s[3]) +# define a04 (p->u.s[4]) +# define a10 (p->u.s[5]) +# define a11 (p->u.s[6]) +# define a12 (p->u.s[7]) +# define a13 (p->u.s[8]) +# define a14 (p->u.s[9]) +# define a20 (p->u.s[10]) +# define a21 (p->u.s[11]) +# define a22 (p->u.s[12]) +# define a23 (p->u.s[13]) +# define a24 (p->u.s[14]) +# define a30 (p->u.s[15]) +# define a31 (p->u.s[16]) +# define a32 (p->u.s[17]) +# define a33 (p->u.s[18]) +# define a34 (p->u.s[19]) +# define a40 (p->u.s[20]) +# define a41 (p->u.s[21]) +# define a42 (p->u.s[22]) +# define a43 (p->u.s[23]) +# define a44 (p->u.s[24]) +# define ROL64(a,x) ((a<>(64-x))) + + for(i=0; i<24; i+=4){ + c0 = a00^a10^a20^a30^a40; + c1 = a01^a11^a21^a31^a41; + c2 = a02^a12^a22^a32^a42; + c3 = a03^a13^a23^a33^a43; + c4 = a04^a14^a24^a34^a44; + d0 = c4^ROL64(c1, 1); + d1 = c0^ROL64(c2, 1); + d2 = c1^ROL64(c3, 1); + d3 = c2^ROL64(c4, 1); + d4 = c3^ROL64(c0, 1); + + b0 = (a00^d0); + b1 = ROL64((a11^d1), 44); + b2 = ROL64((a22^d2), 43); + b3 = ROL64((a33^d3), 21); + b4 = ROL64((a44^d4), 14); + a00 = b0 ^((~b1)& b2 ); + a00 ^= RC[i]; + a11 = b1 ^((~b2)& b3 ); + a22 = b2 ^((~b3)& b4 ); + a33 = b3 ^((~b4)& b0 ); + a44 = b4 ^((~b0)& b1 ); + + b2 = ROL64((a20^d0), 3); + b3 = ROL64((a31^d1), 45); + b4 = ROL64((a42^d2), 61); + b0 = ROL64((a03^d3), 28); + b1 = ROL64((a14^d4), 20); + a20 = b0 ^((~b1)& b2 ); + a31 = b1 ^((~b2)& b3 ); + a42 = b2 ^((~b3)& b4 ); + a03 = b3 ^((~b4)& b0 ); + a14 = b4 ^((~b0)& b1 ); + + b4 = ROL64((a40^d0), 18); + b0 = ROL64((a01^d1), 1); + b1 = ROL64((a12^d2), 6); + b2 = ROL64((a23^d3), 25); + b3 = ROL64((a34^d4), 8); + a40 = b0 ^((~b1)& b2 ); + a01 = b1 ^((~b2)& b3 ); + a12 = b2 ^((~b3)& b4 ); + a23 = b3 ^((~b4)& b0 ); + a34 = b4 ^((~b0)& b1 ); + + b1 = ROL64((a10^d0), 36); + b2 = ROL64((a21^d1), 10); + b3 = ROL64((a32^d2), 15); + b4 = ROL64((a43^d3), 56); + b0 = ROL64((a04^d4), 27); + a10 = b0 ^((~b1)& b2 ); + a21 = b1 ^((~b2)& b3 ); + a32 = b2 ^((~b3)& b4 ); + a43 = b3 ^((~b4)& b0 ); + a04 = b4 ^((~b0)& b1 ); + + b3 = ROL64((a30^d0), 41); + b4 = ROL64((a41^d1), 2); + b0 = ROL64((a02^d2), 62); + b1 = ROL64((a13^d3), 55); + b2 = ROL64((a24^d4), 39); + a30 = b0 ^((~b1)& b2 ); + a41 = b1 ^((~b2)& b3 ); + a02 = b2 ^((~b3)& b4 ); + a13 = b3 ^((~b4)& b0 ); + a24 = b4 ^((~b0)& b1 ); + + c0 = a00^a20^a40^a10^a30; + c1 = a11^a31^a01^a21^a41; + c2 = a22^a42^a12^a32^a02; + c3 = a33^a03^a23^a43^a13; + c4 = a44^a14^a34^a04^a24; + d0 = c4^ROL64(c1, 1); + d1 = c0^ROL64(c2, 1); + d2 = c1^ROL64(c3, 1); + d3 = c2^ROL64(c4, 1); + d4 = c3^ROL64(c0, 1); + + b0 = (a00^d0); + b1 = ROL64((a31^d1), 44); + b2 = ROL64((a12^d2), 43); + b3 = ROL64((a43^d3), 21); + b4 = ROL64((a24^d4), 14); + a00 = b0 ^((~b1)& b2 ); + a00 ^= RC[i+1]; + a31 = b1 ^((~b2)& b3 ); + a12 = b2 ^((~b3)& b4 ); + a43 = b3 ^((~b4)& b0 ); + a24 = b4 ^((~b0)& b1 ); + + b2 = ROL64((a40^d0), 3); + b3 = ROL64((a21^d1), 45); + b4 = ROL64((a02^d2), 61); + b0 = ROL64((a33^d3), 28); + b1 = ROL64((a14^d4), 20); + a40 = b0 ^((~b1)& b2 ); + a21 = b1 ^((~b2)& b3 ); + a02 = b2 ^((~b3)& b4 ); + a33 = b3 ^((~b4)& b0 ); + a14 = b4 ^((~b0)& b1 ); + + b4 = ROL64((a30^d0), 18); + b0 = ROL64((a11^d1), 1); + b1 = ROL64((a42^d2), 6); + b2 = ROL64((a23^d3), 25); + b3 = ROL64((a04^d4), 8); + a30 = b0 ^((~b1)& b2 ); + a11 = b1 ^((~b2)& b3 ); + a42 = b2 ^((~b3)& b4 ); + a23 = b3 ^((~b4)& b0 ); + a04 = b4 ^((~b0)& b1 ); + + b1 = ROL64((a20^d0), 36); + b2 = ROL64((a01^d1), 10); + b3 = ROL64((a32^d2), 15); + b4 = ROL64((a13^d3), 56); + b0 = ROL64((a44^d4), 27); + a20 = b0 ^((~b1)& b2 ); + a01 = b1 ^((~b2)& b3 ); + a32 = b2 ^((~b3)& b4 ); + a13 = b3 ^((~b4)& b0 ); + a44 = b4 ^((~b0)& b1 ); + + b3 = ROL64((a10^d0), 41); + b4 = ROL64((a41^d1), 2); + b0 = ROL64((a22^d2), 62); + b1 = ROL64((a03^d3), 55); + b2 = ROL64((a34^d4), 39); + a10 = b0 ^((~b1)& b2 ); + a41 = b1 ^((~b2)& b3 ); + a22 = b2 ^((~b3)& b4 ); + a03 = b3 ^((~b4)& b0 ); + a34 = b4 ^((~b0)& b1 ); + + c0 = a00^a40^a30^a20^a10; + c1 = a31^a21^a11^a01^a41; + c2 = a12^a02^a42^a32^a22; + c3 = a43^a33^a23^a13^a03; + c4 = a24^a14^a04^a44^a34; + d0 = c4^ROL64(c1, 1); + d1 = c0^ROL64(c2, 1); + d2 = c1^ROL64(c3, 1); + d3 = c2^ROL64(c4, 1); + d4 = c3^ROL64(c0, 1); + + b0 = (a00^d0); + b1 = ROL64((a21^d1), 44); + b2 = ROL64((a42^d2), 43); + b3 = ROL64((a13^d3), 21); + b4 = ROL64((a34^d4), 14); + a00 = b0 ^((~b1)& b2 ); + a00 ^= RC[i+2]; + a21 = b1 ^((~b2)& b3 ); + a42 = b2 ^((~b3)& b4 ); + a13 = b3 ^((~b4)& b0 ); + a34 = b4 ^((~b0)& b1 ); + + b2 = ROL64((a30^d0), 3); + b3 = ROL64((a01^d1), 45); + b4 = ROL64((a22^d2), 61); + b0 = ROL64((a43^d3), 28); + b1 = ROL64((a14^d4), 20); + a30 = b0 ^((~b1)& b2 ); + a01 = b1 ^((~b2)& b3 ); + a22 = b2 ^((~b3)& b4 ); + a43 = b3 ^((~b4)& b0 ); + a14 = b4 ^((~b0)& b1 ); + + b4 = ROL64((a10^d0), 18); + b0 = ROL64((a31^d1), 1); + b1 = ROL64((a02^d2), 6); + b2 = ROL64((a23^d3), 25); + b3 = ROL64((a44^d4), 8); + a10 = b0 ^((~b1)& b2 ); + a31 = b1 ^((~b2)& b3 ); + a02 = b2 ^((~b3)& b4 ); + a23 = b3 ^((~b4)& b0 ); + a44 = b4 ^((~b0)& b1 ); + + b1 = ROL64((a40^d0), 36); + b2 = ROL64((a11^d1), 10); + b3 = ROL64((a32^d2), 15); + b4 = ROL64((a03^d3), 56); + b0 = ROL64((a24^d4), 27); + a40 = b0 ^((~b1)& b2 ); + a11 = b1 ^((~b2)& b3 ); + a32 = b2 ^((~b3)& b4 ); + a03 = b3 ^((~b4)& b0 ); + a24 = b4 ^((~b0)& b1 ); + + b3 = ROL64((a20^d0), 41); + b4 = ROL64((a41^d1), 2); + b0 = ROL64((a12^d2), 62); + b1 = ROL64((a33^d3), 55); + b2 = ROL64((a04^d4), 39); + a20 = b0 ^((~b1)& b2 ); + a41 = b1 ^((~b2)& b3 ); + a12 = b2 ^((~b3)& b4 ); + a33 = b3 ^((~b4)& b0 ); + a04 = b4 ^((~b0)& b1 ); + + c0 = a00^a30^a10^a40^a20; + c1 = a21^a01^a31^a11^a41; + c2 = a42^a22^a02^a32^a12; + c3 = a13^a43^a23^a03^a33; + c4 = a34^a14^a44^a24^a04; + d0 = c4^ROL64(c1, 1); + d1 = c0^ROL64(c2, 1); + d2 = c1^ROL64(c3, 1); + d3 = c2^ROL64(c4, 1); + d4 = c3^ROL64(c0, 1); + + b0 = (a00^d0); + b1 = ROL64((a01^d1), 44); + b2 = ROL64((a02^d2), 43); + b3 = ROL64((a03^d3), 21); + b4 = ROL64((a04^d4), 14); + a00 = b0 ^((~b1)& b2 ); + a00 ^= RC[i+3]; + a01 = b1 ^((~b2)& b3 ); + a02 = b2 ^((~b3)& b4 ); + a03 = b3 ^((~b4)& b0 ); + a04 = b4 ^((~b0)& b1 ); + + b2 = ROL64((a10^d0), 3); + b3 = ROL64((a11^d1), 45); + b4 = ROL64((a12^d2), 61); + b0 = ROL64((a13^d3), 28); + b1 = ROL64((a14^d4), 20); + a10 = b0 ^((~b1)& b2 ); + a11 = b1 ^((~b2)& b3 ); + a12 = b2 ^((~b3)& b4 ); + a13 = b3 ^((~b4)& b0 ); + a14 = b4 ^((~b0)& b1 ); + + b4 = ROL64((a20^d0), 18); + b0 = ROL64((a21^d1), 1); + b1 = ROL64((a22^d2), 6); + b2 = ROL64((a23^d3), 25); + b3 = ROL64((a24^d4), 8); + a20 = b0 ^((~b1)& b2 ); + a21 = b1 ^((~b2)& b3 ); + a22 = b2 ^((~b3)& b4 ); + a23 = b3 ^((~b4)& b0 ); + a24 = b4 ^((~b0)& b1 ); + + b1 = ROL64((a30^d0), 36); + b2 = ROL64((a31^d1), 10); + b3 = ROL64((a32^d2), 15); + b4 = ROL64((a33^d3), 56); + b0 = ROL64((a34^d4), 27); + a30 = b0 ^((~b1)& b2 ); + a31 = b1 ^((~b2)& b3 ); + a32 = b2 ^((~b3)& b4 ); + a33 = b3 ^((~b4)& b0 ); + a34 = b4 ^((~b0)& b1 ); + + b3 = ROL64((a40^d0), 41); + b4 = ROL64((a41^d1), 2); + b0 = ROL64((a42^d2), 62); + b1 = ROL64((a43^d3), 55); + b2 = ROL64((a44^d4), 39); + a40 = b0 ^((~b1)& b2 ); + a41 = b1 ^((~b2)& b3 ); + a42 = b2 ^((~b3)& b4 ); + a43 = b3 ^((~b4)& b0 ); + a44 = b4 ^((~b0)& b1 ); + } +} + +/* +** Initialize a new hash. iSize determines the size of the hash +** in bits and should be one of 224, 256, 384, or 512. Or iSize +** can be zero to use the default hash size of 256 bits. +*/ +static void SHA3Init(SHA3Context *p, int iSize){ + memset(p, 0, sizeof(*p)); + p->iSize = iSize; + if( iSize>=128 && iSize<=512 ){ + p->nRate = (1600 - ((iSize + 31)&~31)*2)/8; + }else{ + p->nRate = (1600 - 2*256)/8; + } +#if SHA3_BYTEORDER==1234 + /* Known to be little-endian at compile-time. No-op */ +#elif SHA3_BYTEORDER==4321 + p->ixMask = 7; /* Big-endian */ +#else + { + static unsigned int one = 1; + if( 1==*(unsigned char*)&one ){ + /* Little endian. No byte swapping. */ + p->ixMask = 0; + }else{ + /* Big endian. Byte swap. */ + p->ixMask = 7; + } + } +#endif +} + +/* +** Make consecutive calls to the SHA3Update function to add new content +** to the hash +*/ +static void SHA3Update( + SHA3Context *p, + const unsigned char *aData, + unsigned int nData +){ + unsigned int i = 0; + if( aData==0 ) return; +#if SHA3_BYTEORDER==1234 + if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){ + for(; i+7u.s[p->nLoaded/8] ^= *(u64*)&aData[i]; + p->nLoaded += 8; + if( p->nLoaded>=p->nRate ){ + KeccakF1600Step(p); + p->nLoaded = 0; + } + } + } +#endif + for(; iu.x[p->nLoaded] ^= aData[i]; +#elif SHA3_BYTEORDER==4321 + p->u.x[p->nLoaded^0x07] ^= aData[i]; +#else + p->u.x[p->nLoaded^p->ixMask] ^= aData[i]; +#endif + p->nLoaded++; + if( p->nLoaded==p->nRate ){ + KeccakF1600Step(p); + p->nLoaded = 0; + } + } +} + +/* +** After all content has been added, invoke SHA3Final() to compute +** the final hash. The function returns a pointer to the binary +** hash value. +*/ +static unsigned char *SHA3Final(SHA3Context *p){ + unsigned int i; + if( p->nLoaded==p->nRate-1 ){ + const unsigned char c1 = 0x86; + SHA3Update(p, &c1, 1); + }else{ + const unsigned char c2 = 0x06; + const unsigned char c3 = 0x80; + SHA3Update(p, &c2, 1); + p->nLoaded = p->nRate - 1; + SHA3Update(p, &c3, 1); + } + for(i=0; inRate; i++){ + p->u.x[i+p->nRate] = p->u.x[i^p->ixMask]; + } + return &p->u.x[p->nRate]; +} + +#endif diff --git a/src/network/net_switch.c b/src/network/net_switch.c index d29513f74..0f0d4b509 100644 --- a/src/network/net_switch.c +++ b/src/network/net_switch.c @@ -49,6 +49,7 @@ #include <86box/config.h> #include <86box/net_event.h> #include <86box/bswap.h> +#include #define SWITCH_PKT_BATCH NET_QUEUE_LEN @@ -80,6 +81,7 @@ typedef struct net_switch_t { net_switch_hostaddr_t *hostaddrs; uint16_t port_out; + uint8_t secret_hash[32]; uint8_t promisc; union { uint8_t mac_addr[6]; @@ -123,6 +125,15 @@ net_switch_in_available(void *priv) net_event_set(&netswitch->tx_event); } +static void +net_switch_secret_hash(const char *secret, uint8_t *hash) +{ + SHA3Context cx; + SHA3Init(&cx, 256); + SHA3Update(&cx, (const uint8_t *)secret, strlen(secret)); + memcpy(hash, SHA3Final(&cx), 32); +} + static unsigned int net_switch_add_hostaddr(net_switch_t *netswitch, net_switch_sockaddr_t *addr, net_switch_sockaddr_t *broadcast, net_switch_sockaddr_t *netmask, unsigned int flags) { @@ -374,15 +385,30 @@ net_switch_thread(void *priv) packets = network_tx_popv(netswitch->card, netswitch->pkt_tx_v, SWITCH_PKT_BATCH); if (!(net_cards_conf[netswitch->card->card_num].link_state & NET_LINK_DOWN)) { for (int i = 0; i < packets; i++) { + int orig_len = netswitch->pkt_tx_v[i].len; + int send_len = orig_len + 32; + + if (send_len > NET_MAX_FRAME) { + netswitch_log("Network Switch: packet too large to add header (%d bytes)\n", + orig_len); + continue; + } + + /* Prepend secret hash data */ + memmove(netswitch->pkt_tx_v[i].data + 32, + netswitch->pkt_tx_v[i].data, + orig_len); + memcpy(netswitch->pkt_tx_v[i].data, netswitch->secret_hash, 32); + #define MAC_FORMAT "(%02X:%02X:%02X:%02X:%02X:%02X -> %02X:%02X:%02X:%02X:%02X:%02X)" -#define MAC_FORMAT_ARGS(p) (p)[6], (p)[7], (p)[8], (p)[9], (p)[10], (p)[11], (p)[0], (p)[1], (p)[2], (p)[3], (p)[4], (p)[5] +#define MAC_FORMAT_ARGS(p) (p)[38], (p)[39], (p)[40], (p)[41], (p)[42], (p)[43], (p)[32], (p)[33], (p)[34], (p)[35], (p)[36], (p)[37] netswitch_log("Network Switch: sending %d-byte packet " MAC_FORMAT "\n", netswitch->pkt_tx_v[i].len, MAC_FORMAT_ARGS(netswitch->pkt_tx_v[i].data)); /* Send through all known host interfaces. */ for (net_switch_hostaddr_t *hostaddr = netswitch->hostaddrs; hostaddr; hostaddr = hostaddr->next) sendto(hostaddr->socket_tx, - (char *) netswitch->pkt_tx_v[i].data, netswitch->pkt_tx_v[i].len, 0, + (char *) netswitch->pkt_tx_v[i].data, send_len, 0, &hostaddr->addr_tx.sa, sizeof(hostaddr->addr_tx.sa)); } } @@ -407,9 +433,18 @@ net_switch_thread(void *priv) if (pfd[NET_EVENT_RX].revents & POLLIN) { #endif len = recv(netswitch->socket_rx, (char *) netswitch->pkt.data, NET_MAX_FRAME, 0); - if (len < 12) { + if (len < 44) { netswitch_log("Network Switch: recv error (%d)\n", len); - } else if ((AS_U64(netswitch->pkt.data[6]) & le64_to_cpu(0xffffffffffffULL)) == netswitch->mac_addr_u64) { + } + + if (memcmp(netswitch->pkt.data, netswitch->secret_hash, 32) != 0) { + /* This packet contains a different secret hash, ignore it. */ + continue; + } else { + memmove(netswitch->pkt.data, netswitch->pkt.data + 32, len - 32); + } + + if ((AS_U64(netswitch->pkt.data[6]) & le64_to_cpu(0xffffffffffffULL)) == netswitch->mac_addr_u64) { /* A packet we've sent has looped back, drop it. */ } else if (!(net_cards_conf[netswitch->card->card_num].link_state & NET_LINK_DOWN) && (netswitch->promisc || /* promiscuous mode? */ (netswitch->pkt.data[0] & 1) || /* broadcast packet? */ @@ -450,6 +485,12 @@ net_switch_init(const netcard_t *card, const uint8_t *mac_addr, void *priv, char netswitch->card = (netcard_t *) card; netswitch->promisc = !!netcard->promisc_mode; + { + uint8_t temp[32]; + net_switch_secret_hash((const uint8_t *)netcard->secret, (uint8_t *) temp); + memcpy(netswitch->secret_hash, temp, 32); + } + /* Initialize receive socket. */ netswitch->socket_rx = socket(AF_INET, SOCK_DGRAM, 0); if (netswitch->socket_rx < 0) { From 0d1e900fb60d5e96371b6a6a1cbb07d02ce5f0da Mon Sep 17 00:00:00 2001 From: Mike Swanson Date: Mon, 9 Feb 2026 20:05:42 -0800 Subject: [PATCH 05/14] Add GUI settings for shared secret, remove switch groups Two birds in one commit: with the introduction of shared secrets, there is a practically-infinite amount of local switches that can be used, by merely editing the shared secret string. As such, support for old switch groups has been removed. In addition to this, the multicast address for local switch has been altered to 239.255.80.86. This ensures a hard compatibility break with the previous code and old (albeit interim) builds of 86Box would not attempt to receive packets with shared secrets. --- src/config.c | 11 --- src/include/86box/network.h | 3 - src/network/net_switch.c | 6 +- src/qt/qt_settingsnetwork.cpp | 46 +++++------- src/qt/qt_settingsnetwork.ui | 136 +++++++--------------------------- 5 files changed, 50 insertions(+), 152 deletions(-) diff --git a/src/config.c b/src/config.c index 182b6bdf0..edd713755 100644 --- a/src/config.c +++ b/src/config.c @@ -910,11 +910,6 @@ load_network(void) nc->slirp_net[0] = '\0'; } - sprintf(temp, "net_%02i_switch_group", c + 1); - nc->switch_group = ini_section_get_int(cat, temp, NET_SWITCH_GRP_MIN); - if (nc->switch_group < NET_SWITCH_GRP_MIN) - nc->switch_group = NET_SWITCH_GRP_MIN; - sprintf(temp, "net_%02i_secret", c + 1); p = ini_section_get_string(cat, temp, NULL); strncpy(nc->secret, p ? p : "", sizeof(nc->secret) - 1); @@ -3024,12 +3019,6 @@ save_network(void) ini_section_delete_var(cat, temp); } - sprintf(temp, "net_%02i_switch_group", c + 1); - if (nc->switch_group == NET_SWITCH_GRP_MIN) - ini_section_delete_var(cat, temp); - else - ini_section_set_int(cat, temp, nc->switch_group); - sprintf(temp, "net_%02i_secret", c + 1); if (nc->secret[0] == '\0') ini_section_delete_var(cat, temp); diff --git a/src/include/86box/network.h b/src/include/86box/network.h index 78b03e439..d208cd345 100644 --- a/src/include/86box/network.h +++ b/src/include/86box/network.h @@ -60,8 +60,6 @@ #define NET_QUEUE_COUNT 4 #define NET_CARD_MAX 4 #define NET_HOST_INTF_MAX 64 -#define NET_SWITCH_GRP_MIN 1 -#define NET_SWITCH_GRP_MAX 10 #define NET_PERIOD_10M 0.8 #define NET_PERIOD_100M 0.08 @@ -97,7 +95,6 @@ typedef struct netcard_conf_t { int net_type; char host_dev_name[128]; uint32_t link_state; - uint8_t switch_group; char secret[256]; uint8_t promisc_mode; char slirp_net[16]; diff --git a/src/network/net_switch.c b/src/network/net_switch.c index 0f0d4b509..938443997 100644 --- a/src/network/net_switch.c +++ b/src/network/net_switch.c @@ -53,7 +53,7 @@ #define SWITCH_PKT_BATCH NET_QUEUE_LEN -#define SWITCH_MULTICAST_GROUP 0xefff5656 /* 239.255.86.86 */ +#define SWITCH_MULTICAST_GROUP 0xefff5056 /* 239.255.80.86 */ #define SWITCH_MULTICAST_PORT 8086 enum { @@ -478,8 +478,6 @@ net_switch_init(const netcard_t *card, const uint8_t *mac_addr, void *priv, char { netcard_conf_t *netcard = (netcard_conf_t *) priv; - netswitch_log("Network Switch: initializing with group %d...\n", netcard->switch_group); - net_switch_t *netswitch = calloc(1, sizeof(net_switch_t)); memcpy(netswitch->mac_addr, mac_addr, sizeof(netswitch->mac_addr)); netswitch->card = (netcard_t *) card; @@ -514,7 +512,7 @@ net_switch_init(const netcard_t *card, const uint8_t *mac_addr, void *priv, char val = 0; setsockopt(netswitch->socket_rx, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &val, sizeof(val)); - netswitch->port_out = htons(SWITCH_MULTICAST_PORT - NET_SWITCH_GRP_MIN + netcard->switch_group); + netswitch->port_out = htons(SWITCH_MULTICAST_PORT); struct sockaddr_in addr = { .sin_family = AF_INET, .sin_addr = { .s_addr = htonl(INADDR_ANY) }, diff --git a/src/qt/qt_settingsnetwork.cpp b/src/qt/qt_settingsnetwork.cpp index 878944e60..ff933fceb 100644 --- a/src/qt/qt_settingsnetwork.cpp +++ b/src/qt/qt_settingsnetwork.cpp @@ -49,13 +49,9 @@ SettingsNetwork::enableElements(Ui::SettingsNetwork *ui) auto *option_list_label = findChild(QString("labelOptionList%1").arg(i + 1)); auto *option_list_line = findChild(QString("lineOptionList%1").arg(i + 1)); - // Switch group - auto *switch_group_label = findChild(QString("labelSwitch%1").arg(i + 1)); - // auto *switch_group_hlayout = findChild(QString("HLayoutSwitch%1").arg(i + 1)); - // auto *switch_group_hspacer = findChild(QString("horizontalSpacerSwitch%1").arg(i + 1)); - auto *switch_group_value = findChild(QString("spinnerSwitch%1").arg(i + 1)); - switch_group_value->setMinimum(NET_SWITCH_GRP_MIN); - switch_group_value->setMaximum(NET_SWITCH_GRP_MAX); + // Shared secret + auto *secret_label = findChild(QString("labelSecret%1").arg(i + 1)); + auto *secret_value = findChild(QString("secretSwitch%1").arg(i + 1)); // Promiscuous option auto *promisc_label = findChild(QString("labelPromisc%1").arg(i + 1)); @@ -73,10 +69,8 @@ SettingsNetwork::enableElements(Ui::SettingsNetwork *ui) // NEW STUFF // Make all options invisible by default - // Switch group - switch_group_label->setVisible(false); - switch_group_value->setVisible(false); - // switch_group_hspacer->setVisible(false); + secret_label->setVisible(false); + secret_value->setVisible(false); // Promiscuous options promisc_label->setVisible(false); @@ -142,10 +136,9 @@ SettingsNetwork::enableElements(Ui::SettingsNetwork *ui) option_list_label->setVisible(true); option_list_line->setVisible(true); - // Switch group - switch_group_label->setVisible(true); - switch_group_value->setVisible(true); - // switch_group_hspacer->setVisible(false); + // Shared secret + secret_label->setVisible(true); + secret_value->setVisible(true); // Promiscuous options promisc_label->setVisible(true); @@ -157,10 +150,9 @@ SettingsNetwork::enableElements(Ui::SettingsNetwork *ui) option_list_label->setVisible(true); option_list_line->setVisible(true); - // Switch group - switch_group_label->setVisible(true); - switch_group_value->setVisible(true); - // switch_group_hspacer->setVisible(false); + // Shared secret + secret_label->setVisible(true); + secret_value->setVisible(true); // Hostname hostname_label->setVisible(true); @@ -215,7 +207,7 @@ SettingsNetwork::save() cbox = findChild(QString("comboBoxIntf%1").arg(i + 1)); auto *hostname_value = findChild(QString("hostnameSwitch%1").arg(i + 1)); auto *promisc_value = findChild(QString("boxPromisc%1").arg(i + 1)); - auto *switch_group_value = findChild(QString("spinnerSwitch%1").arg(i + 1)); + auto *secret_value = findChild(QString("secretSwitch%1").arg(i + 1)); memset(net_cards_conf[i].host_dev_name, '\0', sizeof(net_cards_conf[i].host_dev_name)); if (net_cards_conf[i].net_type == NET_TYPE_PCAP) strncpy(net_cards_conf[i].host_dev_name, network_devs[cbox->currentData().toInt()].device, sizeof(net_cards_conf[i].host_dev_name) - 1); @@ -230,10 +222,12 @@ SettingsNetwork::save() else if (net_cards_conf[i].net_type == NET_TYPE_NRSWITCH) { memset(net_cards_conf[i].nrs_hostname, '\0', sizeof(net_cards_conf[i].nrs_hostname)); strncpy(net_cards_conf[i].nrs_hostname, hostname_value->text().toUtf8().constData(), sizeof(net_cards_conf[i].nrs_hostname) - 1); - net_cards_conf[i].switch_group = switch_group_value->value(); + memset(net_cards_conf[i].secret, '\0', sizeof(net_cards_conf[i].secret)); + strncpy(net_cards_conf[i].secret, secret_value->text().toUtf8().constData(), sizeof(net_cards_conf[i].secret) - 1); } else if (net_cards_conf[i].net_type == NET_TYPE_NLSWITCH) { net_cards_conf[i].promisc_mode = promisc_value->isChecked(); - net_cards_conf[i].switch_group = switch_group_value->value(); + memset(net_cards_conf[i].secret, '\0', sizeof(net_cards_conf[i].secret)); + strncpy(net_cards_conf[i].secret, secret_value->text().toUtf8().constData(), sizeof(net_cards_conf[i].secret) - 1); } } } @@ -349,13 +343,13 @@ SettingsNetwork::onCurrentMachineChanged(int machineId) } else if (net_cards_conf[i].net_type == NET_TYPE_NLSWITCH) { auto *promisc_value = findChild(QString("boxPromisc%1").arg(i + 1)); promisc_value->setCheckState(net_cards_conf[i].promisc_mode == 1 ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); - auto *switch_group_value = findChild(QString("spinnerSwitch%1").arg(i + 1)); - switch_group_value->setValue(net_cards_conf[i].switch_group); + auto *secret_value = findChild(QString("secretSwitch%1").arg(i + 1)); + secret_value->setText(net_cards_conf[i].secret); } else if (net_cards_conf[i].net_type == NET_TYPE_NRSWITCH) { auto *hostname_value = findChild(QString("hostnameSwitch%1").arg(i + 1)); hostname_value->setText(net_cards_conf[i].nrs_hostname); - auto *switch_group_value = findChild(QString("spinnerSwitch%1").arg(i + 1)); - switch_group_value->setValue(net_cards_conf[i].switch_group); + auto *secret_value = findChild(QString("secretSwitch%1").arg(i + 1)); + secret_value->setText(net_cards_conf[i].secret); } } } diff --git a/src/qt/qt_settingsnetwork.ui b/src/qt/qt_settingsnetwork.ui index 12b74004f..5f7bd316a 100644 --- a/src/qt/qt_settingsnetwork.ui +++ b/src/qt/qt_settingsnetwork.ui @@ -170,38 +170,18 @@ - + - Switch: + Shared secret: - - - - - 1 - - - 10 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + 256 + + @@ -385,38 +365,18 @@ - + - Switch: + Shared secret: - - - - - 1 - - - 10 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + 256 + + @@ -600,38 +560,18 @@ - + - Switch: + Shared secret: - - - - - 1 - - - 10 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + 256 + + @@ -815,38 +755,18 @@ - + - Switch: + Shared secret: - - - - - 1 - - - 10 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + 256 + + From cc2e97acc7dc9ee0c3d77c81599b8e9a7b89d5cf Mon Sep 17 00:00:00 2001 From: Mike Swanson Date: Mon, 9 Feb 2026 20:23:49 -0800 Subject: [PATCH 06/14] =?UTF-8?q?Translate=20=E2=80=9Cshared=20secret?= =?UTF-8?q?=E2=80=9D=20into=20the=20languages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I used AI to translate the phrase. If it got any of the wrong, I trust it'll be fixed. :-) --- src/qt/languages/86box.pot | 2 +- src/qt/languages/ca-ES.po | 4 ++-- src/qt/languages/cs-CZ.po | 4 ++-- src/qt/languages/de-DE.po | 4 ++-- src/qt/languages/el-GR.po | 4 ++-- src/qt/languages/es-ES.po | 4 ++-- src/qt/languages/fi-FI.po | 4 ++-- src/qt/languages/fr-FR.po | 4 ++-- src/qt/languages/hr-HR.po | 4 ++-- src/qt/languages/it-IT.po | 4 ++-- src/qt/languages/ja-JP.po | 4 ++-- src/qt/languages/ko-KR.po | 4 ++-- src/qt/languages/nb-NO.po | 4 ++-- src/qt/languages/nl-NL.po | 4 ++-- src/qt/languages/pl-PL.po | 4 ++-- src/qt/languages/pt-BR.po | 4 ++-- src/qt/languages/pt-PT.po | 4 ++-- src/qt/languages/ru-RU.po | 4 ++-- src/qt/languages/sk-SK.po | 4 ++-- src/qt/languages/sl-SI.po | 4 ++-- src/qt/languages/sv-SE.po | 4 ++-- src/qt/languages/tr-TR.po | 4 ++-- src/qt/languages/uk-UA.po | 4 ++-- src/qt/languages/vi-VN.po | 4 ++-- src/qt/languages/zh-CN.po | 4 ++-- src/qt/languages/zh-TW.po | 4 ++-- 26 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index c62c18ea8..8bcc5c794 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -2832,7 +2832,7 @@ msgstr "" msgid "Remote Switch" msgstr "" -msgid "Switch:" +msgid "Shared secret:" msgstr "" msgid "Hub Mode" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index 0c1c8ac89..813b82dcb 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -2838,8 +2838,8 @@ msgstr "Commutador local" msgid "Remote Switch" msgstr "Commutador remot" -msgid "Switch:" -msgstr "Commutador:" +msgid "Shared secret:" +msgstr "Secret compartit:" msgid "Hub Mode" msgstr "Modalitat de concentrador" diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index 1df82475f..f27ac9d3c 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -2838,8 +2838,8 @@ msgstr "Lokální switch" msgid "Remote Switch" msgstr "Vzdálený switch" -msgid "Switch:" -msgstr "Switch:" +msgid "Shared secret:" +msgstr "Sdílené tajemství:" msgid "Hub Mode" msgstr "Režim hubu" diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index d0e649bc2..fc201c303 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -2838,8 +2838,8 @@ msgstr "Lokaler Schalter" msgid "Remote Switch" msgstr "Entfernter Schalter" -msgid "Switch:" -msgstr "Schalter:" +msgid "Shared secret:" +msgstr "Gemeinsames Geheimnis:" msgid "Hub Mode" msgstr "Hub-Modus" diff --git a/src/qt/languages/el-GR.po b/src/qt/languages/el-GR.po index 1442183df..6f10bbba9 100644 --- a/src/qt/languages/el-GR.po +++ b/src/qt/languages/el-GR.po @@ -2883,8 +2883,8 @@ msgstr "Τοπικός Διακόπτης" msgid "Remote Switch" msgstr "Απομακρυσμένος Διακόπτης" -msgid "Switch:" -msgstr "Διακόπτης:" +msgid "Shared secret:" +msgstr "κοινό μυστικό:" msgid "Hub Mode" msgstr "Λειτουργία Hub" diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index af2e1e75e..54e3d2079 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -2838,8 +2838,8 @@ msgstr "Conmutador local" msgid "Remote Switch" msgstr "Conmutador remoto" -msgid "Switch:" -msgstr "Conmutador:" +msgid "Shared secret:" +msgstr "Secreto compartido:" msgid "Hub Mode" msgstr "Modo de concentrador" diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index 2351f1afa..9d4e84f39 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -2838,8 +2838,8 @@ msgstr "Paikallinen kytkin" msgid "Remote Switch" msgstr "Etäkytkin" -msgid "Switch:" -msgstr "Kytkin:" +msgid "Shared secret:" +msgstr "Jaettu salaisuus:" msgid "Hub Mode" msgstr "Hubitila" diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index 42f1a8f40..453b52de4 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -2838,8 +2838,8 @@ msgstr "Commutateur local" msgid "Remote Switch" msgstr "Commutateur distant" -msgid "Switch:" -msgstr "Commutateur :" +msgid "Shared secret:" +msgstr "Secret partagé:" msgid "Hub Mode" msgstr "Mode concentrateur" diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index 32aaf1cf7..f1e8e3688 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -2840,8 +2840,8 @@ msgstr "Lokalni prekidač" msgid "Remote Switch" msgstr "Udaljeni prekidač" -msgid "Switch:" -msgstr "Prekidač:" +msgid "Shared secret:" +msgstr "Zajednička tajna:" msgid "Hub Mode" msgstr "Način čvorišta" diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index f46d09159..71fc69bce 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -2838,8 +2838,8 @@ msgstr "Commutatore locale" msgid "Remote Switch" msgstr "Commutatore remoto" -msgid "Switch:" -msgstr "Commutatore:" +msgid "Shared secret:" +msgstr "Segreto condiviso:" msgid "Hub Mode" msgstr "Modalità Hub" diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index 027b05204..2961a28f3 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -2839,8 +2839,8 @@ msgstr "ローカルスイッチ" msgid "Remote Switch" msgstr "リモートスイッチ" -msgid "Switch:" -msgstr "スイッチ:" +msgid "Shared secret:" +msgstr "きょうゆうひみつ:" msgid "Hub Mode" msgstr "ハブモード" diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index a46dc07c7..cd85aec57 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -2838,8 +2838,8 @@ msgstr "로컬 스위치" msgid "Remote Switch" msgstr "원격 스위치" -msgid "Switch:" -msgstr "스위치:" +msgid "Shared secret:" +msgstr "공유 비밀:" msgid "Hub Mode" msgstr "허브 모드" diff --git a/src/qt/languages/nb-NO.po b/src/qt/languages/nb-NO.po index b22f0bf69..b8370fedb 100644 --- a/src/qt/languages/nb-NO.po +++ b/src/qt/languages/nb-NO.po @@ -2839,8 +2839,8 @@ msgstr "Lokal svitsj" msgid "Remote Switch" msgstr "Ekstern svitsj" -msgid "Switch:" -msgstr "Svitsj:" +msgid "Shared secret:" +msgstr "Delt hemmelighet:" msgid "Hub Mode" msgstr "Hub-modus" diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index 3ad6f4feb..e48409dcd 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -2838,8 +2838,8 @@ msgstr "Lokale Switch" msgid "Remote Switch" msgstr "Externe Switch" -msgid "Switch:" -msgstr "Switch:" +msgid "Shared secret:" +msgstr "Gedeeld geheim:" msgid "Hub Mode" msgstr "Hub-modus" diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index e67ada685..e235bf995 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -2839,8 +2839,8 @@ msgstr "Switch lokalny" msgid "Remote Switch" msgstr "Switch zdalny" -msgid "Switch:" -msgstr "Switch:" +msgid "Shared secret:" +msgstr "Wspólny sekret:" msgid "Hub Mode" msgstr "Tryb hub" diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index 5ffbc2c72..05829de13 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -2832,8 +2832,8 @@ msgstr "Switch Local" msgid "Remote Switch" msgstr "Switch Remoto" -msgid "Switch:" -msgstr "Switch:" +msgid "Shared secret:" +msgstr "Segredo compartihado:" msgid "Hub Mode" msgstr "Modo Hub" diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index 8f0f55caf..87619edf7 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -2839,8 +2839,8 @@ msgstr "Comutador local" msgid "Remote Switch" msgstr "Comutador remoto" -msgid "Switch:" -msgstr "Comutador:" +msgid "Shared secret:" +msgstr "Segredo compartihado:" msgid "Hub Mode" msgstr "Modo de concentrador" diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index 9ca679356..2f272b262 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -2851,8 +2851,8 @@ msgstr "Локальный коммутатор" msgid "Remote Switch" msgstr "Удалённый коммутатор" -msgid "Switch:" -msgstr "Номер коммутатора:" +msgid "Shared secret:" +msgstr "Общий секрет:" msgid "Hub Mode" msgstr "Режим концентратора" diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index a5570faeb..2de580e32 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -2838,8 +2838,8 @@ msgstr "Lokálny prepínač" msgid "Remote Switch" msgstr "Vzdialený prepínač" -msgid "Switch:" -msgstr "Prepínač:" +msgid "Shared secret:" +msgstr "Zdieľané tajomstvo:" msgid "Hub Mode" msgstr "Režim hubu" diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index dfe0acbcd..b4d857e6a 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -2840,8 +2840,8 @@ msgstr "Lokalno stikalo" msgid "Remote Switch" msgstr "Oddaljeno stikalo" -msgid "Switch:" -msgstr "Stikalo:" +msgid "Shared secret:" +msgstr "Skupni skrivnost:" msgid "Hub Mode" msgstr "Način koncentratorja" diff --git a/src/qt/languages/sv-SE.po b/src/qt/languages/sv-SE.po index 5a8c7291c..c5a09f506 100644 --- a/src/qt/languages/sv-SE.po +++ b/src/qt/languages/sv-SE.po @@ -2838,8 +2838,8 @@ msgstr "Lokal switch" msgid "Remote Switch" msgstr "Fjärr-switch" -msgid "Switch:" -msgstr "Switch:" +msgid "Shared secret:" +msgstr "Delad hemlighet:" msgid "Hub Mode" msgstr "Hubb-läge" diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index 510fd82f3..d113c92b8 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -2838,8 +2838,8 @@ msgstr "Yerel Switch" msgid "Remote Switch" msgstr "Uzak Switch" -msgid "Switch:" -msgstr "Switch:" +msgid "Shared secret:" +msgstr "Paylaşılan sır:" msgid "Hub Mode" msgstr "Hub Modu" diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index d1964e647..3e6b695e1 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -2840,8 +2840,8 @@ msgstr "Локальний комутатор" msgid "Remote Switch" msgstr "Віддалений комутатор" -msgid "Switch:" -msgstr "Номер комутатора:" +msgid "Shared secret:" +msgstr "Спільний секрет:" msgid "Hub Mode" msgstr "Режим концентратора" diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index 73b59831a..4bd9d7baa 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -2839,8 +2839,8 @@ msgstr "Công tắc cục bộ" msgid "Remote Switch" msgstr "Công tắc từ xa" -msgid "Switch:" -msgstr "Công tắc:" +msgid "Shared secret:" +msgstr "Bí mật chia sẻ:" msgid "Hub Mode" msgstr "Chế độ hub" diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index 7e98480cd..ddca350e8 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -2839,8 +2839,8 @@ msgstr "本地交换机" msgid "Remote Switch" msgstr "远程交换机" -msgid "Switch:" -msgstr "交换机:" +msgid "Shared secret:" +msgstr "共享秘密:" msgid "Hub Mode" msgstr "集线器模式" diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index 78365a911..f1d720adc 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -2839,8 +2839,8 @@ msgstr "本地交換器" msgid "Remote Switch" msgstr "遠端交換器" -msgid "Switch:" -msgstr "交換器:" +msgid "Shared secret:" +msgstr "共享秘密:" msgid "Hub Mode" msgstr "集線器模式" From 2d9374190c67e7715fc5c09fa3827c8393a5b51d Mon Sep 17 00:00:00 2001 From: Mike Swanson Date: Tue, 10 Feb 2026 01:58:35 -0800 Subject: [PATCH 07/14] net_switch: build secret_hash header as a separate component The prior code did a memmove over the packet data, and in cases where a packet is completely full (large transfers under an MTU 1500, for instance), it would corrupt the data packet and nothing got transferred. In its place, teach the code to build up the secret_hash header as a separate component and send a larger packet (by 32 bytes). The original packet remains intact and will get received by the intended target this way. --- src/network/net_switch.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/network/net_switch.c b/src/network/net_switch.c index 938443997..001575348 100644 --- a/src/network/net_switch.c +++ b/src/network/net_switch.c @@ -386,19 +386,14 @@ net_switch_thread(void *priv) if (!(net_cards_conf[netswitch->card->card_num].link_state & NET_LINK_DOWN)) { for (int i = 0; i < packets; i++) { int orig_len = netswitch->pkt_tx_v[i].len; - int send_len = orig_len + 32; + int send_len = orig_len + sizeof(netswitch->secret_hash); - if (send_len > NET_MAX_FRAME) { - netswitch_log("Network Switch: packet too large to add header (%d bytes)\n", - orig_len); - continue; - } - - /* Prepend secret hash data */ - memmove(netswitch->pkt_tx_v[i].data + 32, - netswitch->pkt_tx_v[i].data, - orig_len); - memcpy(netswitch->pkt_tx_v[i].data, netswitch->secret_hash, 32); + /* Build header with secret hash */ + uint8_t augmented[sizeof(netswitch->secret_hash) + NET_MAX_FRAME]; + uint8_t *hdr = augmented; + memcpy(hdr, netswitch->secret_hash, sizeof(netswitch->secret_hash)); + memcpy(augmented + sizeof(netswitch->secret_hash), + netswitch->pkt_tx_v[i].data, orig_len); #define MAC_FORMAT "(%02X:%02X:%02X:%02X:%02X:%02X -> %02X:%02X:%02X:%02X:%02X:%02X)" #define MAC_FORMAT_ARGS(p) (p)[38], (p)[39], (p)[40], (p)[41], (p)[42], (p)[43], (p)[32], (p)[33], (p)[34], (p)[35], (p)[36], (p)[37] @@ -407,8 +402,7 @@ net_switch_thread(void *priv) /* Send through all known host interfaces. */ for (net_switch_hostaddr_t *hostaddr = netswitch->hostaddrs; hostaddr; hostaddr = hostaddr->next) - sendto(hostaddr->socket_tx, - (char *) netswitch->pkt_tx_v[i].data, send_len, 0, + sendto(hostaddr->socket_tx, augmented, send_len, 0, &hostaddr->addr_tx.sa, sizeof(hostaddr->addr_tx.sa)); } } @@ -432,16 +426,21 @@ net_switch_thread(void *priv) } if (pfd[NET_EVENT_RX].revents & POLLIN) { #endif - len = recv(netswitch->socket_rx, (char *) netswitch->pkt.data, NET_MAX_FRAME, 0); - if (len < 44) { + len = recv(netswitch->socket_rx, (char *) netswitch->pkt.data, NET_MAX_FRAME + sizeof(netswitch->secret_hash), 0); + if (len < sizeof(netswitch->secret_hash) + 12) { netswitch_log("Network Switch: recv error (%d)\n", len); + continue; } - if (memcmp(netswitch->pkt.data, netswitch->secret_hash, 32) != 0) { + if (memcmp(netswitch->pkt.data, netswitch->secret_hash, sizeof(netswitch->secret_hash)) != 0) { /* This packet contains a different secret hash, ignore it. */ continue; } else { - memmove(netswitch->pkt.data, netswitch->pkt.data + 32, len - 32); + memmove(netswitch->pkt.data, + netswitch->pkt.data + sizeof(netswitch->secret_hash), + len - sizeof(netswitch->secret_hash)); + len = len - sizeof(netswitch->secret_hash); + netswitch->pkt.len = len; } if ((AS_U64(netswitch->pkt.data[6]) & le64_to_cpu(0xffffffffffffULL)) == netswitch->mac_addr_u64) { From 16068c28b111fd4daa922425e468e3674cfc6612 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Tue, 10 Feb 2026 20:27:23 +0100 Subject: [PATCH 08/14] Proper (so to say) clock table for the RTG310x cards Based on a xfree 3.3.6 realtek svga driver source, this commit implements a proper clock table for the RTG310x cards (both -5 and -6). Fixes wrong refresh rates on Windows drivers and DOS possibly. --- src/video/vid_rtg310x.c | 77 +++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/src/video/vid_rtg310x.c b/src/video/vid_rtg310x.c index 76b8d8f3f..f43e7f643 100644 --- a/src/video/vid_rtg310x.c +++ b/src/video/vid_rtg310x.c @@ -76,7 +76,7 @@ rtg_in(uint16_t addr, void *priv) case 0x3cf: if (svga->gdcaddr == 0x0c) - return svga->gdcreg[0x0c] | 4; + return svga->gdcreg[0x0c] | 0x04; else if ((svga->gdcaddr > 8) && (svga->gdcaddr != 0x0c)) return svga->gdcreg[svga->gdcaddr]; break; @@ -89,13 +89,13 @@ rtg_in(uint16_t addr, void *priv) return dev->type << 6; if (svga->crtcreg == 0x1e) { ret = svga->crtc[0x1e]; - ret &= ~3; + ret &= ~0x03; if (dev->vram_size == 1024) - ret = 2; + ret = 0x02; else if (dev->vram_size == 512) - ret = 1; + ret = 0x01; else - ret = 0; + ret = 0x00; return ret; } return svga->crtc[svga->crtcreg]; @@ -207,60 +207,60 @@ rtg_out(uint16_t addr, uint8_t val, void *priv) static void rtg_recalctimings(svga_t *svga) { - const rtg_t *dev = (rtg_t *) svga->priv; + const rtg_t *dev = (rtg_t *) svga->priv; + int clk_sel = ((svga->miscout >> 2) & 0x03) | ((svga->gdcreg[0x0c] & 0x20) >> 3); svga->memaddr_latch |= ((svga->crtc[0x19] & 0x10) << 16) | ((svga->crtc[0x19] & 0x40) << 17); - svga->interlace = (svga->crtc[0x19] & 1); + svga->interlace = (svga->crtc[0x19] & 0x01); - /*Clock table not available, currently a guesswork*/ - switch (((svga->miscout >> 2) & 3) | ((svga->gdcreg[0x0c] & 0x20) >> 3)) { - case 0: - case 1: - break; + /*Source: xfree86 3.3.6 source code, rt_driver.c.*/ + switch (clk_sel) { case 2: - svga->clock = (cpuclock * (double) (1ULL << 32)) / 36000000.0; - break; - case 3: - svga->clock = (cpuclock * (double) (1ULL << 32)) / 65100000.0; - break; - case 4: svga->clock = (cpuclock * (double) (1ULL << 32)) / 44900000.0; break; + case 3: + svga->clock = (cpuclock * (double) (1ULL << 32)) / 71600000.0; + break; + case 4: + svga->clock = (cpuclock * (double) (1ULL << 32)) / 73000000.0; + break; case 5: - svga->clock = (cpuclock * (double) (1ULL << 32)) / 50000000.0; + svga->clock = (cpuclock * (double) (1ULL << 32)) / 64000000.0; break; case 6: - svga->clock = (cpuclock * (double) (1ULL << 32)) / 80000000.0; + svga->clock = (cpuclock * (double) (1ULL << 32)) / 84000000.0; break; case 7: - svga->clock = (cpuclock * (double) (1ULL << 32)) / 75000000.0; + svga->clock = (cpuclock * (double) (1ULL << 32)) / 79000000.0; break; default: break; } - switch (svga->gdcreg[0x0c] & 3) { - case 1: - svga->clock /= 1.5; - break; - case 2: - svga->clock /= 2; - break; - case 3: - svga->clock /= 4; - break; + if (clk_sel >= 2) { + switch (svga->gdcreg[0x0b] & 0x03) { + case 1: + svga->clock *= 1.5; + break; + case 2: + svga->clock *= 2.0; + break; + case 3: + svga->clock *= 4.0; + break; - default: - break; + default: + break; + } } if (!svga->scrblank && (svga->crtc[0x17] & 0x80) && svga->attr_palette_enable) { if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { switch (svga->gdcreg[5] & 0x60) { case 0x00: - if (svga->seqregs[1] & 8) /*Low res (320)*/ + if (svga->seqregs[1] & 0x08) /*Low res (320)*/ svga->render = svga_render_4bpp_lowres; else { if (svga->hdisp == 1280) @@ -270,17 +270,18 @@ rtg_recalctimings(svga_t *svga) } break; case 0x20: /*4 colours*/ - if (svga->seqregs[1] & 8) /*Low res (320)*/ + if (svga->seqregs[1] & 0x08) /*Low res (320)*/ svga->render = svga_render_2bpp_lowres; else svga->render = svga_render_2bpp_highres; break; case 0x40: case 0x60: - if (svga->crtc[0x19] & 2) { - if (svga->hdisp == 1280) + if (svga->crtc[0x19] & 0x02) { + if (svga->hdisp == 1280) { svga->hdisp >>= 1; - else if (dev->type == 2) + svga->dots_per_clock >>= 1; + } else if (dev->type == 2) svga->rowoffset <<= 1; svga->render = svga_render_8bpp_highres; From 04aea9404973817b99c0bea9c23f0ecb566488b7 Mon Sep 17 00:00:00 2001 From: Bozo Scum Date: Wed, 11 Feb 2026 10:44:28 +0800 Subject: [PATCH 09/14] Update zh-TW.po * use more appropriate Traditional Chinese term for 'Shared Secret' --- src/qt/languages/zh-TW.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index f1d720adc..2b2189f2c 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -2840,7 +2840,7 @@ msgid "Remote Switch" msgstr "遠端交換器" msgid "Shared secret:" -msgstr "共享秘密:" +msgstr "共用秘鑰:" msgid "Hub Mode" msgstr "集線器模式" From 752bed01ceec463fb85200c8b4d3229aacf1ffb4 Mon Sep 17 00:00:00 2001 From: Mike Swanson Date: Tue, 10 Feb 2026 22:22:00 -0800 Subject: [PATCH 10/14] net_switch: Use old packet construction with no shared secret MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This falls through to using 239.255.86.86 as the multicast address and excluding a shared secret hash, if no shared secret has been entered. This restores compatibility with QEMU’s `-netdev dgram` mode, as suggested by @richardg867. --- src/network/net_switch.c | 82 ++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 29 deletions(-) diff --git a/src/network/net_switch.c b/src/network/net_switch.c index 001575348..ced2f0392 100644 --- a/src/network/net_switch.c +++ b/src/network/net_switch.c @@ -81,6 +81,7 @@ typedef struct net_switch_t { net_switch_hostaddr_t *hostaddrs; uint16_t port_out; + uint8_t secret_enabled; uint8_t secret_hash[32]; uint8_t promisc; union { @@ -197,10 +198,12 @@ net_switch_add_hostaddr(net_switch_t *netswitch, net_switch_sockaddr_t *addr, ne } /* Join IPv4 multicast group. */ - struct ip_mreq mreq = { - .imr_multiaddr = { .s_addr = htonl(SWITCH_MULTICAST_GROUP) }, - .imr_interface = { .s_addr = hostaddr->addr.sin.sin_addr.s_addr } - }; + struct ip_mreq mreq = { .imr_interface = { .s_addr = hostaddr->addr.sin.sin_addr.s_addr } }; + if (netswitch->secret_enabled) + mreq.imr_multiaddr.s_addr = htonl(SWITCH_MULTICAST_GROUP); + else + mreq.imr_multiaddr.s_addr = htonl(SWITCH_MULTICAST_GROUP + 0x600); // 239.255.86.86 + if (setsockopt(netswitch->socket_rx, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq)) < 0) { netswitch_log("Network Switch: could not join multicast group on interface %s\n", buf); goto broadcast; @@ -386,24 +389,34 @@ net_switch_thread(void *priv) if (!(net_cards_conf[netswitch->card->card_num].link_state & NET_LINK_DOWN)) { for (int i = 0; i < packets; i++) { int orig_len = netswitch->pkt_tx_v[i].len; - int send_len = orig_len + sizeof(netswitch->secret_hash); - - /* Build header with secret hash */ + int send_len = orig_len; uint8_t augmented[sizeof(netswitch->secret_hash) + NET_MAX_FRAME]; - uint8_t *hdr = augmented; - memcpy(hdr, netswitch->secret_hash, sizeof(netswitch->secret_hash)); - memcpy(augmented + sizeof(netswitch->secret_hash), - netswitch->pkt_tx_v[i].data, orig_len); + if (netswitch->secret_enabled) { + send_len = orig_len + sizeof(netswitch->secret_hash); + + /* Build header with secret hash */ + uint8_t *hdr = augmented; + memcpy(hdr, netswitch->secret_hash, sizeof(netswitch->secret_hash)); + memcpy(augmented + sizeof(netswitch->secret_hash), + netswitch->pkt_tx_v[i].data, orig_len); + } #define MAC_FORMAT "(%02X:%02X:%02X:%02X:%02X:%02X -> %02X:%02X:%02X:%02X:%02X:%02X)" +#define MAC_FORMAT_NOSECRET_ARGS(p) (p)[6], (p)[7], (p)[8], (p)[9], (p)[10], (p)[11], (p)[0], (p)[1], (p)[2], (p)[3], (p)[4], (p)[5] #define MAC_FORMAT_ARGS(p) (p)[38], (p)[39], (p)[40], (p)[41], (p)[42], (p)[43], (p)[32], (p)[33], (p)[34], (p)[35], (p)[36], (p)[37] netswitch_log("Network Switch: sending %d-byte packet " MAC_FORMAT "\n", - netswitch->pkt_tx_v[i].len, MAC_FORMAT_ARGS(netswitch->pkt_tx_v[i].data)); + netswitch->pkt_tx_v[i].len, + netswitch->secret_enabled ? MAC_FORMAT_ARGS(netswitch->pkt_tx_v[i].data) + : MAC_FORMAT_NOSECRET_ARGS(netswitch->pkt_tx_v[i].data)); /* Send through all known host interfaces. */ for (net_switch_hostaddr_t *hostaddr = netswitch->hostaddrs; hostaddr; hostaddr = hostaddr->next) - sendto(hostaddr->socket_tx, augmented, send_len, 0, - &hostaddr->addr_tx.sa, sizeof(hostaddr->addr_tx.sa)); + if (netswitch->secret_enabled) + sendto(hostaddr->socket_tx, (char *)augmented, send_len, 0, + &hostaddr->addr_tx.sa, sizeof(hostaddr->addr_tx.sa)); + else + sendto(hostaddr->socket_tx, (char *)netswitch->pkt_tx_v[i].data, + send_len, 0, &hostaddr->addr_tx.sa, sizeof(hostaddr->addr_tx.sa)); } } netswitch->during_tx = 0; @@ -426,24 +439,32 @@ net_switch_thread(void *priv) } if (pfd[NET_EVENT_RX].revents & POLLIN) { #endif - len = recv(netswitch->socket_rx, (char *) netswitch->pkt.data, NET_MAX_FRAME + sizeof(netswitch->secret_hash), 0); - if (len < sizeof(netswitch->secret_hash) + 12) { - netswitch_log("Network Switch: recv error (%d)\n", len); - continue; - } + if (netswitch->secret_enabled) { + len = recv(netswitch->socket_rx, (char *) netswitch->pkt.data, NET_MAX_FRAME + sizeof(netswitch->secret_hash), 0); + if (len < sizeof(netswitch->secret_hash) + 12) { + netswitch_log("Network Switch: recv error (%d)\n", len); + continue; + } - if (memcmp(netswitch->pkt.data, netswitch->secret_hash, sizeof(netswitch->secret_hash)) != 0) { - /* This packet contains a different secret hash, ignore it. */ - continue; + if (memcmp(netswitch->pkt.data, netswitch->secret_hash, sizeof(netswitch->secret_hash)) != 0) { + /* This packet contains a different secret hash, ignore it. */ + continue; + } else { + memmove(netswitch->pkt.data, + netswitch->pkt.data + sizeof(netswitch->secret_hash), + len - sizeof(netswitch->secret_hash)); + len = len - sizeof(netswitch->secret_hash); + netswitch->pkt.len = len; + } } else { - memmove(netswitch->pkt.data, - netswitch->pkt.data + sizeof(netswitch->secret_hash), - len - sizeof(netswitch->secret_hash)); - len = len - sizeof(netswitch->secret_hash); - netswitch->pkt.len = len; + len = recv(netswitch->socket_rx, (char *) netswitch->pkt.data, NET_MAX_FRAME, 0); + if (len < 12) { + netswitch_log("Network Switch: recv error (%d)\n", len); + continue; + } } - if ((AS_U64(netswitch->pkt.data[6]) & le64_to_cpu(0xffffffffffffULL)) == netswitch->mac_addr_u64) { + if ((AS_U64(netswitch->pkt.data[netswitch->secret_enabled ? 38 : 6]) & le64_to_cpu(0xffffffffffffULL)) == netswitch->mac_addr_u64) { /* A packet we've sent has looped back, drop it. */ } else if (!(net_cards_conf[netswitch->card->card_num].link_state & NET_LINK_DOWN) && (netswitch->promisc || /* promiscuous mode? */ (netswitch->pkt.data[0] & 1) || /* broadcast packet? */ @@ -482,10 +503,13 @@ net_switch_init(const netcard_t *card, const uint8_t *mac_addr, void *priv, char netswitch->card = (netcard_t *) card; netswitch->promisc = !!netcard->promisc_mode; - { + if (netcard->secret[0] != '\0') { uint8_t temp[32]; net_switch_secret_hash((const uint8_t *)netcard->secret, (uint8_t *) temp); memcpy(netswitch->secret_hash, temp, 32); + netswitch->secret_enabled = 1; + } else { + netswitch->secret_enabled = 0; } /* Initialize receive socket. */ From 84326e0cb6ebdcbc61d15f52ab9f59ea38dd7976 Mon Sep 17 00:00:00 2001 From: BlueRain-debug Date: Tue, 10 Feb 2026 17:06:50 +0000 Subject: [PATCH 11/14] Translated using Weblate (Chinese (Simplified Han script)) Currently translated at 100.0% (1005 of 1005 strings) Translation: 86Box/86Box Translate-URL: https://weblate.86box.net/projects/86box/86box/zh_Hans/ --- src/qt/languages/zh-CN.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index ddca350e8..706c7f8ad 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -1,6 +1,6 @@ msgid "" msgstr "" -"PO-Revision-Date: 2026-01-23 17:57+0000\n" +"PO-Revision-Date: 2026-02-11 06:30+0000\n" "Last-Translator: BlueRain-debug \n" "Language-Team: Chinese (Simplified Han script) \n" @@ -2840,7 +2840,7 @@ msgid "Remote Switch" msgstr "远程交换机" msgid "Shared secret:" -msgstr "共享秘密:" +msgstr "共享密钥:" msgid "Hub Mode" msgstr "集线器模式" From e9f8a6ca3ce511bb5ce14912f0cf8ad96fea3c7f Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 11 Feb 2026 08:08:19 +0100 Subject: [PATCH 12/14] Fix the shared secret string in Greek, Japanese, Portuguese (Brazil), Portuguese (Portugal), and Slovenian. --- src/qt/languages/el-GR.po | 2 +- src/qt/languages/ja-JP.po | 2 +- src/qt/languages/pt-BR.po | 2 +- src/qt/languages/pt-PT.po | 2 +- src/qt/languages/sl-SI.po | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/qt/languages/el-GR.po b/src/qt/languages/el-GR.po index 6f10bbba9..7465743e0 100644 --- a/src/qt/languages/el-GR.po +++ b/src/qt/languages/el-GR.po @@ -2884,7 +2884,7 @@ msgid "Remote Switch" msgstr "Απομακρυσμένος Διακόπτης" msgid "Shared secret:" -msgstr "κοινό μυστικό:" +msgstr "Κοινό μυστικό:" msgid "Hub Mode" msgstr "Λειτουργία Hub" diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index 2961a28f3..487e5e297 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -2840,7 +2840,7 @@ msgid "Remote Switch" msgstr "リモートスイッチ" msgid "Shared secret:" -msgstr "きょうゆうひみつ:" +msgstr "共有秘密:" msgid "Hub Mode" msgstr "ハブモード" diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index 05829de13..bd95c22ce 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -2833,7 +2833,7 @@ msgid "Remote Switch" msgstr "Switch Remoto" msgid "Shared secret:" -msgstr "Segredo compartihado:" +msgstr "Segredo compartilhado:" msgid "Hub Mode" msgstr "Modo Hub" diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index 87619edf7..123376ee1 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -2840,7 +2840,7 @@ msgid "Remote Switch" msgstr "Comutador remoto" msgid "Shared secret:" -msgstr "Segredo compartihado:" +msgstr "Segredo partilhado:" msgid "Hub Mode" msgstr "Modo de concentrador" diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index b4d857e6a..bbddd9a7e 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -2841,7 +2841,7 @@ msgid "Remote Switch" msgstr "Oddaljeno stikalo" msgid "Shared secret:" -msgstr "Skupni skrivnost:" +msgstr "Skupna skrivnost:" msgid "Hub Mode" msgstr "Način koncentratorja" From b636ed3b920a6d480637cc7abfb07876e3aa91c0 Mon Sep 17 00:00:00 2001 From: WNT50 <173389620+WNT50@users.noreply.github.com> Date: Wed, 11 Feb 2026 15:23:15 +0800 Subject: [PATCH 13/14] Add IBM PS/2 Model 30-286 rev. 0 BIOS --- src/include/86box/machine.h | 3 ++ src/machine/m_ps2_isa.c | 66 ++++++++++++++++++++++++++++++++++--- src/machine/machine_table.c | 2 +- 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index b7702e55b..3b65952a2 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -1382,6 +1382,9 @@ extern const device_t ps1_hdc_device; #endif /* m_ps2_isa.c */ +#ifdef EMU_DEVICE_H +extern const device_t ps2_m30_286_device; +#endif extern int machine_ps2_m30_286_init(const machine_t *); /* m_ps2_mca.c */ diff --git a/src/machine/m_ps2_isa.c b/src/machine/m_ps2_isa.c index 5754eee11..04c4279c8 100644 --- a/src/machine/m_ps2_isa.c +++ b/src/machine/m_ps2_isa.c @@ -146,6 +146,58 @@ ps2_read(uint16_t port, void *priv) return temp; } +static const device_config_t ps2_m30_286_config[] = { + // clang-format off + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "ibmps2_m30_286", + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { + { + .name = "Model 30-286 rev. 0 BIOS", + .internal_name = "ibmps2_m30_286_rev0", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 131072, + .files = { "roms/machines/ibmps2_m30_286/27F4092.BIN", "" } + }, + { + .name = "Model 30-286 rev. 2 BIOS", + .internal_name = "ibmps2_m30_286", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 131072, + .files = { "roms/machines/ibmps2_m30_286/33f5381a.bin", "" } + }, + { .files_no = 0 } + } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t ps2_m30_286_device = { + .name = "IBM PS/2 model 30-286", + .internal_name = "ps2_m30_286_device", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ps2_m30_286_config +}; + + static void ps2_isa_setup(int model, int cpu_type) { @@ -208,14 +260,18 @@ ps2_isa_common_init(const machine_t *model) int machine_ps2_m30_286_init(const machine_t *model) { - int ret; + int ret = 0; + const char *fn; - ret = bios_load_linear("roms/machines/ibmps2_m30_286/33f5381a.bin", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) + /* No ROMs available */ + if (!device_available(model->device)) return ret; + device_context(model->device); + fn = device_get_bios_file(machine_get_device(machine), device_get_config_bios("bios"), 0); + ret = bios_load_linear(fn, 0x000e0000, 131072, 0); + device_context_restore(); + ps2_isa_common_init(model); ps2_isa_setup(30, 286); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index c67a22c04..240e2d255 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -3202,7 +3202,7 @@ const machine_t machines[] = { .kbc_p1 = 0x00000cf0, .gpio = 0xffffffff, .gpio_acpi = 0xffffffff, - .device = NULL, + .device = &ps2_m30_286_device, .kbd_device = NULL, .fdc_device = NULL, .sio_device = NULL, From e064caac73bbe8c1d9697dbd0fadcd2c05d9d3dd Mon Sep 17 00:00:00 2001 From: WNT50 <173389620+WNT50@users.noreply.github.com> Date: Wed, 11 Feb 2026 15:30:27 +0800 Subject: [PATCH 14/14] Fix memory size report for IBM PS/2 model 30-286 --- src/device/kbc_at.c | 9 +++++++++ src/include/86box/machine.h | 1 + src/machine/m_ps2_isa.c | 25 +++++++++++++++++++++++++ src/machine/machine_table.c | 2 +- 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 4cb23428e..d50dfb5d1 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -2184,6 +2184,7 @@ read_p1(atkbc_t *dev) ----------------- IBM PS/1: xxxxxxxx IBM PS/2 MCA: xxxxx1xx + IBM PS/2 Model 30-286: xxxxx1xx Intel AMI Pentium BIOS'es with AMI MegaKey KB-5 keyboard controller: x1x1xxxx Acer: xxxxx0xx Packard Bell PB450: xxxxx1xx @@ -2198,6 +2199,7 @@ read_p1(atkbc_t *dev) Acer: Pull down bit 6 if primary display is MDA. Pull down bit 2 always (must be so to enable CMOS Setup). IBM PS/1: Pull down bit 6 if current floppy drive is 3.5". + IBM PS/2 Model 30-286: Pull down bits 5 and 4 based on planar memory size. Epson Action Tower 2600: Pull down bit 3 always (for Epson logo). NCR: Pull down bit 5 always (power-on default speed = high). Pull down bit 3 if there is no FPU. @@ -2216,11 +2218,18 @@ read_p1(atkbc_t *dev) Compaq: 0 = Compaq dual-scan display, 1 = non-Compaq display. Bit 5: Mostly, manufacturing jumper: 0 = installed (infinite loop at POST), 1 = not installed; NCR: power-on default speed: 0 = high, 1 = low; + IBM PS/2 Model 30-286: memory presence detect pin 1; Compaq: System board DIP switch 5: 0 = ON, 1 = OFF. Bit 4: (Which board?): RAM on motherboard: 0 = 512 kB, 1 = 256 kB; NCR: RAM on motherboard: 0 = unsupported, 1 = 512 kB; Intel AMI MegaKey KB-5: Must be 1; IBM PS/1: Ignored; + IBM PS/2 Model 30-286: memory presence detect pin 2; + Bit 5, 4: + 1, 1: 256Kx2 SIMM memory installed; + 1, 0: 256Kx4 SIMM memory installed; + 0, 1: 1Mx2 SIMM memory installed; + 0, 0: 1Mx4 SIMM memory installed. Compaq: 0 = Auto speed selected, 1 = High speed selected. Bit 3: TriGem AMIKey: most significant bit of 2-bit OEM ID; NCR: Coprocessor detect (1 = yes, 0 = no); diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 3b65952a2..79a457e26 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -426,6 +426,7 @@ extern uint8_t machine_compaq_p1_handler(void); extern uint8_t machine_generic_p1_handler(void); extern uint8_t machine_ncr_p1_handler(void); extern uint8_t machine_ps1_p1_handler(void); +extern uint8_t machine_ps2_isa_p1_handler(void); extern uint8_t machine_t3100e_p1_handler(void); extern uint8_t machine_get_p1_default(void); diff --git a/src/machine/m_ps2_isa.c b/src/machine/m_ps2_isa.c index 04c4279c8..64a8da2ed 100644 --- a/src/machine/m_ps2_isa.c +++ b/src/machine/m_ps2_isa.c @@ -257,6 +257,31 @@ ps2_isa_common_init(const machine_t *model) device_add(&port_6x_ps2_device); } +uint8_t +machine_ps2_isa_p1_handler(void) +{ + uint8_t mem_p1; + + switch (mem_size / 1024) { + case 0: /*256Kx2*/ + mem_p1 = 0xf0; + break; + case 1: /*256Kx4*/ + mem_p1 = 0xe0; + break; + case 2: /*1Mx2*/ + case 3: + mem_p1 = 0xd0; + break; + case 4: /*1Mx4*/ + default: + mem_p1 = 0xc0; + break; + } + + return mem_p1; +} + int machine_ps2_m30_286_init(const machine_t *model) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 240e2d255..ee16c4675 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -3173,7 +3173,7 @@ const machine_t machines[] = { .type = MACHINE_TYPE_286, .chipset = MACHINE_CHIPSET_PROPRIETARY, .init = machine_ps2_m30_286_init, - .p1_handler = machine_generic_p1_handler, + .p1_handler = machine_ps2_isa_p1_handler, .gpio_handler = NULL, .available_flag = MACHINE_AVAILABLE, .gpio_acpi_handler = NULL,