From nobody Thu Jul 30 02:27:07 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4h9Y4d4BPRz6mMTB for ; Thu, 30 Jul 2026 02:27:13 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR1" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4h9Y4d2C9gz3CPW for ; Thu, 30 Jul 2026 02:27:13 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1785378433; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=9E35tGn3414cmZkL1DLw64fKKY5tnzKREThzH9pela0=; b=nA16DHjRXouylsTuGT8YeY6PZ2dWJEM13/sy9zW04v9AupeYpwnbSQufNruaAJ04Okcjtm NMgbRq+ErViALbxoF8vcmBbaKinU7g/cUze5KoVVDTDsUEJ68Z8AxVaAsiztKgjI4rzN+D IsWr/EumAHRrgj4+hyoFcLGfQq14rvNOV2eGFFEsiG5d4ibTjS9QES/igXCja7BQScy+7U wlfZEOu+IV+CxWFYhsCCu8j4shXRfhR9by7tphVU/LMlvTN3tPm+kdtLANwyrjHqljSPAi eGb9K0fa1b2K42Y07iJc4HK/LRPgMn3p7+qKMJ4Vou8JVGyzjdDg96KIS8djNg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1785378433; a=rsa-sha256; cv=none; b=K4qNnMO/6YmD+7m68gt1SwkvSHlLOWTrcgTSbSnwLO7Iqjb0BYJctXcP7wY9bhPQqAmtjW ff6zg01v6+klrr3bwFf0ex5MOJrTNL0F9ZMgMHgdVeIMA+lDXnpTb2oMxUJeHtWq6MUuxD eL2tpOEjE5Z/LtgsdPsaxMmiK4aXcQqLnpWBmuXFyfMxqkXjeteCrwqAsDxCTTG3U3I5Kf fJ2R4dAV4pEw8uDl+TVo/DJU4Klgt7TAEgocDDFHJ16GWJIjycGoZAiT8CbxAcJIvinKEK joPD54sun3h9iY3AuyzC1R7okWp7ZvBaQSV8AQ74tZ0aSvxlDfg60dZ9iwo+YA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1785378433; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=9E35tGn3414cmZkL1DLw64fKKY5tnzKREThzH9pela0=; b=DlBaYUXBoRBHhCge+xPNsLE506gSZ6VwTbAeXMAzNMsrMtmO9mRojZiDt2+YGmuhRz25SJ Hc48/qB6Nlj17NC2m6ZBIEw9sQ+kos/Yp9H9XIePDQoTd2UVMlD4JGZE/vkJhxHqrzgsND awjGgBPrCLfImM3fKK6j40xlj5f+s2BpaIvyNAFj9vOEYK8aPVsV65AIbqxA1RbnwRF2nW UxVSRLxh3C82Jtt/h7mjUBF7P+VLwYT/ixQbpzrmGSc3YUCNPulj2A/YJX7dqYTl2nL9Rw beGp4oXIzm3qX5eBVEIaFALyxS2IjydSa+KLvfALnmo+p2Lpzdu4aPRnpGFt9A== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4h9Y4d0ZTTzthP for ; Thu, 30 Jul 2026 02:27:13 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 1920b by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Thu, 30 Jul 2026 02:27:07 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Alexander Motin Subject: git: 88229544807f - main - stand: Cleanup use of cached DHCP response packet List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: mav X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 88229544807f0f8aedd202a980f251df5757fe5c Auto-Submitted: auto-generated Date: Thu, 30 Jul 2026 02:27:07 +0000 Message-Id: <6a6ab67b.1920b.1269126c@gitrepo.freebsd.org> The branch main has been updated by mav: URL: https://cgit.FreeBSD.org/src/commit/?id=88229544807f0f8aedd202a980f251df5757fe5c commit 88229544807f0f8aedd202a980f251df5757fe5c Author: Alexander Motin AuthorDate: 2026-07-30 02:12:22 +0000 Commit: Alexander Motin CommitDate: 2026-07-30 02:26:46 +0000 stand: Cleanup use of cached DHCP response packet - When cached response is available, actually use xid from one instead of using its byte-swapped value for BIOS and 1 for UEFI. - If cached response is not available, generate pseudo-random xid, since use of a constant may cause conflicts if two systems are booting same time, and server sends responses as broadcast. - When cached response is available, skip DHCP DISCOVER/OFFER and just send REQUEST to the DHCP server from the cached response. We could skip this phase too and just use the cached response, but we don't know whether firmware requested all of DHCP options we'd like to get. Tested on amd64 Supermicro X11DPI-NT for both BIOS and EFI, with and without cached response packet. --- stand/efi/libefi/efinet.c | 1 - stand/i386/libi386/pxe.c | 5 -- stand/libsa/bootp.c | 135 +++++++++++++++++++++++++++++++++++----------- 3 files changed, 105 insertions(+), 36 deletions(-) diff --git a/stand/efi/libefi/efinet.c b/stand/efi/libefi/efinet.c index d3d975d21268..5c391d38a265 100644 --- a/stand/efi/libefi/efinet.c +++ b/stand/efi/libefi/efinet.c @@ -324,7 +324,6 @@ efinet_init(struct iodesc *desc, void *machdep_hint) #endif bcopy(net->Mode->CurrentAddress.Addr, desc->myea, 6); - desc->xid = 1; } static void diff --git a/stand/i386/libi386/pxe.c b/stand/i386/libi386/pxe.c index aa392b83718c..e0752eadccc2 100644 --- a/stand/i386/libi386/pxe.c +++ b/stand/i386/libi386/pxe.c @@ -413,11 +413,6 @@ pxe_netif_init(struct iodesc *desc, void *machdep_hint) for (i = 0; i < len; ++i) desc->myea[i] = mac[i]; - if (bootp_response != NULL) - desc->xid = bootp_response->bp_xid; - else - desc->xid = 0; - bio_free(undi_info_p, sizeof(*undi_info_p)); undi_open_p = bio_alloc(sizeof(*undi_open_p)); if (undi_open_p == NULL) diff --git a/stand/libsa/bootp.c b/stand/libsa/bootp.c index ac37553c6d34..5143bc91ff08 100644 --- a/stand/libsa/bootp.c +++ b/stand/libsa/bootp.c @@ -120,7 +120,7 @@ bootp_fill_request(unsigned char *bp_vend) void bootp(int sock) { - void *pkt; + void *pkt = NULL; struct iodesc *d; struct bootp *bp; struct { @@ -128,36 +128,28 @@ bootp(int sock) struct bootp wbootp; } wbuf; struct bootp *rbootp; + bool init_reboot = false; DEBUG_PRINTF(1, ("bootp: socket=%d\n", sock)); if (!bot) bot = getsecs(); - + if (!(d = socktodesc(sock))) { printf("bootp: bad socket. %d\n", sock); return; } DEBUG_PRINTF(1, ("bootp: socktodesc=%lx\n", (long)d)); +restart: bp = &wbuf.wbootp; bzero(bp, sizeof(*bp)); bp->bp_op = BOOTREQUEST; bp->bp_htype = 1; /* 10Mb Ethernet (48 bits) */ bp->bp_hlen = 6; - bp->bp_xid = htonl(d->xid); MACPY(d->myea, bp->bp_chaddr); strncpy(bp->bp_file, bootfile, sizeof(bp->bp_file)); bcopy(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)); -#ifdef SUPPORT_DHCP - bp->bp_vend[4] = TAG_DHCP_MSGTYPE; - bp->bp_vend[5] = 1; - bp->bp_vend[6] = DHCPDISCOVER; - bootp_fill_request(&bp->bp_vend[7]); - -#else - bp->bp_vend[4] = TAG_END; -#endif d->myip.s_addr = INADDR_ANY; d->myport = htons(IPPORT_BOOTPC); @@ -165,47 +157,130 @@ bootp(int sock) d->destport = htons(IPPORT_BOOTPS); #ifdef SUPPORT_DHCP - expected_dhcpmsgtype = DHCPOFFER; - dhcp_ok = 0; + /* + * If a DHCP reply is already cached (populated by a lower layer + * that captured it from firmware, e.g. UEFI PXE Base Code), enter + * RFC 2131 § 4.3.2 INIT-REBOOT: skip DISCOVER/OFFER and go + * straight to REQUEST with option 50 = cached IP. The DHCP + * server confirms the lease with an ACK containing whatever + * options this client asks for, which may be a superset of what + * the firmware asked for (e.g. option 26 interface-MTU, option 16 + * swap-server). On NAK or timeout, fall back to a full + * DISCOVER/OFFER/REQUEST/ACK cycle. + */ + if (bootp_response != NULL && + bootp_response->bp_yiaddr.s_addr != INADDR_ANY) { + init_reboot = true; + rbootp = bootp_response; + d->xid = ntohl(rbootp->bp_xid); + DEBUG_PRINTF(1, ("bootp: using cached DHCP reply " + "(INIT-REBOOT), yiaddr=%s xid=0x%08x\n", + inet_ntoa(rbootp->bp_yiaddr), (unsigned)d->xid)); + } else #endif + if (d->xid == 0) { + /* + * RFC 951 / RFC 2131 § 4.1 recommend a random xid. + * Without a real RNG in the loader, seed from the + * interface MAC (host-unique) mixed with the current + * time (unique across reboots on the same host). This + * avoids the pre-existing behavior of every fresh + * BOOTP/DHCP client sending xid=0, which risks + * broadcast-reply mis-correlation when several PXE + * clients boot concurrently — bootprecv() enforces + * xid matching. + */ + memcpy(&d->xid, &d->myea[2], sizeof(d->xid)); + d->xid ^= (uint32_t)getsecs(); + } + bp->bp_xid = htonl(d->xid); - if(sendrecv(d, - bootpsend, bp, sizeof(*bp), - bootprecv, &pkt, (void **)&rbootp, NULL) == -1) { - printf("bootp: no reply\n"); - return; + if (!init_reboot) { +#ifdef SUPPORT_DHCP + bp->bp_vend[4] = TAG_DHCP_MSGTYPE; + bp->bp_vend[5] = 1; + bp->bp_vend[6] = DHCPDISCOVER; + bootp_fill_request(&bp->bp_vend[7]); + expected_dhcpmsgtype = DHCPOFFER; + dhcp_ok = 0; +#else + bp->bp_vend[4] = TAG_END; +#endif + + if (sendrecv(d, + bootpsend, bp, sizeof(*bp), + bootprecv, &pkt, (void **)&rbootp, NULL) == -1) { + printf("bootp: no reply\n"); + return; + } } #ifdef SUPPORT_DHCP - if(dhcp_ok) { + if (dhcp_ok || init_reboot) { uint32_t leasetime; + int off; + + bp->bp_vend[4] = TAG_DHCP_MSGTYPE; + bp->bp_vend[5] = 1; bp->bp_vend[6] = DHCPREQUEST; bp->bp_vend[7] = TAG_REQ_ADDR; bp->bp_vend[8] = 4; bcopy(&rbootp->bp_yiaddr, &bp->bp_vend[9], 4); - bp->bp_vend[13] = TAG_SERVERID; - bp->bp_vend[14] = 4; - bcopy(&dhcp_serverip.s_addr, &bp->bp_vend[15], 4); - bp->bp_vend[19] = TAG_LEASETIME; - bp->bp_vend[20] = 4; + off = 13; + if (!init_reboot) { + /* SELECTING: server-id identifies the server whose + * OFFER we accepted. INIT-REBOOT omits it (RFC 2131 + * § 4.3.2). */ + bp->bp_vend[off++] = TAG_SERVERID; + bp->bp_vend[off++] = 4; + bcopy(&dhcp_serverip.s_addr, &bp->bp_vend[off], 4); + off += 4; + } + bp->bp_vend[off++] = TAG_LEASETIME; + bp->bp_vend[off++] = 4; leasetime = htonl(300); - bcopy(&leasetime, &bp->bp_vend[21], 4); - bootp_fill_request(&bp->bp_vend[25]); + bcopy(&leasetime, &bp->bp_vend[off], 4); + off += 4; + bootp_fill_request(&bp->bp_vend[off]); expected_dhcpmsgtype = DHCPACK; - free(pkt); - if(sendrecv(d, + if (pkt != NULL) { + free(pkt); + pkt = NULL; + } + if (sendrecv(d, bootpsend, bp, sizeof(*bp), bootprecv, &pkt, (void **)&rbootp, NULL) == -1) { + if (init_reboot) { + printf("bootp: INIT-REBOOT failed, " + "falling back to DISCOVER\n"); + free(bootp_response); + bootp_response = NULL; + bootp_response_size = 0; + init_reboot = false; + if (pkt != NULL) { + free(pkt); + pkt = NULL; + } + goto restart; + } printf("DHCPREQUEST failed\n"); return; } + if (init_reboot) + DEBUG_PRINTF(1, ("bootp: INIT-REBOOT ACK received\n")); } #endif myip = d->myip = rbootp->bp_yiaddr; - servip = rbootp->bp_siaddr; + /* + * Preserve a pre-set servip (e.g. seeded by PXE-consuming code + * from a ProxyDHCP offer) when the ACK's siaddr is zero, which is + * typical for non-PXE-aware primary DHCP servers. + */ + if (rbootp->bp_siaddr.s_addr != INADDR_ANY) + servip = rbootp->bp_siaddr; if (rootip.s_addr == INADDR_ANY) rootip = servip; bcopy(rbootp->bp_file, bootfile, sizeof(bootfile));