git: a098fd021e51 - main - loader: request DHCP initmd option

From: Warner Losh <imp_at_FreeBSD.org>
Date: Fri, 11 Sep 2026 05:04:25 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=a098fd021e517df930d8df0ac3a808d63c24252b

commit a098fd021e517df930d8df0ac3a808d63c24252b
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2026-09-11 04:13:57 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2026-09-11 04:15:28 +0000

    loader: request DHCP initmd option
    
    Request FreeBSD RFC 3925 PEM 2238 DHCP 125 option. Use suboption 1 to
    specify a ramdisk image to load and use to load the kernel and as the
    root file system.
    
    Differential Revision:  https://reviews.freebsd.org/D59428
    Sponsored by:           Netflix
---
 stand/libsa/bootp.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 stand/libsa/bootp.h |  5 +++++
 2 files changed, 63 insertions(+), 1 deletion(-)

diff --git a/stand/libsa/bootp.c b/stand/libsa/bootp.c
index 6008f0bf8f11..f708006169d0 100644
--- a/stand/libsa/bootp.c
+++ b/stand/libsa/bootp.c
@@ -69,6 +69,7 @@ static	char vm_cmu[4] = VM_CMU;
 static	ssize_t bootpsend(struct iodesc *, void *, size_t);
 static	ssize_t bootprecv(struct iodesc *, void **, void **, time_t, void *);
 static	int vend_rfc1048(u_char *, u_int);
+static	void vend_vivso(const u_char *, size_t);
 #ifdef BOOTP_VEND_CMU
 static	void vend_cmu(u_char *);
 #endif
@@ -122,6 +123,15 @@ bootp_fill_request(unsigned char *bp_vend)
 	bcopy("FreeBSD", &bp_vend[off], 7);
 	off += 7;
 
+	/* Vendor-Identifying Vendor Class, RFC 3925. */
+	bp_vend[off++] = TAG_VI_VENDOR_CLASS;
+	bp_vend[off++] = 12;
+	be32enc(&bp_vend[off], FREEBSD_ENTERPRISE_NUMBER);
+	off += 4;
+	bp_vend[off++] = 7;
+	bcopy("FreeBSD", &bp_vend[off], 7);
+	off += 7;
+
 	/*
 	 * Client architecture (RFC 4578).  Value is 2 bytes big-endian.
 	 * Omit entirely for loaders that don't have a spec-defined value.
@@ -146,7 +156,7 @@ bootp_fill_request(unsigned char *bp_vend)
 	bp_vend[off++] = 1472 & 0xff;
 
 	bp_vend[off++] = TAG_PARAM_REQ;
-	bp_vend[off++] = 7;
+	bp_vend[off++] = 8;
 	bp_vend[off++] = TAG_ROOTPATH;
 	bp_vend[off++] = TAG_HOSTNAME;
 	bp_vend[off++] = TAG_SWAPSERVER;
@@ -154,6 +164,7 @@ bootp_fill_request(unsigned char *bp_vend)
 	bp_vend[off++] = TAG_SUBNET_MASK;
 	bp_vend[off++] = TAG_INTF_MTU;
 	bp_vend[off++] = TAG_SERVERID;
+	bp_vend[off++] = TAG_VI_VENDOR_OPTS;
 	bp_vend[off] = TAG_END;
 }
 
@@ -497,6 +508,8 @@ vend_rfc1048(u_char *cp, u_int len)
 			if (intf_mtu <= 0)
 				intf_mtu = be16dec(cp);
 		}
+		if (tag == TAG_VI_VENDOR_OPTS)
+			vend_vivso(cp, size);
 #ifdef SUPPORT_DHCP
 		if (tag == TAG_DHCP_MSGTYPE) {
 			if(*cp != expected_dhcpmsgtype)
@@ -513,6 +526,49 @@ vend_rfc1048(u_char *cp, u_int len)
 	return(0);
 }
 
+static void
+vend_freebsd(const u_char *cp, size_t len)
+{
+	char value[256];
+	size_t size;
+	u_char tag;
+
+	while (len >= 2) {
+		tag = *cp++;
+		size = *cp++;
+		len -= 2;
+		if (size > len)
+			return;
+		if (tag == FREEBSD_VI_INITMD && size < sizeof(value)) {
+			bcopy(cp, value, size);
+			value[size] = '\0';
+			setenv("dhcp.initmd", value, 0);
+		}
+		cp += size;
+		len -= size;
+	}
+}
+
+static void
+vend_vivso(const u_char *cp, size_t len)
+{
+	uint32_t enterprise;
+	size_t size;
+
+	while (len >= 5) {
+		enterprise = be32dec(cp);
+		cp += 4;
+		size = *cp++;
+		len -= 5;
+		if (size > len)
+			return;
+		if (enterprise == FREEBSD_ENTERPRISE_NUMBER)
+			vend_freebsd(cp, size);
+		cp += size;
+		len -= size;
+	}
+}
+
 #ifdef BOOTP_VEND_CMU
 static void
 vend_cmu(u_char *cp)
@@ -687,6 +743,7 @@ static struct dhcp_opt dhcp_opt[] = {
 	{86,	__TXT,	"nds-tree-name"},
 	{87,	__TXT,	"nds-context"},
 	{210,	__TXT,	"authenticate"},
+	{125,	__NONE, "vendor-identifying-vendor-options"},
 
 	/* use the following entries for arbitrary variables */
 	{246,	__ILIST, ""},
diff --git a/stand/libsa/bootp.h b/stand/libsa/bootp.h
index 577449a79292..d5f65d0c6981 100644
--- a/stand/libsa/bootp.h
+++ b/stand/libsa/bootp.h
@@ -108,6 +108,11 @@ struct bootp {
 #define TAG_CLIENTID		((unsigned char)  61)
 #define TAG_USER_CLASS		((unsigned char)  77)
 #define TAG_CLIENT_ARCH		((unsigned char)  93)	/* RFC 4578 */
+#define TAG_VI_VENDOR_CLASS	((unsigned char) 124)	/* RFC 3925 */
+#define TAG_VI_VENDOR_OPTS	((unsigned char) 125)	/* RFC 3925 */
+
+#define FREEBSD_ENTERPRISE_NUMBER	2238
+#define FREEBSD_VI_INITMD		1
 #endif
 
 #define TAG_END			((unsigned char) 255)