git: 495826f69d96 - main - stand: add ARCH and MSZ into DHCP requests
Alexander Motin <[email protected]> Tue, 04 Aug 2026 02:29:19 +0000
| Newsgroups | gmane.os.freebsd.devel.cvs.src,gmane.os.freebsd.current.scm |
|---|---|
| Message-ID | <[email protected]> |
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_ */