diff --git a/Changelog.md b/Changelog.md
index 472e3db6d00..a3bcd80bbd1 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,5 +1,10 @@
OpenCore Changelog
==================
+#### v1.0.4
+- Added support for booting from static IPv4 address to OpenCore-specific HttpBootDxe
+- Added static IPv4 configuration options to OpenNetworkBoot
+- Removed `--` prefix from OpenNetworkBoot arguments (modify driver arguments if using this driver)
+
#### v1.0.3
- Fixed support for `AMD_CPU_EXT_FAMILY_1AH`, thx @Shaneee
- Fixed EHCI handoff logic in OpenDuet, causing older machines to hang at start
diff --git a/Docs/Configuration.md5 b/Docs/Configuration.md5
index 358dc279b53..cbab4628c6c 100644
--- a/Docs/Configuration.md5
+++ b/Docs/Configuration.md5
@@ -1 +1 @@
-42906709c8db3c5b923b8ba1e2f6d432
+4728e88d95bbba6d7add29638587fb98
diff --git a/Docs/Configuration.pdf b/Docs/Configuration.pdf
index 0639cfd8d8f..d2755a59a12 100644
Binary files a/Docs/Configuration.pdf and b/Docs/Configuration.pdf differ
diff --git a/Docs/Configuration.tex b/Docs/Configuration.tex
index 0743c542d45..516aa00ee11 100755
--- a/Docs/Configuration.tex
+++ b/Docs/Configuration.tex
@@ -4119,7 +4119,7 @@ \subsection{Debug Properties}\label{miscdebugprops}
\item \texttt{HDA} --- AudioDxe
\item \texttt{KKT} --- KeyTester
\item \texttt{LNX} --- OpenLinuxBoot
- \item \texttt{NTBT} --- OpenNetworkBoot
+ \item \texttt{NETB} --- OpenNetworkBoot
\item \texttt{MMDD} --- MmapDump
\item \texttt{OCPAVP} --- PavpProvision
\item \texttt{OCRST} --- ResetSystem
@@ -6576,7 +6576,7 @@ \subsection{Drivers}\label{uefidrivers}
to allow direct detection and booting of Linux distributions from OpenCore, without
chainloading via GRUB. \\
\href{https://github.com/acidanthera/OpenCorePkg}{\texttt{OpenNetworkBoot}}\textbf{*}
-& \hyperref[uefipxe]{OpenCore plugin} implementing \texttt{OC\_BOOT\_ENTRY\_PROTOCOL}
+& \hyperref[uefinetboot]{OpenCore plugin} implementing \texttt{OC\_BOOT\_ENTRY\_PROTOCOL}
to show available PXE and HTTP(S) boot options on the OpenCore boot menu. \\
\href{https://github.com/acidanthera/OpenCorePkg}{\texttt{OpenNtfsDxe}}\textbf{*}
& New Technologies File System (NTFS) read-only driver.
@@ -7091,7 +7091,7 @@ \subsubsection{Additional information}
therefore \texttt{efibootmgr} rather than \texttt{bootctl} must be used for any low-level Linux command line interaction
with the boot menu.
-\subsection{OpenNetworkBoot}\label{uefipxe}
+\subsection{OpenNetworkBoot}\label{uefinetboot}
OpenNetworkBoot is an OpenCore plugin implementing \texttt{OC\_BOOT\_ENTRY\_PROTOCOL}.
It enables PXE and HTTP(S) Boot options in the OpenCore menu if these
@@ -7113,67 +7113,121 @@ \subsection{OpenNetworkBoot}\label{uefipxe}
PXE and HTTP(S) Boot is provided on
\href{https://github.com/acidanthera/OpenCorePkg/blob/master/Platform/OpenNetworkBoot/README.md}{this page}.
-The following configuration options may be specified in the \texttt{Arguments} section for this driver:
-
-\begin{itemize}
- \item \texttt{-4} - Boolean flag, enabled if present. \medskip
-
- If specified enable IPv4 for PXE and HTTP(S) Boot. Disable IPV6
- unless the \texttt{-6} flag is also present. If neither flag is
- present, both are enabled by default. \medskip
+The below configuration options may be specified in the \texttt{Arguments} section for this driver.
- \item \texttt{-6} - Boolean flag, enabled if present. \medskip
+\emph{Note}: There is no problem if configuration options within \texttt{...} are given on
+multiple lines, and option values enclosed within quotes can also span multiple lines. This applies to all drivers
+which use OpenCore argument parsing, and can be particularly convenient when multiple long options such as \texttt{uri},
+\texttt{static4} and particularly \texttt{enroll-cert} may be needed.
- If specified enable IPv6 for PXE and HTTP(S) Boot. Disable IPV4
- unless the \texttt{-4} flag is also present. If neither flag is
- present, both are enabled by default. \medskip
-
- \item \texttt{-{}-aux} - Boolean flag, enabled if present. \medskip
+\begin{itemize}
+ \item \texttt{aux} - Boolean flag, enabled if present. \medskip
If specified the driver will generate auxiliary boot entries. \medskip
- \item \texttt{-{}-delete-all-certs[:\{OWNER\_GUID\}]} - Default: not set. \medskip
+ \item \texttt{delete-all-certs[:\{OWNER\_GUID\}]} - Default: not set. \medskip
If specified, delete all certificates present for \texttt{OWNER\_GUID}.
- \texttt{OWNER\_GUID} is optional, and will default to all zeros if not specified. \medskip
+ \texttt{OWNER\_GUID} is optional, and will default to all zeros if not specified.
+ \medskip
- \item \texttt{-{}-delete-cert[:\{OWNER\_GUID\}]="\{cert-text\}"} - Default: not set. \medskip
+ \item \texttt{delete-cert[:\{OWNER\_GUID\}]="\{cert-text\}"} - Default: not set. \medskip
If specified, delete the given certificate(s) for HTTPS Boot. The certificate(s) can be specified
as a multi-line PEM value between double quotes.
- \texttt{OWNER\_GUID} is optional, and will default to all zeros if not specified.
A single PEM file can contain one or more certicates.
Multiple instances of this option can be used to delete multiple different
PEM files, if required.
+ \texttt{OWNER\_GUID} is optional, and will default to all zeros if not specified.
+ \medskip
- \item \texttt{-{}-enroll-cert[:\{OWNER\_GUID\}]="\{cert-text\}"} - Default: not set. \medskip
+ \item \texttt{enroll-cert[:\{OWNER\_GUID\}]="\{cert-text\}"} - Default: not set. \medskip
If specified, enroll the given certificate(s) for HTTPS Boot. The certificate(s) can be specified
as a multi-line PEM value between double quotes.
- \texttt{OWNER\_GUID} is optional, and will default to all zeros if not specified.
A single PEM file can contain one or more certicates.
Multiple instances of this option can be used to enroll multiple different
- PEM files, if required. \medskip
+ PEM files, if required.
+ \texttt{OWNER\_GUID} is optional, and will default to all zeros if not specified.
+ \medskip
- \item \texttt{-{}-http} - Boolean flag, enabled if present. \medskip
+ \item \texttt{http} - Boolean flag, enabled if present. \medskip
If specified enable HTTP(S) Boot. Disable PXE Boot unless
- the \texttt{-{}-pxe} flag is also present. If neither flag is
+ the \texttt{pxe} flag is also present. If neither flag is
present, both are enabled by default. \medskip
- \item \texttt{-{}-https} - Boolean flag, enabled if present. \medskip
+ \item \texttt{https} - Boolean flag, enabled if present. \medskip
If enabled, allow only \texttt{https://} URIs for HTTP(S) Boot.
- Additionally has the same behaviour as the \texttt{-{}-http} flag. \medskip
+ Additionally has the same behaviour as the \texttt{http} flag. \medskip
- \item \texttt{-{}-pxe} - Boolean flag, enabled if present. \medskip
+ \item \texttt{ipv4} - Boolean flag, enabled if present. \medskip
+
+ If specified enable IPv4 for PXE and HTTP(S) Boot. Disable IPV6
+ unless the \texttt{ipv6} flag is also present. If neither flag is
+ present, both are enabled by default. \medskip
+
+ \item \texttt{ipv6} - Boolean flag, enabled if present. \medskip
+
+ If specified enable IPv6 for PXE and HTTP(S) Boot. Disable IPV4
+ unless the \texttt{ipv4} flag is also present. If neither flag is
+ present, both are enabled by default. \medskip
+
+ \item \texttt{pxe} - Boolean flag, enabled if present. \medskip
If specified enable PXE Boot, and disable HTTP(S) Boot unless
- the \texttt{-{}-http} or \texttt{-{}-https} flags are present.
+ the \texttt{http} or \texttt{https} flags are present.
If none of these flags are present, both PXE and HTTP(S) Boot are
enabled by default. \medskip
- \item \texttt{-{}-uri} - String value, no default. \medskip
+ \item \texttt{static4:\{MAC\_ADDR\}[\textbackslash VLAN\_ID][="\{IP\},\{MASK\},\{GATEWAY\}[,\{DNS\}]"]} - String value. \medskip
+
+ Specify static IPv4 address for the network interface with the MAC address given by \texttt{MAC\_ADDR}. \texttt{MAC\_ADDR}
+ must be specified as 12 consecutive hex digits, with no spaces, colons or hyphens separating digit pairs. In some advanced
+ use-cases such as iSCSI, the MAC address length may be some other even number length of hex digits. The required
+ MAC address can be found in the names of the boot options produced by this driver. Note that
+ hyphens separating digit pairs must be removed, as compared to the format displayed in boot option names.
+ It is also possible to specify a VLAN ID to use on the interface, by adding a backslash
+ followed by a 4 digit hex representation of the VLAN ID following the MAC address. The VLAN ID will also be
+ shown in the boot entry name, but note that it must be converted from decimal in the boot entry name to a
+ 4 digit hex number in this option.
+
+ Required elements in value are IP address in \texttt{IP}, network mask in \texttt{MASK}
+ and gateway in \texttt{GATEWAY}. Optional is an additional space separated list of one or more DNS servers
+ in \texttt{DNS}. \texttt{DNS} will be needed if the boot file URI includes a domain name rather than an IP address.
+
+ \texttt{MAC\_ADDR} is not optional.
+
+ If value is omitted, then any static IP for this MAC address (and VLAN ID when present) will be deleted.
+
+ \begin{itemize}
+ \item Example 1: \texttt{static4:112233445566="192.168.1.20,255.255.255.0,192.168.1.1,8.8.8.8 4.4.4.4"}.
+ \item Example 2: \texttt{static4:112233445566\textbackslash 0001="10.0.0.2,255.255.255.0,10.0.0.1"}.
+ \end{itemize}
+
+ \emph{Note 1}: This option is written to NVRAM and will remain present even if the option is removed from the driver
+ \texttt{Arguments}, unless NVRAM is cleared or an alternative value is written or the value deleted, using this option.
+
+ \emph{Note 2}: This setting will normally cause a static IP to be assigned during pre-boot, even in vendor-provided
+ network stacks. However, due to a quirk of the design of PXE and HTTP boot, any such static assignment will then be
+ ignored and DHCP used instead, during network boot. The OpenCore network stack (specifically \texttt{HttpBootDxe.efi})
+ is unusual in that it will allow HTTP boot from a static IP address, as long as an HTTP boot URI has also been specified,
+ using the \texttt{uri} option for this driver (or e.g. in the OVMF admin screens if using OVMF, or similar options
+ where present in other firmeare). If HTTP boot from static
+ IP is required, then any pre-existing vendor-specific version of \texttt{HttpBootDxe.efi} will need to be unloaded
+ (see \texttt{UEFI} \texttt{Unload} option) and the OpenCore version used instead.
+
+ \emph{Note 3}: If \texttt{Ip4Dxe} is loaded before OpenCore then any setting here will only take effect after one
+ reboot. If \texttt{Ip4Dxe} is loaded after \texttt{OpenNetworkBoot} the setting will take effect immediately.
+ \medskip
+
+ \emph{Note 4}: In the majority of cases this option is not required, and the default DHCP behaviour should be
+ preferred, since IP address conflicts are automatically avoided, and any IP address assigned by DHCP during network
+ boot will normally automatically match the IP address assigned in-OS, as the same MAC address is used in both cases.
+ \medskip
+
+ \item \texttt{uri} - String value, no default. \medskip
If present, specify the URI to use for HTTP(S) Boot. If not present then
DHCP boot options must be enabled on the network in order for HTTP(S)
@@ -7184,17 +7238,17 @@ \subsection{OpenNetworkBoot}\label{uefipxe}
\subsubsection{OpenNetworkBoot Certificate Management}
Certificates are enrolled to NVRAM storage, therefore once
-a certificate has been enrolled, it will remain enrolled even if the \texttt{-{}-enroll-cert} config
-option is removed. \texttt{-{}-delete-cert} or \texttt{-{}-delete-all-certs}
+a certificate has been enrolled, it will remain enrolled even if the \texttt{enroll-cert} config
+option is removed. \texttt{delete-cert} or \texttt{delete-all-certs}
should be used to remove enrolled certificates.
-Checking for certificate presence by the \texttt{-{}-enroll-cert}
-and \texttt{-{}-delete-cert} options uses the simple algorithm
+Checking for certificate presence by the \texttt{enroll-cert}
+and \texttt{delete-cert} options uses the simple algorithm
of matching by exact file contents, not by file meaning. The intended
-usage is to leave an \texttt{-{}-enroll-cert} option present in the config
+usage is to leave an \texttt{enroll-cert} option present in the config
file until it is time to delete it, e.g. after another more up-to-date
-\texttt{-{}-enroll-cert} option has been added and tested. At this point
-the user can change \texttt{-{}-enroll-cert} to \texttt{-{}-delete-cert}
+\texttt{enroll-cert} option has been added and tested. At this point
+the user can change \texttt{enroll-cert} to \texttt{delete-cert}
for the old certificate. \medskip
Certificate options are processed one at a time, in
@@ -7202,10 +7256,10 @@ \subsubsection{OpenNetworkBoot Certificate Management}
However each option will not change the NVRAM store if it is already correct
for the option at that point in time (e.g. will not enroll a certificate if it is
already enrolled).
-Avoid combinations such as \texttt{-{}-delete-all-certs} followed by
-\texttt{-{}-enroll-cert}, as this will modify the NVRAM certificate
+Avoid combinations such as \texttt{delete-all-certs} followed by
+\texttt{enroll-cert}, as this will modify the NVRAM certificate
storage twice on every boot. However a combination such as
-\texttt{-{}-delete-cert="\{certA-text\}"} followed by \texttt{-{}-enroll-cert="\{certB-text\}"}
+\texttt{delete-cert="\{certA-text\}"} followed by \texttt{enroll-cert="\{certB-text\}"}
(with \texttt{certA-text} and \texttt{certB-text} different) is safe,
because certA will only be deleted if it is present
and certB will only be added if it is not present, therefore no
@@ -7218,13 +7272,13 @@ \subsubsection{OpenNetworkBoot Certificate Management}
HTTPS Boot firmware, the certificates managed by this driver will be
separate from those managed by firmware.
-When using the debug version of this driver, the OpenCore debug log includes \texttt{NTBT:} entries
+When using the debug version of this driver, the OpenCore debug log includes \texttt{NETB:} entries
that show which certificates are enrolled and removed by these options, and which
certificates are present after all certificate configuration options have been processed.
\subsection{Other Boot Entry Protocol drivers}
-In addition to the \hyperref[uefilinux]{OpenLinuxBoot} and \hyperref[uefipxe]{OpenNetworkBoot} plugins,
+In addition to the \hyperref[uefilinux]{OpenLinuxBoot} and \hyperref[uefinetboot]{OpenNetworkBoot} plugins,
the following \texttt{OC\_BOOT\_ENTRY\_PROTOCOL}
plugins are made available to add optional, configurable boot entries to the OpenCore boot picker.
diff --git a/Docs/Differences/Differences.pdf b/Docs/Differences/Differences.pdf
index 482d396a951..6b2e15ca038 100644
Binary files a/Docs/Differences/Differences.pdf and b/Docs/Differences/Differences.pdf differ
diff --git a/Docs/Differences/Differences.tex b/Docs/Differences/Differences.tex
index 4f09829b373..90a92613cce 100644
--- a/Docs/Differences/Differences.tex
+++ b/Docs/Differences/Differences.tex
@@ -1,7 +1,7 @@
\documentclass[]{article}
%DIF LATEXDIFF DIFFERENCE FILE
-%DIF DEL PreviousConfiguration.tex Sun Dec 22 13:34:51 2024
-%DIF ADD ../Configuration.tex Sun Dec 22 13:34:51 2024
+%DIF DEL PreviousConfiguration.tex Sun Dec 22 14:07:33 2024
+%DIF ADD ../Configuration.tex Sun Dec 22 14:07:33 2024
\usepackage{lmodern}
\usepackage{amssymb,amsmath}
@@ -4179,7 +4179,7 @@ \subsection{Debug Properties}\label{miscdebugprops}
\item \texttt{HDA} --- AudioDxe
\item \texttt{KKT} --- KeyTester
\item \texttt{LNX} --- OpenLinuxBoot
- \item \texttt{NTBT} --- OpenNetworkBoot
+ \item \texttt{\DIFdelbegin \DIFdel{NTBT}\DIFdelend \DIFaddbegin \DIFadd{NETB}\DIFaddend } --- OpenNetworkBoot
\item \texttt{MMDD} --- MmapDump
\item \texttt{OCPAVP} --- PavpProvision
\item \texttt{OCRST} --- ResetSystem
@@ -6636,7 +6636,8 @@ \subsection{Drivers}\label{uefidrivers}
to allow direct detection and booting of Linux distributions from OpenCore, without
chainloading via GRUB. \\
\href{https://github.com/acidanthera/OpenCorePkg}{\texttt{OpenNetworkBoot}}\textbf{*}
-& \hyperref[uefipxe]{OpenCore plugin} implementing \texttt{OC\_BOOT\_ENTRY\_PROTOCOL}
+& \DIFdelbegin %DIFDELCMD < \hyperref[uefipxe]{OpenCore plugin} %%%
+\DIFdelend \DIFaddbegin \hyperref[uefinetboot]{OpenCore plugin} \DIFaddend implementing \texttt{OC\_BOOT\_ENTRY\_PROTOCOL}
to show available PXE and HTTP(S) boot options on the OpenCore boot menu. \\
\href{https://github.com/acidanthera/OpenCorePkg}{\texttt{OpenNtfsDxe}}\textbf{*}
& New Technologies File System (NTFS) read-only driver.
@@ -7151,7 +7152,10 @@ \subsubsection{Additional information}
therefore \texttt{efibootmgr} rather than \texttt{bootctl} must be used for any low-level Linux command line interaction
with the boot menu.
-\subsection{OpenNetworkBoot}\label{uefipxe}
+\subsection{OpenNetworkBoot}\DIFdelbegin %DIFDELCMD < \label{uefipxe}
+%DIFDELCMD < %%%
+\DIFdelend \DIFaddbegin \label{uefinetboot}
+\DIFaddend
OpenNetworkBoot is an OpenCore plugin implementing \texttt{OC\_BOOT\_ENTRY\_PROTOCOL}.
It enables PXE and HTTP(S) Boot options in the OpenCore menu if these
@@ -7173,69 +7177,177 @@ \subsection{OpenNetworkBoot}\label{uefipxe}
PXE and HTTP(S) Boot is provided on
\href{https://github.com/acidanthera/OpenCorePkg/blob/master/Platform/OpenNetworkBoot/README.md}{this page}.
-The following configuration options may be specified in the \texttt{Arguments} section for this driver:
-
-\begin{itemize}
- \item \texttt{-4} - Boolean flag, enabled if present. \medskip
-
- If specified enable IPv4 for PXE and HTTP(S) Boot. Disable IPV6
- unless the \texttt{-6} flag is also present. If neither flag is
- present, both are enabled by default. \medskip
-
- \item \texttt{-6} - Boolean flag, enabled if present. \medskip
+The \DIFdelbegin \DIFdel{following }\DIFdelend \DIFaddbegin \DIFadd{below }\DIFaddend configuration options may be specified in the \texttt{Arguments} section for this driver\DIFdelbegin \DIFdel{:
+}\DIFdelend \DIFaddbegin \DIFadd{.
+}\DIFaddend
- If specified enable IPv6 for PXE and HTTP(S) Boot. Disable IPV4
- unless the \texttt{-4} flag is also present. If neither flag is
- present, both are enabled by default. \medskip
+\DIFaddbegin \emph{\DIFadd{Note}}\DIFadd{: There is no problem if configuration options within }\texttt{\DIFadd{...}} \DIFadd{are given on
+multiple lines, and option values enclosed within quotes can also span multiple lines. This applies to all drivers
+which use OpenCore argument parsing, and can be particularly convenient when multiple long options such as }\texttt{\DIFadd{uri}}\DIFadd{,
+}\texttt{\DIFadd{static4}} \DIFadd{and particularly }\texttt{\DIFadd{enroll-cert}} \DIFadd{may be needed.
+}
- \item \texttt{-{}-aux} - Boolean flag, enabled if present. \medskip
+\DIFaddend \begin{itemize}
+ \item \DIFdelbegin \texttt{\DIFdel{-4}} %DIFAUXCMD
+\DIFdel{- Boolean flag, enabled if present.
+}%DIFDELCMD < \medskip
+%DIFDELCMD <
+
+%DIFDELCMD < %%%
+\DIFdel{If specified enable IPv4 for PXE and HTTP(S) Boot. Disable IPV6
+ unless the }\texttt{\DIFdel{-6}} %DIFAUXCMD
+\DIFdel{flag is also present. If neither flag is
+ present, both are enabled by default. }%DIFDELCMD < \medskip
+%DIFDELCMD <
+
+%DIFDELCMD < \item %%%
+\item %DIFAUXCMD
+\texttt{\DIFdel{-6}} %DIFAUXCMD
+\DIFdel{- Boolean flag, enabled if present. }%DIFDELCMD < \medskip
+%DIFDELCMD <
+
+%DIFDELCMD < %%%
+\DIFdel{If specified enable IPv6 for PXE and HTTP(S) Boot. Disable IPV4
+ unless the }\texttt{\DIFdel{-4}} %DIFAUXCMD
+\DIFdel{flag is also present. If neither flag is
+ present, both are enabled by default.
+}%DIFDELCMD < \medskip
+%DIFDELCMD <
+
+%DIFDELCMD < \item %%%
+\item %DIFAUXCMD
+\DIFdelend \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-aux}\DIFdelend \DIFaddbegin \DIFadd{aux}\DIFaddend } - Boolean flag, enabled if present. \medskip
If specified the driver will generate auxiliary boot entries. \medskip
- \item \texttt{-{}-delete-all-certs[:\{OWNER\_GUID\}]} - Default: not set. \medskip
+ \item \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-delete-all-certs}\DIFdelend \DIFaddbegin \DIFadd{delete-all-certs}\DIFaddend [:\{OWNER\_GUID\}]} - Default: not set. \medskip
If specified, delete all certificates present for \texttt{OWNER\_GUID}.
- \texttt{OWNER\_GUID} is optional, and will default to all zeros if not specified. \medskip
+ \texttt{OWNER\_GUID} is optional, and will default to all zeros if not specified.
+ \medskip
- \item \texttt{-{}-delete-cert[:\{OWNER\_GUID\}]="\{cert-text\}"} - Default: not set. \medskip
+ \item \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-delete-cert}\DIFdelend \DIFaddbegin \DIFadd{delete-cert}\DIFaddend [:\{OWNER\_GUID\}]="\{cert-text\}"} - Default: not set. \medskip
If specified, delete the given certificate(s) for HTTPS Boot. The certificate(s) can be specified
as a multi-line PEM value between double quotes.
- \texttt{OWNER\_GUID} is optional, and will default to all zeros if not specified.
- A single PEM file can contain one or more certicates.
+ \DIFdelbegin \texttt{\DIFdel{OWNER\_GUID}} %DIFAUXCMD
+\DIFdel{is optional, and will default to all zeros if not specified.
+ }\DIFdelend A single PEM file can contain one or more certicates.
Multiple instances of this option can be used to delete multiple different
PEM files, if required.
+ \DIFaddbegin \texttt{\DIFadd{OWNER\_GUID}} \DIFadd{is optional, and will default to all zeros if not specified.
+ }\medskip
+\DIFaddend
- \item \texttt{-{}-enroll-cert[:\{OWNER\_GUID\}]="\{cert-text\}"} - Default: not set. \medskip
+ \item \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-enroll-cert}\DIFdelend \DIFaddbegin \DIFadd{enroll-cert}\DIFaddend [:\{OWNER\_GUID\}]="\{cert-text\}"} - Default: not set. \medskip
If specified, enroll the given certificate(s) for HTTPS Boot. The certificate(s) can be specified
as a multi-line PEM value between double quotes.
- \texttt{OWNER\_GUID} is optional, and will default to all zeros if not specified.
- A single PEM file can contain one or more certicates.
+ \DIFdelbegin \texttt{\DIFdel{OWNER\_GUID}} %DIFAUXCMD
+\DIFdel{is optional, and will default to all zeros if not specified.
+ }\DIFdelend A single PEM file can contain one or more certicates.
Multiple instances of this option can be used to enroll multiple different
- PEM files, if required. \medskip
+ PEM files, if required.
+ \DIFaddbegin \texttt{\DIFadd{OWNER\_GUID}} \DIFadd{is optional, and will default to all zeros if not specified.
+ }\DIFaddend \medskip
- \item \texttt{-{}-http} - Boolean flag, enabled if present. \medskip
+ \item \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-http}\DIFdelend \DIFaddbegin \DIFadd{http}\DIFaddend } - Boolean flag, enabled if present. \medskip
If specified enable HTTP(S) Boot. Disable PXE Boot unless
- the \texttt{-{}-pxe} flag is also present. If neither flag is
+ the \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-pxe}\DIFdelend \DIFaddbegin \DIFadd{pxe}\DIFaddend } flag is also present. If neither flag is
present, both are enabled by default. \medskip
- \item \texttt{-{}-https} - Boolean flag, enabled if present. \medskip
+ \item \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-https}\DIFdelend \DIFaddbegin \DIFadd{https}\DIFaddend } - Boolean flag, enabled if present. \medskip
If enabled, allow only \texttt{https://} URIs for HTTP(S) Boot.
- Additionally has the same behaviour as the \texttt{-{}-http} flag. \medskip
+ Additionally has the same behaviour as the \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-http}\DIFdelend \DIFaddbegin \DIFadd{http}\DIFaddend } flag. \medskip
+
+ \item \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-pxe}\DIFdelend \DIFaddbegin \DIFadd{ipv4}\DIFaddend } - Boolean flag, enabled if present. \medskip
+
+ If specified enable \DIFdelbegin \DIFdel{PXE Boot, and }\DIFdelend \DIFaddbegin \DIFadd{IPv4 for PXE and HTTP(S) Boot. Disable IPV6
+ unless the }\texttt{\DIFadd{ipv6}} \DIFadd{flag is also present. If neither flag is
+ present, both are enabled by default. }\medskip
- \item \texttt{-{}-pxe} - Boolean flag, enabled if present. \medskip
+ \item \texttt{\DIFadd{ipv6}} \DIFadd{- Boolean flag, enabled if present. }\medskip
- If specified enable PXE Boot, and disable HTTP(S) Boot unless
- the \texttt{-{}-http} or \texttt{-{}-https} flags are present.
+ \DIFadd{If specified enable IPv6 for PXE and HTTP(S) Boot. Disable IPV4
+ unless the }\texttt{\DIFadd{ipv4}} \DIFadd{flag is also present. If neither flag is
+ present, both are enabled by default. }\medskip
+
+ \item \texttt{\DIFadd{pxe}} \DIFadd{- Boolean flag, enabled if present. }\medskip
+
+ \DIFadd{If specified enable PXE Boot, and }\DIFaddend disable HTTP(S) Boot unless
+ the \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-http}\DIFdelend \DIFaddbegin \DIFadd{http}\DIFaddend } or \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-https}\DIFdelend \DIFaddbegin \DIFadd{https}\DIFaddend } flags are present.
If none of these flags are present, both PXE and HTTP(S) Boot are
enabled by default. \medskip
- \item \texttt{-{}-uri} - String value, no default. \medskip
+ \item \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-uri}\DIFdelend \DIFaddbegin \DIFadd{static4:\{MAC\_ADDR\}[\textbackslash VLAN\_ID][="\{IP\},\{MASK\},\{GATEWAY\}[,\{DNS\}]"]}\DIFaddend } - String value\DIFdelbegin \DIFdel{, no default}\DIFdelend . \medskip
+
+ \DIFaddbegin \DIFadd{Specify static IPv4 address for the network interface with the MAC address given by }\texttt{\DIFadd{MAC\_ADDR}}\DIFadd{. }\texttt{\DIFadd{MAC\_ADDR}}
+ \DIFadd{must be specified as 12 consecutive hex digits, with no spaces, colons or hyphens separating digit pairs. In some advanced
+ use-cases such as iSCSI, the MAC address length may be some other even number length of hex digits. The required
+ MAC address can be found in the names of the boot options produced by this driver. Note that
+ hyphens separating digit pairs must be removed, as compared to the format displayed in boot option names.
+ It is also possible to specify a VLAN ID to use on the interface, by adding a backslash
+ followed by a 4 digit hex representation of the VLAN ID following the MAC address. The VLAN ID will also be
+ shown in the boot entry name, but note that it must be converted from decimal in the boot entry name to a
+ 4 digit hex number in this option.
+}
+
+ \DIFadd{Required elements in value are IP address in }\texttt{\DIFadd{IP}}\DIFadd{, network mask in }\texttt{\DIFadd{MASK}}
+ \DIFadd{and gateway in }\texttt{\DIFadd{GATEWAY}}\DIFadd{. Optional is an additional space separated list of one or more DNS servers
+ in }\texttt{\DIFadd{DNS}}\DIFadd{. }\texttt{\DIFadd{DNS}} \DIFadd{will be needed if the boot file URI includes a domain name rather than an IP address.
+ }
+
+ \texttt{\DIFadd{MAC\_ADDR}} \DIFadd{is not optional.
+}
+
+ \DIFadd{If value is omitted, then any static IP for this MAC address (and VLAN ID when present) will be deleted.
+}
+
+ \begin{itemize}
+ \item \DIFadd{Example 1: }\texttt{\DIFadd{static4:112233445566="192.168.1.20,255.255.255.0,192.168.1.1,8.8.8.8 4.4.4.4"}}\DIFadd{.
+ }\item \DIFadd{Example 2: }\texttt{\DIFadd{static4:112233445566\textbackslash 0001="10.0.0.2,255.255.255.0,10.0.0.1"}}\DIFadd{.
+ }\end{itemize}
+
+ \emph{\DIFadd{Note 1}}\DIFadd{: This option is written to NVRAM and will remain present even if the option is removed from the driver
+ }\texttt{\DIFadd{Arguments}}\DIFadd{, unless NVRAM is cleared or an alternative value is written or the value deleted, using this option.
+ }
+
+ \emph{\DIFadd{Note 2}}\DIFadd{: This setting will normally cause a static IP to be assigned during pre-boot, even in vendor-provided
+ network stacks. However, due to a quirk of the design of PXE and HTTP boot, any such static assignment will then be
+ ignored and DHCP used instead, during network boot. The OpenCore network stack (specifically }\texttt{\DIFadd{HttpBootDxe.efi}}\DIFadd{)
+ is unusual in that it will allow HTTP boot from a static IP address, as long as an HTTP boot URI has also been specified,
+ using the }\texttt{\DIFadd{uri}} \DIFadd{option for this driver (or e.g. in the OVMF admin screens if using OVMF, or similar options
+ where present in other firmeare). If HTTP boot from static
+ IP is required, then any pre-existing vendor-specific version of }\texttt{\DIFadd{HttpBootDxe.efi}} \DIFadd{will need to be unloaded
+ (see }\texttt{\DIFadd{UEFI}} \texttt{\DIFadd{Unload}} \DIFadd{option) and the OpenCore version used instead.
+}
+
+ \emph{\DIFadd{Note 3}}\DIFadd{: If }\texttt{\DIFadd{Ip4Dxe}} \DIFadd{is loaded before OpenCore then any setting here will only take effect after one
+ reboot. If }\texttt{\DIFadd{Ip4Dxe}} \DIFadd{is loaded after }\texttt{\DIFadd{OpenNetworkBoot}} \DIFadd{the setting will take effect immediately.
+ }\medskip
+
+ \emph{\DIFadd{Note 4}}\DIFadd{: In the majority of cases this option is not required, and the default DHCP behaviour should be
+ preferred, since IP address conflicts are automatically avoided, and any IP address assigned by DHCP during network
+ boot will normally automatically match the IP address assigned in-OS, as the same MAC address is used in both cases.
+ }\medskip
+
+ \item \texttt{\DIFadd{uri}} \DIFadd{- String value, no default. }\medskip
- If present, specify the URI to use for HTTP(S) Boot. If not present then
+ \DIFaddend If present, specify the URI to use for HTTP(S) Boot. If not present then
DHCP boot options must be enabled on the network in order for HTTP(S)
Boot to know what to boot.
@@ -7244,17 +7356,26 @@ \subsection{OpenNetworkBoot}\label{uefipxe}
\subsubsection{OpenNetworkBoot Certificate Management}
Certificates are enrolled to NVRAM storage, therefore once
-a certificate has been enrolled, it will remain enrolled even if the \texttt{-{}-enroll-cert} config
-option is removed. \texttt{-{}-delete-cert} or \texttt{-{}-delete-all-certs}
+a certificate has been enrolled, it will remain enrolled even if the \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-enroll-cert}\DIFdelend \DIFaddbegin \DIFadd{enroll-cert}\DIFaddend } config
+option is removed. \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-delete-cert}\DIFdelend \DIFaddbegin \DIFadd{delete-cert}\DIFaddend } or \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-delete-all-certs}\DIFdelend \DIFaddbegin \DIFadd{delete-all-certs}\DIFaddend }
should be used to remove enrolled certificates.
-Checking for certificate presence by the \texttt{-{}-enroll-cert}
-and \texttt{-{}-delete-cert} options uses the simple algorithm
+Checking for certificate presence by the \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-enroll-cert}\DIFdelend \DIFaddbegin \DIFadd{enroll-cert}\DIFaddend }
+and \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-delete-cert}\DIFdelend \DIFaddbegin \DIFadd{delete-cert}\DIFaddend } options uses the simple algorithm
of matching by exact file contents, not by file meaning. The intended
-usage is to leave an \texttt{-{}-enroll-cert} option present in the config
+usage is to leave an \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-enroll-cert}\DIFdelend \DIFaddbegin \DIFadd{enroll-cert}\DIFaddend } option present in the config
file until it is time to delete it, e.g. after another more up-to-date
-\texttt{-{}-enroll-cert} option has been added and tested. At this point
-the user can change \texttt{-{}-enroll-cert} to \texttt{-{}-delete-cert}
+\texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-enroll-cert}\DIFdelend \DIFaddbegin \DIFadd{enroll-cert}\DIFaddend } option has been added and tested. At this point
+the user can change \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-enroll-cert}\DIFdelend \DIFaddbegin \DIFadd{enroll-cert}\DIFaddend } to \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-delete-cert}\DIFdelend \DIFaddbegin \DIFadd{delete-cert}\DIFaddend }
for the old certificate. \medskip
Certificate options are processed one at a time, in
@@ -7262,10 +7383,14 @@ \subsubsection{OpenNetworkBoot Certificate Management}
However each option will not change the NVRAM store if it is already correct
for the option at that point in time (e.g. will not enroll a certificate if it is
already enrolled).
-Avoid combinations such as \texttt{-{}-delete-all-certs} followed by
-\texttt{-{}-enroll-cert}, as this will modify the NVRAM certificate
+Avoid combinations such as \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-delete-all-certs}\DIFdelend \DIFaddbegin \DIFadd{delete-all-certs}\DIFaddend } followed by
+\texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-enroll-cert}\DIFdelend \DIFaddbegin \DIFadd{enroll-cert}\DIFaddend }, as this will modify the NVRAM certificate
storage twice on every boot. However a combination such as
-\texttt{-{}-delete-cert="\{certA-text\}"} followed by \texttt{-{}-enroll-cert="\{certB-text\}"}
+\texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-delete-cert}\DIFdelend \DIFaddbegin \DIFadd{delete-cert}\DIFaddend ="\{certA-text\}"} followed by \texttt{\DIFdelbegin \DIFdel{-}%DIFDELCMD < {}%%%
+\DIFdel{-enroll-cert}\DIFdelend \DIFaddbegin \DIFadd{enroll-cert}\DIFaddend ="\{certB-text\}"}
(with \texttt{certA-text} and \texttt{certB-text} different) is safe,
because certA will only be deleted if it is present
and certB will only be added if it is not present, therefore no
@@ -7278,13 +7403,14 @@ \subsubsection{OpenNetworkBoot Certificate Management}
HTTPS Boot firmware, the certificates managed by this driver will be
separate from those managed by firmware.
-When using the debug version of this driver, the OpenCore debug log includes \texttt{NTBT:} entries
+When using the debug version of this driver, the OpenCore debug log includes \texttt{\DIFdelbegin \DIFdel{NTBT}\DIFdelend \DIFaddbegin \DIFadd{NETB}\DIFaddend :} entries
that show which certificates are enrolled and removed by these options, and which
certificates are present after all certificate configuration options have been processed.
\subsection{Other Boot Entry Protocol drivers}
-In addition to the \hyperref[uefilinux]{OpenLinuxBoot} and \hyperref[uefipxe]{OpenNetworkBoot} plugins,
+In addition to the \hyperref[uefilinux]{OpenLinuxBoot} and \DIFdelbegin %DIFDELCMD < \hyperref[uefipxe]{OpenNetworkBoot} %%%
+\DIFdelend \DIFaddbegin \hyperref[uefinetboot]{OpenNetworkBoot} \DIFaddend plugins,
the following \texttt{OC\_BOOT\_ENTRY\_PROTOCOL}
plugins are made available to add optional, configurable boot entries to the OpenCore boot picker.
diff --git a/Docs/Errata/Errata.pdf b/Docs/Errata/Errata.pdf
index d3bd97e0f17..2435684d8fa 100644
Binary files a/Docs/Errata/Errata.pdf and b/Docs/Errata/Errata.pdf differ
diff --git a/Platform/OpenNetworkBoot/BmBoot.c b/Platform/OpenNetworkBoot/BmBoot.c
index 69919829be2..045f321edb4 100644
--- a/Platform/OpenNetworkBoot/BmBoot.c
+++ b/Platform/OpenNetworkBoot/BmBoot.c
@@ -601,7 +601,7 @@ BmExpandLoadFiles (
if ((Node != NULL) && !UriWasValidated ()) {
Print (L"\n"); ///< Sort out cramped spacing
- DEBUG ((DEBUG_ERROR, "NTBT: LoadFile returned value but URI was never validated\n"));
+ DEBUG ((DEBUG_ERROR, "NETB: LoadFile returned value but URI was never validated\n"));
FreePool (Node);
return NULL;
}
diff --git a/Platform/OpenNetworkBoot/HttpBootCallback.c b/Platform/OpenNetworkBoot/HttpBootCallback.c
index 145f60e8323..d97d70dc88f 100644
--- a/Platform/OpenNetworkBoot/HttpBootCallback.c
+++ b/Platform/OpenNetworkBoot/HttpBootCallback.c
@@ -40,7 +40,7 @@ ValidateDmgAndHttps (
// Do not return ACCESS_DENIED as this will attempt to add authentication to the request.
//
if (ShowLog) {
- DEBUG ((DEBUG_INFO, "NTBT: Invalid URI https:// is required\n"));
+ DEBUG ((DEBUG_INFO, "NETB: Invalid URI https:// is required\n"));
}
return EFI_UNSUPPORTED;
@@ -66,7 +66,7 @@ ValidateDmgAndHttps (
if (gDmgLoading == OcDmgLoadingDisabled) {
if (*HasDmgExtension) {
if (ShowLog) {
- DEBUG ((DEBUG_INFO, "NTBT: %a file is requested while DMG loading is disabled\n", Match));
+ DEBUG ((DEBUG_INFO, "NETB: %a file is requested while DMG loading is disabled\n", Match));
}
return EFI_UNSUPPORTED;
diff --git a/Platform/OpenNetworkBoot/HttpBootCustomRead.c b/Platform/OpenNetworkBoot/HttpBootCustomRead.c
index fa6875da1be..a23870e690f 100644
--- a/Platform/OpenNetworkBoot/HttpBootCustomRead.c
+++ b/Platform/OpenNetworkBoot/HttpBootCustomRead.c
@@ -232,7 +232,7 @@ HttpBootCustomRead (
OtherDevicePath = BmExpandLoadFiles (OtherLoadFile, Data, DataSize, TRUE);
FreePool (OtherLoadFile);
if (OtherDevicePath == NULL) {
- DEBUG ((DEBUG_INFO, "NTBT: Failed to fetch required matching file %a\r", OtherUri));
+ DEBUG ((DEBUG_INFO, "NETB: Failed to fetch required matching file %a\r", OtherUri));
Status = EFI_NOT_FOUND;
} else {
if (GotDmgFirst) {
diff --git a/Platform/OpenNetworkBoot/Ip4Config2Nv.c b/Platform/OpenNetworkBoot/Ip4Config2Nv.c
new file mode 100644
index 00000000000..0f26686950f
--- /dev/null
+++ b/Platform/OpenNetworkBoot/Ip4Config2Nv.c
@@ -0,0 +1,299 @@
+/** @file
+ IPv4 NVRAM utilities.
+
+ Code derived from:
+ - NetworkPkg/Ip4Dxe/Ip4Config2Impl.c
+ - NetworkPkg/Ip4Dxe/Ip4Config2Nv.c
+
+ Copyright (c) 2024, Mike Beaton. All rights reserved.
+ Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "NetworkBootInternal.h"
+
+STATIC
+VOID
+AddDataRecord (
+ IN OUT IP4_CONFIG2_VARIABLE *Variable,
+ IN EFI_IP4_CONFIG2_DATA_TYPE DataType,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN OUT CHAR8 **Heap
+ )
+{
+ *Heap -= DataSize;
+ CopyMem (*Heap, Data, DataSize);
+
+ Variable->DataRecord[Variable->DataRecordCount].Offset = (UINT16)(*Heap - (CHAR8 *)Variable);
+ Variable->DataRecord[Variable->DataRecordCount].DataSize = (UINT32)DataSize;
+ Variable->DataRecord[Variable->DataRecordCount].DataType = DataType;
+
+ ++Variable->DataRecordCount;
+}
+
+EFI_STATUS
+Ip4Config2ConvertOcConfigDataToNvData (
+ IN CHAR16 *VarName,
+ IN IP4_CONFIG2_OC_CONFIG_DATA *ConfigData
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+
+ EFI_IP4_CONFIG2_POLICY Policy;
+ EFI_IP4_CONFIG2_MANUAL_ADDRESS ManualAddress;
+ EFI_IP_ADDRESS StationAddress;
+ EFI_IP_ADDRESS SubnetMask;
+ EFI_IP_ADDRESS Gateway;
+ IP4_ADDR Ip;
+ EFI_IPv4_ADDRESS *DnsAddress;
+ UINTN DnsCount;
+
+ IP4_CONFIG2_VARIABLE *Variable;
+ UINTN VarSize;
+ UINT16 DataRecordCount;
+ CHAR8 *Heap;
+
+ //
+ // cf Ip4Config2ConvertIfrNvDataToConfigNvData
+ // REF: https://github.com/tianocore/edk2/blob/e99d532fd7224e68026543834ed9c0fe3cfaf88c/NetworkPkg/Ip4Dxe/Ip4Config2Nv.c#L551
+ //
+ Policy = Ip4Config2PolicyStatic;
+
+ Status = Ip4Config2StrToIp (ConfigData->SubnetMask, &SubnetMask.v4);
+ if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (GetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {
+ DEBUG ((DEBUG_WARN, "NETB: Invalid subnet mask %s\n", ConfigData->SubnetMask));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = Ip4Config2StrToIp (ConfigData->StationAddress, &StationAddress.v4);
+ if (EFI_ERROR (Status) ||
+ ((SubnetMask.Addr[0] != 0) && !NetIp4IsUnicast (NTOHL (StationAddress.Addr[0]), NTOHL (SubnetMask.Addr[0]))) ||
+ !Ip4StationAddressValid (NTOHL (StationAddress.Addr[0]), NTOHL (SubnetMask.Addr[0])))
+ {
+ DEBUG ((DEBUG_WARN, "NETB: Invalid IP address %s\n", ConfigData->StationAddress));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = Ip4Config2StrToIp (ConfigData->GatewayAddress, &Gateway.v4);
+ if (EFI_ERROR (Status) ||
+ ((Gateway.Addr[0] != 0) && (SubnetMask.Addr[0] != 0) && !NetIp4IsUnicast (NTOHL (Gateway.Addr[0]), NTOHL (SubnetMask.Addr[0]))))
+ {
+ DEBUG ((DEBUG_WARN, "NETB: Invalid gateway %s\n", ConfigData->GatewayAddress));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = Ip4Config2StrToIpList (ConfigData->DnsAddress, &DnsAddress, &DnsCount);
+ if (!EFI_ERROR (Status) && (DnsCount > 0)) {
+ for (Index = 0; Index < DnsCount; Index++) {
+ CopyMem (&Ip, &DnsAddress[Index], sizeof (IP4_ADDR));
+ if (IP4_IS_UNSPECIFIED (NTOHL (Ip)) || IP4_IS_LOCAL_BROADCAST (NTOHL (Ip))) {
+ DEBUG ((
+ DEBUG_WARN,
+ "NETB: Invalid DNS address %d.%d.%d.%d\n",
+ DnsAddress[Index].Addr[0],
+ DnsAddress[Index].Addr[1],
+ DnsAddress[Index].Addr[2],
+ DnsAddress[Index].Addr[3]
+ ));
+ FreePool (DnsAddress);
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ } else {
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "NETB: Invalid DNS server list %s\n", ConfigData->DnsAddress));
+ //
+ // Unlike Ip4Config2ConvertIfrNvDataToConfigNvData we abort if unparseable DNS list.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ CopyMem (&ManualAddress.Address, &StationAddress.v4, sizeof (EFI_IPv4_ADDRESS));
+ CopyMem (&ManualAddress.SubnetMask, &SubnetMask.v4, sizeof (EFI_IPv4_ADDRESS));
+
+ //
+ // cf Ip4Config2WriteConfigData
+ // REF: https://github.com/tianocore/edk2/blob/e99d532fd7224e68026543834ed9c0fe3cfaf88c/NetworkPkg/Ip4Dxe/Ip4Config2Impl.c#L303
+ //
+ DataRecordCount = DnsCount == 0 ? 3 : 4;
+ VarSize = sizeof (*Variable) +
+ sizeof (Variable->DataRecord[0]) * DataRecordCount +
+ sizeof (Policy) +
+ sizeof (ManualAddress) +
+ sizeof (Gateway.v4) +
+ DnsCount * sizeof (*DnsAddress);
+
+ Variable = AllocatePool (VarSize);
+
+ if (Variable == NULL) {
+ if (DnsAddress != NULL) {
+ FreePool (DnsAddress);
+ }
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Heap = (CHAR8 *)Variable + VarSize;
+
+ Variable->DataRecordCount = 0;
+
+ AddDataRecord (Variable, Ip4Config2DataTypePolicy, &Policy, sizeof (Policy), &Heap);
+ AddDataRecord (Variable, Ip4Config2DataTypeManualAddress, &ManualAddress, sizeof (ManualAddress), &Heap);
+ AddDataRecord (Variable, Ip4Config2DataTypeGateway, &Gateway.v4, sizeof (Gateway.v4), &Heap);
+ if (DnsAddress != NULL) {
+ AddDataRecord (Variable, Ip4Config2DataTypeDnsServer, DnsAddress, sizeof (*DnsAddress) * DnsCount, &Heap);
+ FreePool (DnsAddress);
+ }
+
+ ASSERT (Variable->DataRecordCount == DataRecordCount);
+ ASSERT (Heap == (CHAR8 *)&Variable->DataRecord[DataRecordCount]);
+
+ Variable->Checksum = 0;
+ Variable->Checksum = (UINT16) ~NetblockChecksum ((UINT8 *)Variable, (UINT32)VarSize);
+
+ Status = gRT->SetVariable (
+ VarName,
+ &gEfiIp4Config2ProtocolGuid,
+ IP4_CONFIG2_VARIABLE_ATTRIBUTE,
+ VarSize,
+ Variable
+ );
+
+ DEBUG ((
+ DEBUG_INFO,
+ "NETB: Adding %a %s - %r\n",
+ "IPv4 NVRAM config for MAC address",
+ VarName,
+ Status
+ ));
+
+ FreePool (Variable);
+
+ return Status;
+}
+
+//
+// cf Ip4Config2ReadConfigData
+// REF: https://github.com/tianocore/edk2/blob/e99d532fd7224e68026543834ed9c0fe3cfaf88c/NetworkPkg/Ip4Dxe/Ip4Config2Impl.c#L188
+//
+EFI_STATUS
+Ip4Config2DeleteStaticIpNvData (
+ IN CHAR16 *VarName
+ )
+{
+ EFI_STATUS Status;
+ UINTN VarSize;
+ IP4_CONFIG2_VARIABLE *Variable;
+ UINTN Index;
+ IP4_CONFIG2_DATA_RECORD *DataRecord;
+
+ EFI_IP4_CONFIG2_POLICY Policy;
+
+ BOOLEAN FoundStaticPolicy;
+ BOOLEAN FoundManualAddress;
+
+ VarSize = 0;
+ Status = gRT->GetVariable (
+ VarName,
+ &gEfiIp4Config2ProtocolGuid,
+ NULL,
+ &VarSize,
+ NULL
+ );
+
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return Status;
+ }
+
+ Variable = AllocatePool (VarSize);
+ if (Variable == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gRT->GetVariable (
+ VarName,
+ &gEfiIp4Config2ProtocolGuid,
+ NULL,
+ &VarSize,
+ Variable
+ );
+ if (EFI_ERROR (Status) || ((UINT16)(~NetblockChecksum ((UINT8 *)Variable, (UINT32)VarSize)) != 0)) {
+ FreePool (Variable);
+
+ //
+ // Unlike Ip4Config2ReadConfigData it is not our job to remove problematic variable,
+ // just warn and return EFI_NOT_FOUND.
+ //
+ DEBUG ((
+ DEBUG_INFO,
+ "NETB: %a, %a %a %s - %r\n",
+ "Invalid variable",
+ "not removing",
+ "IPv4 NVRAM config for MAC address",
+ VarName,
+ Status
+ ));
+
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // In order to avoid fighting with PXE and HTTP boot over the variable value,
+ // only remove valid static IP settings.
+ //
+ FoundStaticPolicy = FALSE;
+ FoundManualAddress = FALSE;
+
+ for (Index = 0; Index < Variable->DataRecordCount; Index++) {
+ DataRecord = &Variable->DataRecord[Index];
+ if ( (DataRecord->DataType == Ip4Config2DataTypePolicy)
+ && (DataRecord->DataSize == sizeof (Policy)))
+ {
+ CopyMem (&Policy, (CHAR8 *)Variable + DataRecord->Offset, DataRecord->DataSize);
+ if (Policy == Ip4Config2PolicyStatic) {
+ FoundStaticPolicy = TRUE;
+ }
+ } else if ( (DataRecord->DataType == Ip4Config2DataTypeManualAddress)
+ && (DataRecord->DataSize == sizeof (EFI_IP4_CONFIG2_MANUAL_ADDRESS)))
+ {
+ FoundManualAddress = TRUE;
+ }
+ }
+
+ if (FoundStaticPolicy && FoundManualAddress) {
+ //
+ // Remove the variable.
+ //
+ Status = gRT->SetVariable (
+ VarName,
+ &gEfiIp4Config2ProtocolGuid,
+ IP4_CONFIG2_VARIABLE_ATTRIBUTE,
+ 0,
+ NULL
+ );
+ DEBUG ((
+ DEBUG_INFO,
+ "NETB: Removing %a %s - %r\n",
+ "IPv4 NVRAM config for MAC address",
+ VarName,
+ Status
+ ));
+ } else {
+ DEBUG ((
+ DEBUG_INFO,
+ "NETB: %a, %a %a %s\n",
+ "No static IP",
+ "not removing",
+ "IPv4 NVRAM config for MAC address",
+ VarName
+ ));
+ Status = EFI_NOT_FOUND;
+ }
+
+ FreePool (Variable);
+ return Status;
+}
diff --git a/Platform/OpenNetworkBoot/Ip4Utils.c b/Platform/OpenNetworkBoot/Ip4Utils.c
new file mode 100644
index 00000000000..3aa0d485ed6
--- /dev/null
+++ b/Platform/OpenNetworkBoot/Ip4Utils.c
@@ -0,0 +1,297 @@
+/** @file
+ IPv4 utilities.
+
+ Methods from:
+ - NetworkPkg/Ip4Dxe/Ip4Common.c
+ - NetworkPkg/Ip4Dxe/Ip4Config2Nv.c
+
+ Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "NetworkBootInternal.h"
+
+/**
+ Validate that Ip/Netmask pair is OK to be used as station
+ address. Only continuous netmasks are supported. and check
+ that StationAddress is a unicast address on the network.
+
+ @param[in] Ip The IP address to validate.
+ @param[in] Netmask The netmask of the IP.
+
+ @retval TRUE The Ip/Netmask pair is valid.
+ @retval FALSE The Ip/Netmask pair is invalid.
+
+**/
+BOOLEAN
+Ip4StationAddressValid (
+ IN IP4_ADDR Ip,
+ IN IP4_ADDR Netmask
+ )
+{
+ //
+ // Only support the station address with 0.0.0.0/0 to enable DHCP client.
+ //
+ if (Netmask == IP4_ALLZERO_ADDRESS) {
+ return (BOOLEAN)(Ip == IP4_ALLZERO_ADDRESS);
+ }
+
+ //
+ // Only support the continuous net masks
+ //
+ if (NetGetMaskLength (Netmask) == (IP4_MASK_MAX + 1)) {
+ return FALSE;
+ }
+
+ //
+ // Station address can't be class D or class E address
+ //
+ if (NetGetIpClass (Ip) > IP4_ADDR_CLASSC) {
+ return FALSE;
+ }
+
+ return NetIp4IsUnicast (Ip, Netmask);
+}
+
+/**
+ Calculate the prefix length of the IPv4 subnet mask.
+
+ @param[in] SubnetMask The IPv4 subnet mask.
+
+ @return The prefix length of the subnet mask.
+ @retval 0 Other errors as indicated.
+
+**/
+UINT8
+GetSubnetMaskPrefixLength (
+ IN EFI_IPv4_ADDRESS *SubnetMask
+ )
+{
+ UINT8 Len;
+ UINT32 ReverseMask;
+
+ //
+ // The SubnetMask is in network byte order.
+ //
+ ReverseMask = SwapBytes32 (*(UINT32 *)&SubnetMask[0]);
+
+ //
+ // Reverse it.
+ //
+ ReverseMask = ~ReverseMask;
+
+ if ((ReverseMask & (ReverseMask + 1)) != 0) {
+ return 0;
+ }
+
+ Len = 0;
+
+ while (ReverseMask != 0) {
+ ReverseMask = ReverseMask >> 1;
+ Len++;
+ }
+
+ return (UINT8)(32 - Len);
+}
+
+/**
+ Convert the decimal dotted IPv4 address into the binary IPv4 address.
+
+ @param[in] Str The UNICODE string.
+ @param[out] Ip The storage to return the IPv4 address.
+
+ @retval EFI_SUCCESS The binary IP address is returned in Ip.
+ @retval EFI_INVALID_PARAMETER The IP string is malformatted.
+
+**/
+EFI_STATUS
+Ip4Config2StrToIp (
+ IN CHAR16 *Str,
+ OUT EFI_IPv4_ADDRESS *Ip
+ )
+{
+ UINTN Index;
+ UINTN Number;
+
+ Index = 0;
+
+ while (*Str != L'\0') {
+ if (Index > 3) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Number = 0;
+ while ((*Str >= L'0') && (*Str <= L'9')) {
+ Number = Number * 10 + (*Str - L'0');
+ Str++;
+ }
+
+ if (Number > 0xFF) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ip->Addr[Index] = (UINT8)Number;
+
+ if ((*Str != L'\0') && (*Str != L'.')) {
+ //
+ // The current character should be either the NULL terminator or
+ // the dot delimiter.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*Str == L'.') {
+ //
+ // Skip the delimiter.
+ //
+ Str++;
+ }
+
+ Index++;
+ }
+
+ if (Index != 4) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Convert the decimal dotted IPv4 addresses separated by space into the binary IPv4 address list.
+
+ @param[in] Str The UNICODE string contains IPv4 addresses.
+ @param[out] PtrIpList The storage to return the IPv4 address list.
+ @param[out] IpCount The size of the IPv4 address list.
+
+ @retval EFI_SUCCESS The binary IP address list is returned in PtrIpList.
+ @retval EFI_OUT_OF_RESOURCES Error occurs in allocating memory.
+ @retval EFI_INVALID_PARAMETER The IP string is malformatted.
+
+**/
+EFI_STATUS
+Ip4Config2StrToIpList (
+ IN CHAR16 *Str,
+ OUT EFI_IPv4_ADDRESS **PtrIpList,
+ OUT UINTN *IpCount
+ )
+{
+ UINTN BeginIndex;
+ UINTN EndIndex;
+ UINTN Index;
+ UINTN IpIndex;
+ CHAR16 *StrTemp;
+ BOOLEAN SpaceTag;
+
+ BeginIndex = 0;
+ EndIndex = BeginIndex;
+ Index = 0;
+ IpIndex = 0;
+ StrTemp = NULL;
+ SpaceTag = TRUE;
+
+ *PtrIpList = NULL;
+ *IpCount = 0;
+
+ if (Str == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get the number of Ip.
+ //
+ while (*(Str + Index) != L'\0') {
+ if (*(Str + Index) == L' ') {
+ SpaceTag = TRUE;
+ } else {
+ if (SpaceTag) {
+ (*IpCount)++;
+ SpaceTag = FALSE;
+ }
+ }
+
+ Index++;
+ }
+
+ if (*IpCount == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Allocate buffer for IpList.
+ //
+ *PtrIpList = AllocateZeroPool (*IpCount * sizeof (EFI_IPv4_ADDRESS));
+ if (*PtrIpList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Get IpList from Str.
+ //
+ Index = 0;
+ while (*(Str + Index) != L'\0') {
+ if (*(Str + Index) == L' ') {
+ if (!SpaceTag) {
+ StrTemp = AllocateZeroPool ((EndIndex - BeginIndex + 1) * sizeof (CHAR16));
+ if (StrTemp == NULL) {
+ FreePool (*PtrIpList);
+ *PtrIpList = NULL;
+ *IpCount = 0;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (StrTemp, Str + BeginIndex, (EndIndex - BeginIndex) * sizeof (CHAR16));
+ *(StrTemp + (EndIndex - BeginIndex)) = L'\0';
+
+ if (Ip4Config2StrToIp (StrTemp, &((*PtrIpList)[IpIndex])) != EFI_SUCCESS) {
+ FreePool (StrTemp);
+ FreePool (*PtrIpList);
+ *PtrIpList = NULL;
+ *IpCount = 0;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BeginIndex = EndIndex;
+ IpIndex++;
+
+ FreePool (StrTemp);
+ }
+
+ BeginIndex++;
+ EndIndex++;
+ SpaceTag = TRUE;
+ } else {
+ EndIndex++;
+ SpaceTag = FALSE;
+ }
+
+ Index++;
+
+ if (*(Str + Index) == L'\0') {
+ if (!SpaceTag) {
+ StrTemp = AllocateZeroPool ((EndIndex - BeginIndex + 1) * sizeof (CHAR16));
+ if (StrTemp == NULL) {
+ FreePool (*PtrIpList);
+ *PtrIpList = NULL;
+ *IpCount = 0;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (StrTemp, Str + BeginIndex, (EndIndex - BeginIndex) * sizeof (CHAR16));
+ *(StrTemp + (EndIndex - BeginIndex)) = L'\0';
+
+ if (Ip4Config2StrToIp (StrTemp, &((*PtrIpList)[IpIndex])) != EFI_SUCCESS) {
+ FreePool (StrTemp);
+ FreePool (*PtrIpList);
+ *PtrIpList = NULL;
+ *IpCount = 0;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FreePool (StrTemp);
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/OpenNetworkBoot/NetworkBootInternal.h b/Platform/OpenNetworkBoot/NetworkBootInternal.h
index bf51cf17bec..78c3131fa62 100644
--- a/Platform/OpenNetworkBoot/NetworkBootInternal.h
+++ b/Platform/OpenNetworkBoot/NetworkBootInternal.h
@@ -10,6 +10,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -20,6 +21,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -27,6 +29,55 @@
#include
#include
+/////
+// Ip4Config2Impl.h
+//
+typedef struct {
+ UINT16 Offset;
+ UINT32 DataSize;
+ EFI_IP4_CONFIG2_DATA_TYPE DataType;
+} IP4_CONFIG2_DATA_RECORD;
+
+//
+// Modified from original Ip4Config2Impl.h version to use flexible array member.
+//
+typedef struct {
+ UINT16 Checksum;
+ UINT16 DataRecordCount;
+ IP4_CONFIG2_DATA_RECORD DataRecord[];
+} IP4_CONFIG2_VARIABLE;
+
+#define IP4_CONFIG2_VARIABLE_ATTRIBUTE (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS)
+//
+// Ip4Config2Impl.h
+/////
+
+/////
+// Ip4Common.h
+//
+#define IP4_ALLZERO_ADDRESS 0x00000000u
+//
+// Ip4Common.h
+/////
+
+typedef struct {
+ CHAR16 *StationAddress;
+ CHAR16 *SubnetMask;
+ CHAR16 *GatewayAddress;
+ CHAR16 *DnsAddress;
+} IP4_CONFIG2_OC_CONFIG_DATA;
+
+EFI_STATUS
+Ip4Config2ConvertOcConfigDataToNvData (
+ IN CHAR16 *VarName,
+ IN IP4_CONFIG2_OC_CONFIG_DATA *ConfigData
+ );
+
+EFI_STATUS
+Ip4Config2DeleteStaticIpNvData (
+ IN CHAR16 *VarName
+ );
+
/**
Set if we should enforce https only within this driver.
**/
@@ -214,4 +265,41 @@ EnrollX509toVariable (
IN VOID *X509Data
);
+///
+/// StaticIp4.c
+///
+
+EFI_STATUS
+AddRemoveStaticIPs (
+ OC_FLEX_ARRAY *ParsedLoadOptions
+ );
+
+///
+/// Ip4Utils.c
+///
+
+BOOLEAN
+Ip4StationAddressValid (
+ IN IP4_ADDR Ip,
+ IN IP4_ADDR Netmask
+ );
+
+UINT8
+GetSubnetMaskPrefixLength (
+ IN EFI_IPv4_ADDRESS *SubnetMask
+ );
+
+EFI_STATUS
+Ip4Config2StrToIp (
+ IN CHAR16 *Str,
+ OUT EFI_IPv4_ADDRESS *Ip
+ );
+
+EFI_STATUS
+Ip4Config2StrToIpList (
+ IN CHAR16 *Str,
+ OUT EFI_IPv4_ADDRESS **PtrIpList,
+ OUT UINTN *IpCount
+ );
+
#endif // LOAD_FILE_INTERNAL_H
diff --git a/Platform/OpenNetworkBoot/OpenNetworkBoot.c b/Platform/OpenNetworkBoot/OpenNetworkBoot.c
index 0b90a83d3b8..329b340cc8a 100644
--- a/Platform/OpenNetworkBoot/OpenNetworkBoot.c
+++ b/Platform/OpenNetworkBoot/OpenNetworkBoot.c
@@ -7,9 +7,9 @@
#include "NetworkBootInternal.h"
-#define ENROLL_CERT L"--enroll-cert"
-#define DELETE_CERT L"--delete-cert"
-#define DELETE_ALL_CERTS L"--delete-all-certs"
+#define ENROLL_CERT L"enroll-cert"
+#define DELETE_CERT L"delete-cert"
+#define DELETE_ALL_CERTS L"delete-all-certs"
BOOLEAN gRequireHttpsUri;
@@ -23,6 +23,7 @@ STATIC CHAR16 *mHttpBootUri;
STATIC CHAR16 PxeBootId[] = L"PXE Boot IPv";
STATIC CHAR16 HttpBootId[] = L"HTTP Boot IPv";
+STATIC
VOID
InternalFreePickerEntry (
IN OC_PICKER_ENTRY *Entry
@@ -104,7 +105,7 @@ InternalAddEntry (
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_INFO,
- "NTBT: Missing device path - %r\n",
+ "NETB: Missing device path - %r\n",
Status
));
return Status;
@@ -193,7 +194,7 @@ GetNetworkBootEntries (
);
if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_INFO, "NTBT: Load file protocol - %r\n", Status));
+ DEBUG ((DEBUG_INFO, "NETB: Load file protocol - %r\n", Status));
return Status;
}
@@ -205,7 +206,7 @@ GetNetworkBootEntries (
for (Index = 0; Index < HandleCount; ++Index) {
NetworkDescription = BmGetNetworkDescription (HandleBuffer[Index]);
if (NetworkDescription == NULL) {
- DebugPrintDevicePathForHandle (DEBUG_INFO, "NTBT: LoadFile handle not PXE/HTTP boot DP", HandleBuffer[Index]);
+ DebugPrintDevicePathForHandle (DEBUG_INFO, "NETB: LoadFile handle not PXE/HTTP boot DP", HandleBuffer[Index]);
} else {
//
// Use fixed format network description which we control as shortcut
@@ -226,7 +227,7 @@ GetNetworkBootEntries (
&& ((IsHttpBoot && mAllowHttpBoot) || (!IsHttpBoot && mAllowPxeBoot))
)
{
- DEBUG ((DEBUG_INFO, "NTBT: Adding %s\n", NetworkDescription));
+ DEBUG ((DEBUG_INFO, "NETB: Adding %s\n", NetworkDescription));
Status = InternalAddEntry (
FlexPickerEntries,
NetworkDescription,
@@ -236,7 +237,7 @@ GetNetworkBootEntries (
IsHttpBoot
);
} else {
- DEBUG ((DEBUG_INFO, "NTBT: Ignoring %s\n", NetworkDescription));
+ DEBUG ((DEBUG_INFO, "NETB: Ignoring %s\n", NetworkDescription));
}
FreePool (NetworkDescription);
@@ -263,6 +264,7 @@ GetNetworkBootEntries (
return EFI_SUCCESS;
}
+STATIC
EFI_STATUS
EnrollCerts (
OC_FLEX_ARRAY *ParsedLoadOptions
@@ -314,7 +316,7 @@ EnrollCerts (
}
if ((EnrollCert || DeleteCert) && (Option->Unicode.Value == NULL)) {
- DEBUG ((DEBUG_INFO, "NTBT: Ignoring %s option with no cert value\n", Option->Unicode.Name));
+ DEBUG ((DEBUG_INFO, "NETB: Ignoring %s option with no cert value\n", Option->Unicode.Name));
EnrollCert = FALSE;
DeleteCert = FALSE;
}
@@ -332,7 +334,7 @@ EnrollCerts (
if (Option->Unicode.Name[OptionLen] == L':') {
Status = StrToGuid (&Option->Unicode.Name[OptionLen + 1], OwnerGuid);
if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_WARN, "NTBT: Cannot parse cert owner GUID from %s - %r\n", Option->Unicode.Name, Status));
+ DEBUG ((DEBUG_WARN, "NETB: Cannot parse cert owner GUID from %s - %r\n", Option->Unicode.Name, Status));
break;
}
}
@@ -346,7 +348,7 @@ EnrollCerts (
NULL,
&DeletedCount
);
- DEBUG ((DEBUG_INFO, "NTBT: %s %u deleted - %r\n", Option->Unicode.Name, DeletedCount, Status));
+ DEBUG ((DEBUG_INFO, "NETB: %s %u deleted - %r\n", Option->Unicode.Name, DeletedCount, Status));
} else {
//
// We do not include the terminating '\0' in the stored certificate,
@@ -371,7 +373,7 @@ EnrollCerts (
CertData,
&DeletedCount
);
- DEBUG ((DEBUG_INFO, "NTBT: %s %u deleted - %r\n", Option->Unicode.Name, DeletedCount, Status));
+ DEBUG ((DEBUG_INFO, "NETB: %s %u deleted - %r\n", Option->Unicode.Name, DeletedCount, Status));
} else {
Status = CertIsPresent (
EFI_TLS_CA_CERTIFICATE_VARIABLE,
@@ -382,10 +384,10 @@ EnrollCerts (
);
if (EFI_ERROR (Status)) {
if (Status == EFI_ALREADY_STARTED) {
- DEBUG ((DEBUG_INFO, "NTBT: %s already present\n", Option->Unicode.Name));
+ DEBUG ((DEBUG_INFO, "NETB: %s already present\n", Option->Unicode.Name));
Status = EFI_SUCCESS;
} else {
- DEBUG ((DEBUG_INFO, "NTBT: Error checking for cert presence - %r\n", Status));
+ DEBUG ((DEBUG_INFO, "NETB: Error checking for cert presence - %r\n", Status));
}
} else {
Status = EnrollX509toVariable (
@@ -395,7 +397,7 @@ EnrollCerts (
CertSize,
CertData
);
- DEBUG ((DEBUG_INFO, "NTBT: %s - %r\n", Option->Unicode.Name, Status));
+ DEBUG ((DEBUG_INFO, "NETB: %s - %r\n", Option->Unicode.Name, Status));
}
}
@@ -461,15 +463,15 @@ UefiMain (
//
// e.g. --https --uri=https://imageserver.org/OpenShell.efi
//
- mAllowIpv4 = OcHasParsedVar (ParsedLoadOptions, L"-4", OcStringFormatUnicode);
- mAllowIpv6 = OcHasParsedVar (ParsedLoadOptions, L"-6", OcStringFormatUnicode);
- mAllowPxeBoot = OcHasParsedVar (ParsedLoadOptions, L"--pxe", OcStringFormatUnicode);
- mAllowHttpBoot = OcHasParsedVar (ParsedLoadOptions, L"--http", OcStringFormatUnicode);
- mAuxEntries = OcHasParsedVar (ParsedLoadOptions, L"--aux", OcStringFormatUnicode);
- gRequireHttpsUri = OcHasParsedVar (ParsedLoadOptions, L"--https", OcStringFormatUnicode);
+ mAllowIpv4 = OcHasParsedVar (ParsedLoadOptions, L"ipv4", OcStringFormatUnicode);
+ mAllowIpv6 = OcHasParsedVar (ParsedLoadOptions, L"ipv6", OcStringFormatUnicode);
+ mAllowPxeBoot = OcHasParsedVar (ParsedLoadOptions, L"pxe", OcStringFormatUnicode);
+ mAllowHttpBoot = OcHasParsedVar (ParsedLoadOptions, L"http", OcStringFormatUnicode);
+ mAuxEntries = OcHasParsedVar (ParsedLoadOptions, L"aux", OcStringFormatUnicode);
+ gRequireHttpsUri = OcHasParsedVar (ParsedLoadOptions, L"https", OcStringFormatUnicode);
TempUri = NULL;
- OcParsedVarsGetUnicodeStr (ParsedLoadOptions, L"--uri", &TempUri);
+ OcParsedVarsGetUnicodeStr (ParsedLoadOptions, L"uri", &TempUri);
if (TempUri != NULL) {
mHttpBootUri = AllocateCopyPool (StrSize (TempUri), TempUri);
if (mHttpBootUri == NULL) {
@@ -480,13 +482,20 @@ UefiMain (
if (!EFI_ERROR (Status)) {
Status = EnrollCerts (ParsedLoadOptions);
if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_WARN, "NTBT: Failed to enroll certs - %r\n", Status));
+ DEBUG ((DEBUG_WARN, "NETB: Failed to enroll certs - %r\n", Status));
}
DEBUG_CODE_BEGIN ();
LogInstalledCerts (EFI_TLS_CA_CERTIFICATE_VARIABLE, &gEfiTlsCaCertificateGuid);
DEBUG_CODE_END ();
}
+
+ if (!EFI_ERROR (Status)) {
+ Status = AddRemoveStaticIPs (ParsedLoadOptions);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "NETB: Failed to update static IPs - %r\n", Status));
+ }
+ }
}
if (!EFI_ERROR (Status)) {
@@ -506,10 +515,10 @@ UefiMain (
if (mHttpBootUri != NULL) {
if (!mAllowHttpBoot) {
- DEBUG ((DEBUG_INFO, "NTBT: URI specified but HTTP boot is disabled\n"));
+ DEBUG ((DEBUG_INFO, "NETB: URI specified but HTTP boot is disabled\n"));
} else {
if (gRequireHttpsUri && !HasHttpsUri (mHttpBootUri)) {
- DEBUG ((DEBUG_WARN, "NTBT: Invalid URI https:// is required\n"));
+ DEBUG ((DEBUG_WARN, "NETB: Invalid URI https:// is required\n"));
mAllowHttpBoot = FALSE;
}
}
diff --git a/Platform/OpenNetworkBoot/OpenNetworkBoot.inf b/Platform/OpenNetworkBoot/OpenNetworkBoot.inf
index b892e86b11f..d1987025186 100644
--- a/Platform/OpenNetworkBoot/OpenNetworkBoot.inf
+++ b/Platform/OpenNetworkBoot/OpenNetworkBoot.inf
@@ -48,7 +48,10 @@
BmBootDescription.c
HttpBootCallback.c
HttpBootCustomRead.c
+ Ip4Config2Nv.c
+ Ip4Utils.c
NetworkBootInternal.h
OpenNetworkBoot.c
+ StaticIp4.c
TlsAuthConfigImpl.c
Uri.c
diff --git a/Platform/OpenNetworkBoot/StaticIp4.c b/Platform/OpenNetworkBoot/StaticIp4.c
new file mode 100644
index 00000000000..008bf007720
--- /dev/null
+++ b/Platform/OpenNetworkBoot/StaticIp4.c
@@ -0,0 +1,188 @@
+/** @file
+ Static IPv4 handling for HTTP Boot.
+ Set and remove NVRAM vars in which Ip4Dxe stores per MAC(+VLAN) IP settings.
+
+ Copyright (c) 2024, Mike Beaton. All rights reserved.
+ SPDX-License-Identifier: BSD-3-Clause
+**/
+
+#include "NetworkBootInternal.h"
+
+typedef enum {
+ MAC_STRING_MAC_ADDRESS,
+ MAC_STRING_VLAN
+} PARSE_MAC_ADDRESS_STATE;
+
+#define STATIC4 L"static4:"
+
+#define NORMAL_MAC_ADDRESS_DIGIT_COUNT (NET_ETHER_ADDR_LEN * 2)
+#define MAX_MAC_ADDRESS_DIGIT_COUNT (sizeof (EFI_MAC_ADDRESS) * 2)
+#define VLAN_DIGIT_COUNT 4
+
+//
+// Variable length hex digit MAC string with no separators, follow by optional backslash then 4 digit hex VLAN id string.
+// REF: https://github.com/tianocore/edk2/blob/e99d532fd7224e68026543834ed9c0fe3cfaf88c/NetworkPkg/Library/DxeNetLib/DxeNetLib.c#L2363
+//
+STATIC
+EFI_STATUS
+ValidateMacString (
+ CHAR16 *MacString
+ )
+{
+ PARSE_MAC_ADDRESS_STATE State;
+ CHAR16 *Walker;
+ CHAR16 Ch;
+ UINTN Count;
+
+ State = MAC_STRING_MAC_ADDRESS;
+ Count = 0;
+ Walker = MacString;
+
+ for ( ; ;) {
+ Ch = *Walker;
+ switch (State) {
+ case MAC_STRING_MAC_ADDRESS:
+ if ((Ch == CHAR_NULL) || (Ch == L'\\')) {
+ if (Count != NORMAL_MAC_ADDRESS_DIGIT_COUNT) {
+ DEBUG ((
+ DEBUG_INFO,
+ "NETB: Non-standard MAC address length %d!=%d (invalid unless iSCSI)!\n",
+ Count,
+ NORMAL_MAC_ADDRESS_DIGIT_COUNT
+ ));
+ }
+
+ if (Ch == CHAR_NULL) {
+ return EFI_SUCCESS;
+ }
+
+ State = MAC_STRING_VLAN;
+ Count = 0;
+ }
+
+ break;
+
+ case MAC_STRING_VLAN:
+ if (Ch == CHAR_NULL) {
+ if (Count != VLAN_DIGIT_COUNT) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ break;
+ }
+
+ if (!(((Ch >= L'0') && (Ch <= L'9')) || ((Ch >= L'A') && (Ch <= L'F')) || ((Ch >= L'a') && (Ch <= L'f')))) {
+ if ((Ch == ':') || (Ch == '-')) {
+ DEBUG ((DEBUG_WARN, "NETB: Do not use : or - separators in %s{MAC}\n", STATIC4));
+ }
+
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ++Walker;
+ ++Count;
+
+ if (Count > ((State == MAC_STRING_MAC_ADDRESS) ? MAX_MAC_ADDRESS_DIGIT_COUNT : VLAN_DIGIT_COUNT)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+}
+
+//
+// Normalise in separate pass to avoid users complaining 'that's not my MAC string' and to avoid
+// showing half-converted MAC string in error messages.
+//
+STATIC
+VOID
+NormaliseMacString (
+ CHAR16 *MacString
+ )
+{
+ CHAR16 *Walker;
+ CHAR16 Ch;
+
+ for (Walker = MacString; (Ch = *Walker) != CHAR_NULL; ++Walker) {
+ if ((Ch >= L'a') && (Ch <= L'f')) {
+ //
+ // All digits are upper cased.
+ // REF: https://github.com/tianocore/edk2/blob/e99d532fd7224e68026543834ed9c0fe3cfaf88c/NetworkPkg/Library/DxeNetLib/DxeNetLib.c#L2363
+ //
+ *Walker -= (L'a' - L'A');
+ }
+ }
+}
+
+STATIC
+CHAR16 *
+GetNextIp4 (
+ CHAR16 *CurrentIP,
+ CHAR8 *RequiredName
+ )
+{
+ CHAR16 *NextIP;
+
+ NextIP = StrStr (CurrentIP, L",");
+ if (NextIP == NULL) {
+ if (RequiredName != NULL) {
+ DEBUG ((DEBUG_WARN, "NETB: Missing required %a\n", RequiredName));
+ }
+
+ return NULL;
+ }
+
+ *NextIP = CHAR_NULL;
+
+ return ++NextIP;
+}
+
+EFI_STATUS
+AddRemoveStaticIPs (
+ OC_FLEX_ARRAY *ParsedLoadOptions
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ OC_PARSED_VAR *Option;
+ CHAR16 *MacString;
+ IP4_CONFIG2_OC_CONFIG_DATA ConfigData;
+
+ //
+ // Find and apply static IP settings in driver arguments.
+ //
+ for (Index = 0; Index < ParsedLoadOptions->Count; ++Index) {
+ Option = OcFlexArrayItemAt (ParsedLoadOptions, Index);
+
+ if (OcUnicodeStartsWith (Option->Unicode.Name, STATIC4, FALSE)) {
+ MacString = &Option->Unicode.Name[L_STR_LEN (STATIC4)];
+ Status = ValidateMacString (MacString);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "NETB: Invalid MAC %s - %r\n", MacString, Status));
+ continue;
+ }
+
+ NormaliseMacString (MacString);
+ if (Option->Unicode.Value == NULL) {
+ Ip4Config2DeleteStaticIpNvData (MacString);
+ } else {
+ ConfigData.StationAddress = Option->Unicode.Value;
+ ConfigData.SubnetMask = GetNextIp4 (ConfigData.StationAddress, "subnet mask");
+ if (ConfigData.SubnetMask == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ConfigData.GatewayAddress = GetNextIp4 (ConfigData.SubnetMask, "gateway");
+ if (ConfigData.GatewayAddress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ConfigData.DnsAddress = GetNextIp4 (ConfigData.GatewayAddress, NULL);
+ Ip4Config2ConvertOcConfigDataToNvData (MacString, &ConfigData);
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/OpenNetworkBoot/TlsAuthConfigImpl.c b/Platform/OpenNetworkBoot/TlsAuthConfigImpl.c
index ed2aa313e23..cc4f9dea3a4 100644
--- a/Platform/OpenNetworkBoot/TlsAuthConfigImpl.c
+++ b/Platform/OpenNetworkBoot/TlsAuthConfigImpl.c
@@ -145,7 +145,7 @@ LogCert (
IN EFI_SIGNATURE_DATA *Cert
)
{
- DEBUG ((DEBUG_INFO, "NTBT: Cert %u owner %g\n", CertIndex, &Cert->SignatureOwner));
+ DEBUG ((DEBUG_INFO, "NETB: Cert %u owner %g\n", CertIndex, &Cert->SignatureOwner));
return EFI_SUCCESS;
}
@@ -163,7 +163,7 @@ LogInstalledCerts (
IN EFI_GUID *VendorGuid
)
{
- DEBUG ((DEBUG_INFO, "NTBT: Listing installed certs...\n"));
+ DEBUG ((DEBUG_INFO, "NETB: Listing installed certs...\n"));
return ProcessAllCerts (
VariableName,
VendorGuid,