]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[efi] Register EFI IPv6 device path settings as netX.ndp 1699/head
authorMichael Brown <mcb30@ipxe.org>
Thu, 30 Apr 2026 13:25:18 +0000 (14:25 +0100)
committerMichael Brown <mcb30@ipxe.org>
Thu, 30 Apr 2026 13:25:18 +0000 (14:25 +0100)
The EFI device path settings are currently registered as the
"netX.dhcp" settings block, in order that they will be automatically
overridden if a real DHCP configuration takes place.  This does not
work as expected in an IPv6-only network, since the IPv6 configurator
will register "netX.ndp" rather than "netX.dhcp".

Fix by registering the EFI device path settings as either "netX.dhcp"
or "netX.ndp" based on the first address family encountered within the
device path.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/include/ipxe/efi/efi_path.h
src/interface/efi/efi_path.c

index f68d782fba8d8555877657c687b093f87bde49ef..e1af4fe15041895c4876760b4c3b76b3946d61d3 100644 (file)
@@ -47,6 +47,7 @@ extern size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path );
 extern int efi_path_check ( EFI_DEVICE_PATH_PROTOCOL *path, size_t max );
 extern void * efi_path_mac ( EFI_DEVICE_PATH_PROTOCOL *path );
 extern unsigned int efi_path_vlan ( EFI_DEVICE_PATH_PROTOCOL *path );
+extern unsigned int efi_path_family ( EFI_DEVICE_PATH_PROTOCOL *path );
 extern int efi_path_guid ( EFI_DEVICE_PATH_PROTOCOL *path, union uuid *uuid );
 extern struct uri * efi_path_uri ( EFI_DEVICE_PATH_PROTOCOL *path );
 extern EFI_DEVICE_PATH_PROTOCOL * efi_paths ( EFI_DEVICE_PATH_PROTOCOL *first,
index 7d7091382c940ff485e58c36004b961a8f430ec8..54aaeb0ebaed3e7b17d15e309f9737bd440e18f7 100644 (file)
@@ -37,6 +37,7 @@ FILE_SECBOOT ( PERMITTED );
 #include <ipxe/usb.h>
 #include <ipxe/settings.h>
 #include <ipxe/dhcp.h>
+#include <ipxe/ndp.h>
 #include <ipxe/efi/efi.h>
 #include <ipxe/efi/efi_driver.h>
 #include <ipxe/efi/efi_strings.h>
@@ -251,6 +252,30 @@ unsigned int efi_path_vlan ( EFI_DEVICE_PATH_PROTOCOL *path ) {
        return 0;
 }
 
+/**
+ * Get IP address family from device path
+ *
+ * @v path             Device path
+ * @ret family         Address family, or 0 if not recognised
+ */
+unsigned int efi_path_family ( EFI_DEVICE_PATH_PROTOCOL *path ) {
+       EFI_DEVICE_PATH_PROTOCOL *next;
+
+       /* Search for IP address device path */
+       for ( ; ( next = efi_path_next ( path ) ) ; path = next ) {
+               if ( path->Type == MESSAGING_DEVICE_PATH ) {
+                       if ( path->SubType == MSG_IPv4_DP ) {
+                               return AF_INET;
+                       } else if ( path->SubType == MSG_IPv6_DP ) {
+                               return AF_INET6;
+                       }
+               }
+       }
+
+       /* No IP address device path found */
+       return 0;
+}
+
 /**
  * Get partition GUID from device path
  *
@@ -1103,7 +1128,9 @@ static int efi_path_net_probe ( struct net_device *netdev, void *priv ) {
        struct efi_path_settings *pathsets = priv;
        struct settings *settings = &pathsets->settings;
        EFI_DEVICE_PATH_PROTOCOL *path = efi_loaded_image_path;
+       const char *name;
        unsigned int vlan;
+       unsigned int family;
        void *mac;
        int rc;
 
@@ -1111,6 +1138,7 @@ static int efi_path_net_probe ( struct net_device *netdev, void *priv ) {
        pathsets->path = path;
        mac = efi_path_mac ( path );
        vlan = efi_path_vlan ( path );
+       family = efi_path_family ( path );
        if ( ( mac == NULL ) ||
             ( memcmp ( mac, netdev->ll_addr,
                        netdev->ll_protocol->ll_addr_len ) != 0 ) ||
@@ -1123,11 +1151,24 @@ static int efi_path_net_probe ( struct net_device *netdev, void *priv ) {
        /* Mark network device to be opened automatically */
        netdev->state |= NETDEV_AUTO_OPEN;
 
-       /* Never override a real DHCP settings block */
-       if ( find_child_settings ( netdev_settings ( netdev ),
-                                  DHCP_SETTINGS_NAME ) ) {
-               DBGC ( settings, "EFI path %s not overriding %s DHCP "
-                      "settings\n", efi_devpath_text ( path ), netdev->name );
+       /* Determine settings block name */
+       switch ( family ) {
+       case AF_INET:
+               name = DHCP_SETTINGS_NAME;
+               break;
+       case AF_INET6:
+               name = NDP_SETTINGS_NAME;
+               break;
+       default:
+               DBGC ( settings, "EFI path %s has no IP address\n",
+                      efi_devpath_text ( path ) );
+               return 0;
+       }
+
+       /* Never override a real settings block */
+       if ( find_child_settings ( netdev_settings ( netdev ), name ) ) {
+               DBGC ( settings, "EFI path %s not overriding %s.%s settings\n",
+                      efi_devpath_text ( path ), netdev->name, name );
                return 0;
        }
 
@@ -1135,14 +1176,14 @@ static int efi_path_net_probe ( struct net_device *netdev, void *priv ) {
        settings_init ( settings, &efi_path_settings_operations,
                        &netdev->refcnt, NULL );
        if ( ( rc = register_settings ( settings, netdev_settings ( netdev ),
-                                       DHCP_SETTINGS_NAME ) ) != 0 ) {
-               DBGC ( settings, "EFI path %s could not register for %s: %s\n",
-                      efi_devpath_text ( path ), netdev->name,
+                                       name ) ) != 0 ) {
+               DBGC ( settings, "EFI path %s could not register %s.%s: %s\n",
+                      efi_devpath_text ( path ), netdev->name, name,
                       strerror ( rc ) );
                return rc;
        }
-       DBGC ( settings, "EFI path %s registered for %s\n",
-              efi_devpath_text ( path ), netdev->name );
+       DBGC ( settings, "EFI path %s registered %s.%s\n",
+              efi_devpath_text ( path ), netdev->name, name );
 
        return 0;
 }