From 406340d6191029cbf06a2ccf9e2d2291004d20fe Mon Sep 17 00:00:00 2001 From: Jonathan Dieter Date: Mon, 5 Oct 2026 12:02:25 +0100 Subject: [PATCH] tap_user: fix DHCP lease renewal losing guest connectivity DHCP was only handled locally when the client source address was zero and no UDP forwarding entry existed for its source port. Renewal requests use the leased address, so they fell through to ordinary UDP forwarding instead of reaching RVVM's DHCP server. Guests could acquire an address at boot but fail to renew it and lose connectivity when the lease expired. Intercept IPv4 DHCP client traffic from port 68 to port 67 at the gateway or broadcast address before looking up UDP forwarding entries. Send replies to the client address in ciaddr when it is set, keeping broadcast replies for initial address acquisition. Assisted-By: GPT-6 Signed-off-by: Jonathan Dieter --- src/devices/tap_user.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/devices/tap_user.c b/src/devices/tap_user.c index e67d39141..40c8e4cc3 100644 --- a/src/devices/tap_user.c +++ b/src/devices/tap_user.c @@ -352,7 +352,8 @@ static void handle_dhcp(tap_dev_t* tap, const uint8_t* buffer, size_t size, net_ uint8_t frame[TAP_FRAME_SIZE]; uint8_t* ipv4 = create_eth_frame(tap, frame, ETH2_IPv4); - uint8_t* udp = create_ipv4_frame(ipv4, 278 + UDP_HDR_SIZE, IP_PROTO_UDP, (const uint8_t*)"\xFF\xFF\xFF\xFF", GATEWAY_IP); + const uint8_t* reply_ip = read_uint32_be_m(buffer + 12) ? buffer + 12 : (const uint8_t*)"\xFF\xFF\xFF\xFF"; + uint8_t* udp = create_ipv4_frame(ipv4, 278 + UDP_HDR_SIZE, IP_PROTO_UDP, reply_ip, GATEWAY_IP); uint8_t* dhcp = create_udp_datagram(udp, 278, 68, 67); dhcp[0] = OP_RESPONSE; @@ -450,15 +451,16 @@ static void handle_udp(tap_dev_t* tap, const uint8_t* buffer, size_t size, net_a } udp_size -= UDP_HDR_SIZE; + // Renewals use the leased source IP; intercept before any UDP forwarding entry. + if (src->type == NET_TYPE_IPV4 && src->port == 68 && dst->port == 67 + && (memcmp(dst->ip, GATEWAY_IP, PLEN_IPv4) == 0 || read_uint32_be_m(dst->ip) == 0xFFFFFFFF)) { + handle_dhcp(tap, udb_buff, udp_size, src); + return; + } + spin_lock(&tap->lock); tap_sock_t* ts = (tap_sock_t*)hashmap_get(&tap->udp_ports, src->port); if (ts == NULL) { - if (dst->port == 67 && (read_uint32_be_m(src->ip) == 0)) { - spin_unlock(&tap->lock); - handle_dhcp(tap, udb_buff, udp_size, src); - return; - } - net_sock_t* sock = net_udp_bind(NET_IPV4_ANY); net_sock_set_blocking(sock, false); if (sock) {