]> gitweb.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
a2065: drop frames that cannot fit receive ring
authorStefan Reinauer <stefan.reinauer@coreboot.org>
Fri, 5 Jun 2026 04:41:45 +0000 (21:41 -0700)
committerStefan Reinauer <stefan.reinauer@coreboot.org>
Tue, 7 Jul 2026 20:47:38 +0000 (13:47 -0700)
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

index 33e9813f23bbdd9fbac726b4a1cd9873f0865cbe..6e0f1065c259713d07523c3842ee424d0c67ea39 100644 (file)
--- 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))