From 60b5532cfc1393a8d34cece1b49f953bd72c303c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 22 Dec 2022 14:59:29 +0000 Subject: [cachedhcp] Include VLAN tag in filter for applying cached DHCPACK When chainloading iPXE from a VLAN device, the MAC address within the cached DHCPACK will match the MAC address of the trunk device created by iPXE, and the cached DHCPACK will then end up being erroneously applied to the trunk device. This tends to break outbound IPv4 routing, since both the trunk and VLAN devices will have the same assigned IPv4 address. Fix by recording the VLAN tag along with the cached DHCPACK, and treating the VLAN tag as part of the filter used to match the cached DHCPACK against candidate network devices. Signed-off-by: Michael Brown --- src/interface/efi/efiprefix.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/interface/efi/efiprefix.c') diff --git a/src/interface/efi/efiprefix.c b/src/interface/efi/efiprefix.c index 126c813d7..7286b3e03 100644 --- a/src/interface/efi/efiprefix.c +++ b/src/interface/efi/efiprefix.c @@ -78,12 +78,13 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle, */ static void efi_init_application ( void ) { EFI_HANDLE device = efi_loaded_image->DeviceHandle; + EFI_DEVICE_PATH_PROTOCOL *path = efi_loaded_image_path; /* Identify autoboot device, if any */ efi_set_autoboot_ll_addr ( device ); /* Store cached DHCP packet, if any */ - efi_cachedhcp_record ( device ); + efi_cachedhcp_record ( device, path ); /* Load autoexec script, if any */ efi_autoexec_load ( device ); -- cgit v1.2.3-55-g7522 From 5a2fa6040e17562ce742df09aa20b8774b3879c5 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 15 Jan 2023 21:36:08 +0000 Subject: [autoboot] Include VLAN tag in filter for identifying autoboot device 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 --- src/include/ipxe/efi/efi_autoboot.h | 3 ++- src/include/usr/autoboot.h | 3 ++- src/interface/efi/efi_autoboot.c | 14 ++++++++++++-- src/interface/efi/efiprefix.c | 2 +- src/usr/autoboot.c | 16 +++++++++++++--- 5 files changed, 30 insertions(+), 8 deletions(-) (limited to 'src/interface/efi/efiprefix.c') diff --git a/src/include/ipxe/efi/efi_autoboot.h b/src/include/ipxe/efi/efi_autoboot.h index 706885e28..94fd2d766 100644 --- a/src/include/ipxe/efi/efi_autoboot.h +++ b/src/include/ipxe/efi/efi_autoboot.h @@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include -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 */ diff --git a/src/include/usr/autoboot.h b/src/include/usr/autoboot.h index f88b8494f..3719b8243 100644 --- a/src/include/usr/autoboot.h +++ b/src/include/usr/autoboot.h @@ -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, diff --git a/src/interface/efi/efi_autoboot.c b/src/interface/efi/efi_autoboot.c index 08d67f761..ec7793cd7 100644 --- a/src/interface/efi/efi_autoboot.c +++ b/src/interface/efi/efi_autoboot.c @@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include @@ -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, diff --git a/src/interface/efi/efiprefix.c b/src/interface/efi/efiprefix.c index 7286b3e03..bdc36d9bd 100644 --- a/src/interface/efi/efiprefix.c +++ b/src/interface/efi/efiprefix.c @@ -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 ); diff --git a/src/usr/autoboot.c b/src/usr/autoboot.c index 24043ae69..d1f259621 100644 --- a/src/usr/autoboot.c +++ b/src/usr/autoboot.c @@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include @@ -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; } -- cgit v1.2.3-55-g7522 From 6f250be279311d461f78bb17eb8b5b70ad90dd0a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 1 Feb 2023 23:54:19 +0000 Subject: [efi] Allow autoexec script to be located alongside iPXE binary Try loading the autoexec.ipxe script first from the directory containing the iPXE binary (based on the relative file path provided to us via EFI_LOADED_IMAGE_PROTOCOL), then fall back to trying the root directory. Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_autoexec.h | 3 +- src/interface/efi/efi_autoexec.c | 85 +++++++++++++++++++++++++++++-------- src/interface/efi/efiprefix.c | 9 ++-- 3 files changed, 75 insertions(+), 22 deletions(-) (limited to 'src/interface/efi/efiprefix.c') diff --git a/src/include/ipxe/efi/efi_autoexec.h b/src/include/ipxe/efi/efi_autoexec.h index 1f93b41cd..08ddf5836 100644 --- a/src/include/ipxe/efi/efi_autoexec.h +++ b/src/include/ipxe/efi/efi_autoexec.h @@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include -extern int efi_autoexec_load ( EFI_HANDLE device ); +extern int efi_autoexec_load ( EFI_HANDLE device, + EFI_DEVICE_PATH_PROTOCOL *path ); #endif /* _IPXE_EFI_AUTOEXEC_H */ diff --git a/src/interface/efi/efi_autoexec.c b/src/interface/efi/efi_autoexec.c index 79d4a4caf..fb12cef08 100644 --- a/src/interface/efi/efi_autoexec.c +++ b/src/interface/efi/efi_autoexec.c @@ -54,12 +54,14 @@ static void *efi_autoexec; static size_t efi_autoexec_len; /** - * Load autoexec script from filesystem + * Load autoexec script from path within filesystem * * @v device Device handle + * @v path Relative path to image, or NULL to load from root * @ret rc Return status code */ -static int efi_autoexec_filesystem ( EFI_HANDLE device ) { +static int efi_autoexec_filesystem ( EFI_HANDLE device, + EFI_DEVICE_PATH_PROTOCOL *path ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; union { void *interface; @@ -70,13 +72,58 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) { CHAR16 name[ sizeof ( efi_autoexec_wname ) / sizeof ( efi_autoexec_wname[0] ) ]; } info; + FILEPATH_DEVICE_PATH *filepath; EFI_FILE_PROTOCOL *root; EFI_FILE_PROTOCOL *file; UINTN size; VOID *data; + unsigned int dirlen; + size_t len; + CHAR16 *wname; EFI_STATUS efirc; int rc; + /* Identify directory */ + if ( path ) { + + /* Check relative device path is a file path */ + if ( ! ( ( path->Type == MEDIA_DEVICE_PATH ) && + ( path->SubType == MEDIA_FILEPATH_DP ) ) ) { + DBGC ( device, "EFI %s image path ", + efi_handle_name ( device ) ); + DBGC ( device, " \"%s\" is not a file path\n", + efi_devpath_text ( path ) ); + rc = -ENOTTY; + goto err_not_filepath; + } + filepath = container_of ( path, FILEPATH_DEVICE_PATH, Header ); + + /* Find length of containing directory */ + dirlen = ( ( ( ( path->Length[1] << 8 ) | path->Length[0] ) + - offsetof ( typeof ( *filepath ), PathName ) ) + / sizeof ( filepath->PathName[0] ) ); + for ( ; dirlen ; dirlen-- ) { + if ( filepath->PathName[ dirlen - 1 ] == L'\\' ) + break; + } + + } else { + + /* Use root directory */ + filepath = NULL; + dirlen = 0; + } + + /* Allocate filename */ + len = ( ( dirlen * sizeof ( wname[0] ) ) + sizeof ( efi_autoexec_wname ) ); + wname = malloc ( len ); + if ( ! wname ) { + rc = -ENOMEM; + goto err_wname; + } + memcpy ( wname, filepath->PathName, ( dirlen * sizeof ( wname[0] ) ) ); + memcpy ( &wname[dirlen], efi_autoexec_wname, sizeof ( efi_autoexec_wname ) ); + /* Open simple file system protocol */ if ( ( efirc = bs->OpenProtocol ( device, &efi_simple_file_system_protocol_guid, @@ -98,12 +145,11 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) { } /* Open autoexec script */ - if ( ( efirc = root->Open ( root, &file, efi_autoexec_wname, + if ( ( efirc = root->Open ( root, &file, wname, EFI_FILE_MODE_READ, 0 ) ) != 0 ) { rc = -EEFI ( efirc ); DBGC ( device, "EFI %s has no %ls: %s\n", - efi_handle_name ( device ), efi_autoexec_wname, - strerror ( rc ) ); + efi_handle_name ( device ), wname, strerror ( rc ) ); goto err_open; } @@ -113,8 +159,7 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) { &info ) ) != 0 ) { rc = -EEFI ( efirc ); DBGC ( device, "EFI %s could not get %ls info: %s\n", - efi_handle_name ( device ), efi_autoexec_wname, - strerror ( rc ) ); + efi_handle_name ( device ), wname, strerror ( rc ) ); goto err_getinfo; } size = info.info.FileSize; @@ -123,7 +168,7 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) { if ( ! size ) { rc = -EINVAL; DBGC ( device, "EFI %s has zero-length %ls\n", - efi_handle_name ( device ), efi_autoexec_wname ); + efi_handle_name ( device ), wname ); goto err_empty; } @@ -132,8 +177,7 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) { &data ) ) != 0 ) { rc = -EEFI ( efirc ); DBGC ( device, "EFI %s could not allocate %ls: %s\n", - efi_handle_name ( device ), efi_autoexec_wname, - strerror ( rc ) ); + efi_handle_name ( device ), wname, strerror ( rc ) ); goto err_alloc; } @@ -141,8 +185,7 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) { if ( ( efirc = file->Read ( file, &size, data ) ) != 0 ) { rc = -EEFI ( efirc ); DBGC ( device, "EFI %s could not read %ls: %s\n", - efi_handle_name ( device ), efi_autoexec_wname, - strerror ( rc ) ); + efi_handle_name ( device ), wname, strerror ( rc ) ); goto err_read; } @@ -150,8 +193,7 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) { efi_autoexec = data; efi_autoexec_len = size; data = NULL; - DBGC ( device, "EFI %s found %ls\n", - efi_handle_name ( device ), efi_autoexec_wname ); + DBGC ( device, "EFI %s found %ls\n", efi_handle_name ( device ), wname ); /* Success */ rc = 0; @@ -169,6 +211,9 @@ static int efi_autoexec_filesystem ( EFI_HANDLE device ) { bs->CloseProtocol ( device, &efi_simple_file_system_protocol_guid, efi_image_handle, device ); err_filesystem: + free ( wname ); + err_wname: + err_not_filepath: return rc; } @@ -345,17 +390,23 @@ static int efi_autoexec_tftp ( EFI_HANDLE device ) { * Load autoexec script * * @v device Device handle + * @v path Image path within device handle * @ret rc Return status code */ -int efi_autoexec_load ( EFI_HANDLE device ) { +int efi_autoexec_load ( EFI_HANDLE device, + EFI_DEVICE_PATH_PROTOCOL *path ) { int rc; /* Sanity check */ assert ( efi_autoexec == NULL ); assert ( efi_autoexec_len == 0 ); - /* Try loading from file system, if supported */ - if ( ( rc = efi_autoexec_filesystem ( device ) ) == 0 ) + /* Try loading from file system loaded image directory, if supported */ + if ( ( rc = efi_autoexec_filesystem ( device, path ) ) == 0 ) + return 0; + + /* Try loading from file system root directory, if supported */ + if ( ( rc = efi_autoexec_filesystem ( device, NULL ) ) == 0 ) return 0; /* Try loading via TFTP, if supported */ diff --git a/src/interface/efi/efiprefix.c b/src/interface/efi/efiprefix.c index bdc36d9bd..261160681 100644 --- a/src/interface/efi/efiprefix.c +++ b/src/interface/efi/efiprefix.c @@ -78,16 +78,17 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle, */ static void efi_init_application ( void ) { EFI_HANDLE device = efi_loaded_image->DeviceHandle; - EFI_DEVICE_PATH_PROTOCOL *path = efi_loaded_image_path; + EFI_DEVICE_PATH_PROTOCOL *devpath = efi_loaded_image_path; + EFI_DEVICE_PATH_PROTOCOL *filepath = efi_loaded_image->FilePath; /* Identify autoboot device, if any */ - efi_set_autoboot_ll_addr ( device, path ); + efi_set_autoboot_ll_addr ( device, devpath ); /* Store cached DHCP packet, if any */ - efi_cachedhcp_record ( device, path ); + efi_cachedhcp_record ( device, devpath ); /* Load autoexec script, if any */ - efi_autoexec_load ( device ); + efi_autoexec_load ( device, filepath ); } /** EFI application initialisation function */ -- cgit v1.2.3-55-g7522