From d6d9c368e91c541a68eb1bdb697d38a85ba4fcf6 Mon Sep 17 00:00:00 2001 From: d00f <8052722+DrDoof@users.noreply.github.com> Date: Tue, 8 Sep 2026 01:55:37 +0200 Subject: [PATCH 1/2] Refresh ARP entries from incoming IP traffic uip_arp_ipin() is an empty macro with its body under #if 0, both inherited from the uIP import and untouched since. That leaves uip_arp_update() reachable only from uip_arp_arpin(), so an entry is refreshed only by ARP addressed to us and ages out after UIP_ARP_MAXAGE no matter how much traffic passed over it. When it goes, the next transmission to that host hits the miss path of uip_arp_out(), which overwrites the packet in uip_buf with an ARP request and returns. For TCP that costs a retransmission. For UDP nothing retransmits, and handle_tx() sends the UDP connections through uip_arp_out() too, so the datagram is lost. The body could not be enabled as written: uip_len -= sizeof(struct uip_eth_hdr) is a leftover from when UIP_LLH_LEN was 0. Here it is ETHER_HEADER_SIZE + RTL_FRAME_DESC_SIZE and uip.c reads the IP header at uip_buf[UIP_LLH_LEN], so uip_len has to keep the link layer in it. The rest of the function is sound. --- rtlplayground.c | 2 +- uip/uip_arp.c | 6 +----- uip/uip_arp.h | 3 +-- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/rtlplayground.c b/rtlplayground.c index 700df0b8..6d88e145 100644 --- a/rtlplayground.c +++ b/rtlplayground.c @@ -1252,7 +1252,7 @@ void handle_rx(void) } } else if (ETH_IN->ether_type == HTONS(0x0800)) { // IPv4 if (!management_vlan || management_vlan == rx_packet_vlan) { - uip_arp_ipin(); // Learn MAC addresses in TCP packets + uip_arp_ipin(); uip_input(); if (uip_len) { // Add ethernet frame diff --git a/uip/uip_arp.c b/uip/uip_arp.c index 44bee6c4..42d48213 100644 --- a/uip/uip_arp.c +++ b/uip/uip_arp.c @@ -239,12 +239,9 @@ uip_arp_update(__xdata u16_t * __xdata ipaddr, __xdata struct uip_eth_addr * __x * variable uip_len. */ /*-----------------------------------------------------------------------------------*/ -#if 0 void -uip_arp_ipin(void) +uip_arp_ipin(void) __banked { - uip_len -= sizeof(struct uip_eth_hdr); - /* Only insert/update an entry if the source IP address of the incoming IP packet comes from a host on the local network. */ if((IPBUF->srcipaddr[0] & uip_netmask[0]) != @@ -259,7 +256,6 @@ uip_arp_ipin(void) return; } -#endif /* 0 */ /*-----------------------------------------------------------------------------------*/ /** * ARP processing for incoming ARP packets. diff --git a/uip/uip_arp.h b/uip/uip_arp.h index 833d7c22..57930979 100644 --- a/uip/uip_arp.h +++ b/uip/uip_arp.h @@ -78,8 +78,7 @@ void uip_arp_init(void) __banked; inserts a new mapping if none exists. The function assumes that an IP packet with an Ethernet header is present in the uip_buf buffer and that the length of the packet is in the uip_len variable. */ -/*void uip_arp_ipin(void);*/ -#define uip_arp_ipin() +void uip_arp_ipin(void) __banked; /* The uip_arp_arpin() should be called when an ARP packet is received by the Ethernet driver. This function also assumes that the From 1c8cdab4bfc2228a2ee41c54e4a9b886969731f2 Mon Sep 17 00:00:00 2001 From: d00f <8052722+DrDoof@users.noreply.github.com> Date: Sun, 13 Sep 2026 04:14:21 +0200 Subject: [PATCH 2/2] arp: take the sender MAC from where a received frame keeps it IPBUF is laid out for frames we send, with the 12 byte TX descriptor in front of the Ethernet header. A received frame starts with the Ethernet header at uip_buf[0] and carries the RTL and VLAN tags after the addresses, so IPBUF->ethhdr.src read the port mask and both VLAN fields as a MAC. Every IP packet from the local network then replaced the sender's ARP entry with that, and our replies went to an address nobody has. The IP source address sits at the same offset in both layouts, which is why the rest looked right. Use BUF, the receive view uip_arp_arpin() already works from. --- uip/uip_arp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uip/uip_arp.c b/uip/uip_arp.c index 42d48213..45318d26 100644 --- a/uip/uip_arp.c +++ b/uip/uip_arp.c @@ -252,7 +252,7 @@ uip_arp_ipin(void) __banked (uip_hostaddr[1] & uip_netmask[1])) { return; } - uip_arp_update(IPBUF->srcipaddr, &(IPBUF->ethhdr.src)); + uip_arp_update(IPBUF->srcipaddr, &(BUF->ethhdr.src)); return; }