]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[autoboot] Include VLAN tag in filter for identifying autoboot device
authorMichael Brown <mcb30@ipxe.org>
Sun, 15 Jan 2023 21:36:08 +0000 (21:36 +0000)
committerMichael Brown <mcb30@ipxe.org>
Sun, 15 Jan 2023 21:36:08 +0000 (21:36 +0000)
When chainloading iPXE from a VLAN device, the MAC address of the
loaded image's device handle will match the MAC address of the trunk
device created by iPXE, and the autoboot process will then erroneously
consider the trunk device to be an autoboot device.

Fix by recording the VLAN tag along with the MAC address, and treating
the VLAN tag as part of the filter used to match the MAC address
against candidate network devices.

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

index 706885e28d882effe6d18b01fcee20e127a8742a..94fd2d7662769d27c7c2daeacc4a2cc9fad768b8 100644 (file)
@@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 
 #include <ipxe/efi/efi.h>
 
-extern int efi_set_autoboot_ll_addr ( EFI_HANDLE device );
+extern int efi_set_autoboot_ll_addr ( EFI_HANDLE device,
+                                     EFI_DEVICE_PATH_PROTOCOL *path );
 
 #endif /* _IPXE_EFI_AUTOBOOT_H */
index f88b8494f9c62b38662af201eadbade929a43baf..3719b824328bce5f4462454adc1d8c94b1d5e5d8 100644 (file)
@@ -28,7 +28,8 @@ enum uriboot_flags {
 
 extern void set_autoboot_busloc ( unsigned int bus_type,
                                  unsigned int location );
-extern void set_autoboot_ll_addr ( const void *ll_addr, size_t len );
+extern void set_autoboot_ll_addr ( const void *ll_addr, size_t len,
+                                  unsigned int vlan );
 
 extern int uriboot ( struct uri *filename, struct uri **root_paths,
                     unsigned int root_path_count, int drive,
index 08d67f761fcdc7ccb7bd471d012b7d1b93890253..ec7793cd71c069d6dbaf46bb562c5dfd61150b36 100644 (file)
@@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 #include <string.h>
 #include <errno.h>
 #include <ipxe/efi/efi.h>
+#include <ipxe/efi/efi_path.h>
 #include <ipxe/efi/efi_autoboot.h>
 #include <ipxe/efi/Protocol/SimpleNetwork.h>
 #include <usr/autoboot.h>
@@ -40,9 +41,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  * Identify autoboot device
  *
  * @v device           Device handle
+ * @v path             Device path
  * @ret rc             Return status code
  */
-int efi_set_autoboot_ll_addr ( EFI_HANDLE device ) {
+int efi_set_autoboot_ll_addr ( EFI_HANDLE device,
+                              EFI_DEVICE_PATH_PROTOCOL *path ) {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        union {
                EFI_SIMPLE_NETWORK_PROTOCOL *snp;
@@ -50,6 +53,7 @@ int efi_set_autoboot_ll_addr ( EFI_HANDLE device ) {
        } snp;
        EFI_SIMPLE_NETWORK_MODE *mode;
        EFI_STATUS efirc;
+       unsigned int vlan;
        int rc;
 
        /* Look for an SNP instance on the image's device handle */
@@ -66,10 +70,16 @@ int efi_set_autoboot_ll_addr ( EFI_HANDLE device ) {
 
        /* Record autoboot device */
        mode = snp.snp->Mode;
-       set_autoboot_ll_addr ( &mode->CurrentAddress, mode->HwAddressSize );
+       vlan = efi_path_vlan ( path );
+       set_autoboot_ll_addr ( &mode->CurrentAddress, mode->HwAddressSize,
+                              vlan );
        DBGC ( device, "EFI %s found autoboot link-layer address:\n",
               efi_handle_name ( device ) );
        DBGC_HDA ( device, 0, &mode->CurrentAddress, mode->HwAddressSize );
+       if ( vlan ) {
+               DBGC ( device, "EFI %s found autoboot VLAN %d\n",
+                      efi_handle_name ( device ), vlan );
+       }
 
        /* Close protocol */
        bs->CloseProtocol ( device, &efi_simple_network_protocol_guid,
index 7286b3e033f2c4d90c775b9be1fb13b246ed7b74..bdc36d9bd7e84a9898e0ec2a29a5d8305624f931 100644 (file)
@@ -81,7 +81,7 @@ static void efi_init_application ( void ) {
        EFI_DEVICE_PATH_PROTOCOL *path = efi_loaded_image_path;
 
        /* Identify autoboot device, if any */
-       efi_set_autoboot_ll_addr ( device );
+       efi_set_autoboot_ll_addr ( device, path );
 
        /* Store cached DHCP packet, if any */
        efi_cachedhcp_record ( device, path );
index 24043ae699ca0673eef54eacdfa1482a62ac6841..d1f25962159c14ff7c91b525e869f2754afb7313 100644 (file)
@@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 #include <stdio.h>
 #include <errno.h>
 #include <ipxe/netdevice.h>
+#include <ipxe/vlan.h>
 #include <ipxe/dhcp.h>
 #include <ipxe/settings.h>
 #include <ipxe/image.h>
@@ -57,6 +58,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 /** Link-layer address of preferred autoboot device, if known */
 static uint8_t autoboot_ll_addr[MAX_LL_ADDR_LEN];
 
+/** VLAN tag of preferred autoboot device, if known */
+static unsigned int autoboot_vlan;
+
 /** Device location of preferred autoboot device, if known */
 static struct device_description autoboot_desc;
 
@@ -494,8 +498,9 @@ void set_autoboot_busloc ( unsigned int bus_type, unsigned int location ) {
  */
 static int is_autoboot_ll_addr ( struct net_device *netdev ) {
 
-       return ( memcmp ( netdev->ll_addr, autoboot_ll_addr,
-                         netdev->ll_protocol->ll_addr_len ) == 0 );
+       return ( ( memcmp ( netdev->ll_addr, autoboot_ll_addr,
+                           netdev->ll_protocol->ll_addr_len ) == 0 ) &&
+                ( vlan_tag ( netdev ) == autoboot_vlan ) );
 }
 
 /**
@@ -503,14 +508,19 @@ static int is_autoboot_ll_addr ( struct net_device *netdev ) {
  *
  * @v ll_addr          Link-layer address
  * @v len              Length of link-layer address
+ * @v vlan             VLAN tag
  */
-void set_autoboot_ll_addr ( const void *ll_addr, size_t len ) {
+void set_autoboot_ll_addr ( const void *ll_addr, size_t len,
+                           unsigned int vlan ) {
 
        /* Record autoboot link-layer address (truncated if necessary) */
        if ( len > sizeof ( autoboot_ll_addr ) )
                len = sizeof ( autoboot_ll_addr );
        memcpy ( autoboot_ll_addr, ll_addr, len );
 
+       /* Record autoboot VLAN tag */
+       autoboot_vlan = vlan;
+
        /* Mark autoboot device as present */
        is_autoboot_device = is_autoboot_ll_addr;
 }