From f4c186eb54447008756e890921c3e006547bd9eb Mon Sep 17 00:00:00 2001 From: Stefan Reinauer Date: Thu, 4 Jun 2026 21:41:45 -0700 Subject: [PATCH] a2065: drop frames that cannot fit receive ring The receive queue can stall forever if the packet at its head is larger than the current descriptor ring can accept. Check the full frame size, including padding and FCS bytes, before trying to drain the queue. Drop packets that can never fit and reject packets that would overflow the temporary frame buffer when the emulated FCS is appended. --- a2065.cpp | 48 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/a2065.cpp b/a2065.cpp index 33e9813f..6e0f1065 100644 --- a/a2065.cpp +++ b/a2065.cpp @@ -430,6 +430,11 @@ static void gotfunc2(void *devv, const uae_u8 *databuf, int len) // winpcap does not include checksum bytes if (!(csr[4] & 0x0400)) { // ASTRP_RCV + if (len > MAX_PACKET_SIZE - 4) { + if (log_a2065) + write_log (_T("7990: oversize frame with FCS, %d bytes\n"), len); + return; + } crc32 = get_crc32 (d, len); d[len++] = crc32 >> 24; d[len++] = crc32 >> 16; @@ -526,15 +531,41 @@ static bool receive_queue_pop(uae_u8 *data, int *len) return got; } +static int receive_packet_buffer_size(int len) +{ + if (len <= 0 || len > MAX_PACKET_SIZE) + return -1; + if (!(csr[4] & 0x0400) && len > MAX_PACKET_SIZE - 4) /* ASTRP_RCV */ + return -1; + int needed = len < 60 ? 60 : len; + if (!(csr[4] & 0x0400)) /* ASTRP_RCV */ + needed += 4; + return needed; +} + +static bool receive_packet_can_fit(int len) +{ + int needed = receive_packet_buffer_size(len); + + if (needed < 0 || !am_initialized || !am_rdr_rlen) + return false; + for (int i = 0; i < am_rdr_rlen; i++) { + const int offset = (rdr_offset + i) % am_rdr_rlen; + const uae_u32 off = am_rdr_rdra + offset * 8; + const uae_u16 rmd2 = get_ram_word(off + 4); + needed -= 65536 - rmd2; + if (needed <= 0) + return true; + } + return false; +} + static bool receive_space_available(int len) { - int needed; + int needed = receive_packet_buffer_size(len); - if (!am_initialized || !(csr[0] & CSR0_RXON) || !am_rdr_rlen) + if (needed < 0 || !am_initialized || !(csr[0] & CSR0_RXON) || !am_rdr_rlen) return false; - needed = len < 60 ? 60 : len; - if (!(csr[4] & 0x0400)) /* ASTRP_RCV */ - needed += 4; for (int i = 0; i < am_rdr_rlen; i++) { const int offset = (rdr_offset + i) % am_rdr_rlen; const uae_u32 off = am_rdr_rdra + offset * 8; @@ -557,6 +588,13 @@ static void receive_queue_drain(void) int len = receive_queue_peek_size(); if (len <= 0) return; + if (!receive_packet_can_fit(len)) { + if (!receive_queue_pop(packet, &len)) + return; + if (log_a2065) + write_log(_T("7990: dropping frame that does not fit receive ring, %d bytes\n"), len); + continue; + } if (!receive_space_available(len)) return; if (!receive_queue_pop(packet, &len)) -- 2.47.3