The branch main has been updated by mav:

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

commit 495826f69d96857bf0559516502e058ecab4ee4d
Author:     Alexander Motin <[email protected]>
AuthorDate: 2026-08-04 02:23:55 +0000
Commit:     Alexander Motin <[email protected]>
CommitDate: 2026-08-04 02:23:55 +0000

    stand: add ARCH and MSZ into DHCP requests
    
    It should give DHCP servers more information for proper responses.
---
 stand/efi/libefi/efinet.c | 18 ++++++++++++
 stand/i386/libi386/pxe.c  |  3 ++
 stand/libsa/bootp.c       | 75 ++++++++++++++++++++++++++++++++++++-----------
 stand/libsa/bootp.h       |  7 +++++
 4 files changed, 86 insertions(+), 17 deletions(-)

diff --git a/stand/efi/libefi/efinet.c b/stand/efi/libefi/efinet.c
index e91b5f73ddf2..26a84e0e8d8e 100644
--- a/stand/efi/libefi/efinet.c
+++ b/stand/efi/libefi/efinet.c
@@ -570,6 +570,24 @@ efinet_dev_init(void)
        int err, i, nifs;
        extern struct devsw netdev;
 
+       /*
+        * Advertise our DHCP Client-System Architecture (RFC 4578).  Many
+        * x86_64 UEFI firmwares report themselves as "EFI BC" (0x0007)
+        * rather than "EFI x86-64" (0x0009); match that convention for
+        * best DHCP-server config compatibility.
+        */
+#if defined(__amd64__)
+       bootp_client_arch = 0x0007;     /* EFI BC */
+#elif defined(__i386__)
+       bootp_client_arch = 0x0006;     /* EFI IA32 */
+#elif defined(__aarch64__)
+       bootp_client_arch = 0x000b;     /* EFI 64-bit ARM */
+#elif defined(__arm__)
+       bootp_client_arch = 0x000a;     /* EFI 32-bit ARM */
+#elif defined(__riscv)
+       bootp_client_arch = 0x001b;     /* EFI 64-bit RISC-V */
+#endif
+
        sz = 0;
        handles = NULL;
        status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz, NULL);
diff --git a/stand/i386/libi386/pxe.c b/stand/i386/libi386/pxe.c
index e0752eadccc2..dc65230acdc9 100644
--- a/stand/i386/libi386/pxe.c
+++ b/stand/i386/libi386/pxe.c
@@ -149,6 +149,9 @@ pxe_init(void)
        if (pxenv_p == NULL)
                return (0);
 
+       /* RFC 4578 § 2.1: BIOS PXE is a 32-bit "Standard PC BIOS" client. */
+       bootp_client_arch = 0x0000;
+
        /* look for "PXENV+" */
        if (bcmp((void *)pxenv_p->Signature, S_SIZE("PXENV+"))) {
                pxenv_p = NULL;
diff --git a/stand/libsa/bootp.c b/stand/libsa/bootp.c
index 927db86abdd8..6008f0bf8f11 100644
--- a/stand/libsa/bootp.c
+++ b/stand/libsa/bootp.c
@@ -87,33 +87,74 @@ struct in_addr dhcp_serverip;
 struct bootp *bootp_response;
 size_t bootp_response_size;
 
+/*
+ * DHCP Client-System Architecture per RFC 4578 (option 93).  Each netif
+ * driver that has a spec-defined value for what it is sets this from
+ * its own init path (e.g. efinet_dev_init on UEFI, pxe_init on legacy
+ * BIOS PXE).  BOOTP_ARCH_UNSET means the loader has no honest value to
+ * report (e.g. U-Boot or OpenFirmware, for which RFC 4578 has no
+ * assignment), and the option is omitted from the DHCP request rather
+ * than misrepresenting the client.
+ */
+#define        BOOTP_ARCH_UNSET        0xFFFF
+uint16_t bootp_client_arch = BOOTP_ARCH_UNSET;
+
 static void
 bootp_fill_request(unsigned char *bp_vend)
 {
+       int off = 0;
+
        /*
         * We are booting from PXE, we want to send the string
         * 'PXEClient' to the DHCP server so you have the option of
         * only responding to PXE aware dhcp requests.
         */
-       bp_vend[0] = TAG_CLASSID;
-       bp_vend[1] = 9;
-       bcopy("PXEClient", &bp_vend[2], 9);
-       bp_vend[11] = TAG_USER_CLASS;
+       bp_vend[off++] = TAG_CLASSID;
+       bp_vend[off++] = 9;
+       bcopy("PXEClient", &bp_vend[off], 9);
+       off += 9;
+
+       bp_vend[off++] = TAG_USER_CLASS;
        /* len of each user class + number of user class */
-       bp_vend[12] = 8;
+       bp_vend[off++] = 8;
        /* len of the first user class */
-       bp_vend[13] = 7;
-       bcopy("FreeBSD", &bp_vend[14], 7);
-       bp_vend[21] = TAG_PARAM_REQ;
-       bp_vend[22] = 7;
-       bp_vend[23] = TAG_ROOTPATH;
-       bp_vend[24] = TAG_HOSTNAME;
-       bp_vend[25] = TAG_SWAPSERVER;
-       bp_vend[26] = TAG_GATEWAY;
-       bp_vend[27] = TAG_SUBNET_MASK;
-       bp_vend[28] = TAG_INTF_MTU;
-       bp_vend[29] = TAG_SERVERID;
-       bp_vend[30] = TAG_END;
+       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.
+        */
+       if (bootp_client_arch != BOOTP_ARCH_UNSET) {
+               bp_vend[off++] = TAG_CLIENT_ARCH;
+               bp_vend[off++] = 2;
+               bp_vend[off++] = (bootp_client_arch >> 8) & 0xff;
+               bp_vend[off++] = bootp_client_arch & 0xff;
+       }
+
+       /*
+        * Maximum DHCP message size we can accept (RFC 2132).  The loader's
+        * UDP read path allocates dynamically per packet up to the interface
+        * MTU, so advertise ~MTU to unlock large option payloads that some
+        * servers would otherwise trim to the RFC 2131 § 4.4.1 576-byte
+        * default.
+        */
+       bp_vend[off++] = TAG_MAXSIZE;
+       bp_vend[off++] = 2;
+       bp_vend[off++] = (1472 >> 8) & 0xff;
+       bp_vend[off++] = 1472 & 0xff;
+
+       bp_vend[off++] = TAG_PARAM_REQ;
+       bp_vend[off++] = 7;
+       bp_vend[off++] = TAG_ROOTPATH;
+       bp_vend[off++] = TAG_HOSTNAME;
+       bp_vend[off++] = TAG_SWAPSERVER;
+       bp_vend[off++] = TAG_GATEWAY;
+       bp_vend[off++] = TAG_SUBNET_MASK;
+       bp_vend[off++] = TAG_INTF_MTU;
+       bp_vend[off++] = TAG_SERVERID;
+       bp_vend[off] = TAG_END;
 }
 
 /* Fetch required bootp infomation */
diff --git a/stand/libsa/bootp.h b/stand/libsa/bootp.h
index 57601e025bf5..577449a79292 100644
--- a/stand/libsa/bootp.h
+++ b/stand/libsa/bootp.h
@@ -107,6 +107,7 @@ struct bootp {
 #define TAG_CLASSID            ((unsigned char)  60)
 #define TAG_CLIENTID           ((unsigned char)  61)
 #define TAG_USER_CLASS         ((unsigned char)  77)
+#define TAG_CLIENT_ARCH                ((unsigned char)  93)   /* RFC 4578 */
 #endif
 
 #define TAG_END                        ((unsigned char) 255)
@@ -144,4 +145,10 @@ struct cmu_vend {
 extern struct bootp *bootp_response;
 extern size_t bootp_response_size;
 
+/*
+ * DHCP option 93 (Client-System Architecture, RFC 4578).  Netif drivers
+ * with RFC 4578 defined identity set this so bootp() emits the option.
+ */
+extern uint16_t bootp_client_arch;
+
 #endif /* _BOOTP_H_ */

Reply via email to