diff options
author | Michael Brown <mcb30@ipxe.org> | 2022-12-22 14:59:29 +0000 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2022-12-22 14:59:29 +0000 |
commit | 60b5532cfc1393a8d34cece1b49f953bd72c303c (patch) | |
tree | 385698046b0150b477cd13794b6a6914a3ab830b | |
parent | b9571ca12ed80472051663e2618dfe083f995da3 (diff) | |
download | ipxe-60b5532cfc1393a8d34cece1b49f953bd72c303c.zip ipxe-60b5532cfc1393a8d34cece1b49f953bd72c303c.tar.gz ipxe-60b5532cfc1393a8d34cece1b49f953bd72c303c.tar.bz2 |
[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 <mcb30@ipxe.org>
-rw-r--r-- | src/arch/x86/interface/pcbios/bios_cachedhcp.c | 2 | ||||
-rw-r--r-- | src/core/cachedhcp.c | 28 | ||||
-rw-r--r-- | src/include/ipxe/cachedhcp.h | 3 | ||||
-rw-r--r-- | src/include/ipxe/efi/efi_cachedhcp.h | 3 | ||||
-rw-r--r-- | src/interface/efi/efi_cachedhcp.c | 17 | ||||
-rw-r--r-- | src/interface/efi/efiprefix.c | 3 |
6 files changed, 41 insertions, 15 deletions
diff --git a/src/arch/x86/interface/pcbios/bios_cachedhcp.c b/src/arch/x86/interface/pcbios/bios_cachedhcp.c index 277c40d..bea803d 100644 --- a/src/arch/x86/interface/pcbios/bios_cachedhcp.c +++ b/src/arch/x86/interface/pcbios/bios_cachedhcp.c @@ -59,7 +59,7 @@ static void cachedhcp_init ( void ) { } /* Record cached DHCPACK */ - if ( ( rc = cachedhcp_record ( &cached_dhcpack, + if ( ( rc = cachedhcp_record ( &cached_dhcpack, 0, phys_to_user ( cached_dhcpack_phys ), sizeof ( BOOTPLAYER_t ) ) ) != 0 ) { DBGC ( colour, "CACHEDHCP could not record DHCPACK: %s\n", diff --git a/src/core/cachedhcp.c b/src/core/cachedhcp.c index c4ca46e..ef21466 100644 --- a/src/core/cachedhcp.c +++ b/src/core/cachedhcp.c @@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/dhcppkt.h> #include <ipxe/init.h> #include <ipxe/netdevice.h> +#include <ipxe/vlan.h> #include <ipxe/cachedhcp.h> /** @file @@ -43,6 +44,8 @@ struct cached_dhcp_packet { const char *name; /** DHCP packet (if any) */ struct dhcp_packet *dhcppkt; + /** VLAN tag (if applicable) */ + unsigned int vlan; }; /** Cached DHCPACK */ @@ -136,15 +139,26 @@ static int cachedhcp_apply ( struct cached_dhcp_packet *cache, * matches this network device. */ if ( memcmp ( ll_addr, chaddr, ll_addr_len ) != 0 ) { - DBGC ( colour, "CACHEDHCP %s does not match %s\n", - cache->name, netdev->name ); + DBGC ( colour, "CACHEDHCP %s %s does not match %s\n", + cache->name, ll_protocol->ntoa ( chaddr ), + netdev->name ); + return 0; + } + + /* Do nothing unless cached packet's VLAN tag matches + * this network device. + */ + if ( vlan_tag ( netdev ) != cache->vlan ) { + DBGC ( colour, "CACHEDHCP %s VLAN %d does not match " + "%s\n", cache->name, cache->vlan, + netdev->name ); return 0; } - DBGC ( colour, "CACHEDHCP %s is for %s\n", - cache->name, netdev->name ); /* Use network device's settings block */ settings = netdev_settings ( netdev ); + DBGC ( colour, "CACHEDHCP %s is for %s\n", + cache->name, netdev->name ); } /* Register settings */ @@ -165,12 +179,13 @@ static int cachedhcp_apply ( struct cached_dhcp_packet *cache, * Record cached DHCP packet * * @v cache Cached DHCP packet + * @v vlan VLAN tag, if any * @v data DHCPACK packet buffer * @v max_len Maximum possible length * @ret rc Return status code */ -int cachedhcp_record ( struct cached_dhcp_packet *cache, userptr_t data, - size_t max_len ) { +int cachedhcp_record ( struct cached_dhcp_packet *cache, unsigned int vlan, + userptr_t data, size_t max_len ) { struct dhcp_packet *dhcppkt; struct dhcp_packet *tmp; struct dhcphdr *dhcphdr; @@ -225,6 +240,7 @@ int cachedhcp_record ( struct cached_dhcp_packet *cache, userptr_t data, DBGC ( colour, "CACHEDHCP %s at %#08lx+%#zx/%#zx\n", cache->name, user_to_phys ( data, 0 ), len, max_len ); cache->dhcppkt = dhcppkt; + cache->vlan = vlan; return 0; } diff --git a/src/include/ipxe/cachedhcp.h b/src/include/ipxe/cachedhcp.h index 39ce745..4ce4a9f 100644 --- a/src/include/ipxe/cachedhcp.h +++ b/src/include/ipxe/cachedhcp.h @@ -18,7 +18,8 @@ extern struct cached_dhcp_packet cached_dhcpack; extern struct cached_dhcp_packet cached_proxydhcp; extern struct cached_dhcp_packet cached_pxebs; -extern int cachedhcp_record ( struct cached_dhcp_packet *cache, userptr_t data, +extern int cachedhcp_record ( struct cached_dhcp_packet *cache, + unsigned int vlan, userptr_t data, size_t max_len ); #endif /* _IPXE_CACHEDHCP_H */ diff --git a/src/include/ipxe/efi/efi_cachedhcp.h b/src/include/ipxe/efi/efi_cachedhcp.h index cd60d40..5968a1e 100644 --- a/src/include/ipxe/efi/efi_cachedhcp.h +++ b/src/include/ipxe/efi/efi_cachedhcp.h @@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/efi/efi.h> -extern int efi_cachedhcp_record ( EFI_HANDLE device ); +extern int efi_cachedhcp_record ( EFI_HANDLE device, + EFI_DEVICE_PATH_PROTOCOL *path ); #endif /* _IPXE_EFI_CACHEDHCP_H */ diff --git a/src/interface/efi/efi_cachedhcp.c b/src/interface/efi/efi_cachedhcp.c index 1d4b98f..b9e49cf 100644 --- a/src/interface/efi/efi_cachedhcp.c +++ b/src/interface/efi/efi_cachedhcp.c @@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <errno.h> #include <ipxe/cachedhcp.h> #include <ipxe/efi/efi.h> +#include <ipxe/efi/efi_path.h> #include <ipxe/efi/efi_cachedhcp.h> #include <ipxe/efi/Protocol/PxeBaseCode.h> @@ -40,10 +41,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * Record cached DHCP packet * * @v device Device handle + * @v path Device path * @ret rc Return status code */ -int efi_cachedhcp_record ( EFI_HANDLE device ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; +int efi_cachedhcp_record ( EFI_HANDLE device, + EFI_DEVICE_PATH_PROTOCOL *path ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + unsigned int vlan; union { EFI_PXE_BASE_CODE_PROTOCOL *pxe; void *interface; @@ -52,6 +56,9 @@ int efi_cachedhcp_record ( EFI_HANDLE device ) { EFI_STATUS efirc; int rc; + /* Get VLAN tag, if any */ + vlan = efi_path_vlan ( path ); + /* Look for a PXE base code instance on the image's device handle */ if ( ( efirc = bs->OpenProtocol ( device, &efi_pxe_base_code_protocol_guid, @@ -75,7 +82,7 @@ int efi_cachedhcp_record ( EFI_HANDLE device ) { /* Record DHCPACK, if present */ if ( mode->DhcpAckReceived && - ( ( rc = cachedhcp_record ( &cached_dhcpack, + ( ( rc = cachedhcp_record ( &cached_dhcpack, vlan, virt_to_user ( &mode->DhcpAck ), sizeof ( mode->DhcpAck ) ) ) != 0 ) ) { DBGC ( device, "EFI %s could not record DHCPACK: %s\n", @@ -85,7 +92,7 @@ int efi_cachedhcp_record ( EFI_HANDLE device ) { /* Record ProxyDHCPOFFER, if present */ if ( mode->ProxyOfferReceived && - ( ( rc = cachedhcp_record ( &cached_proxydhcp, + ( ( rc = cachedhcp_record ( &cached_proxydhcp, vlan, virt_to_user ( &mode->ProxyOffer ), sizeof ( mode->ProxyOffer ) ) ) != 0)){ DBGC ( device, "EFI %s could not record ProxyDHCPOFFER: %s\n", @@ -95,7 +102,7 @@ int efi_cachedhcp_record ( EFI_HANDLE device ) { /* Record PxeBSACK, if present */ if ( mode->PxeReplyReceived && - ( ( rc = cachedhcp_record ( &cached_pxebs, + ( ( rc = cachedhcp_record ( &cached_pxebs, vlan, virt_to_user ( &mode->PxeReply ), sizeof ( mode->PxeReply ) ) ) != 0)){ DBGC ( device, "EFI %s could not record PXEBSACK: %s\n", diff --git a/src/interface/efi/efiprefix.c b/src/interface/efi/efiprefix.c index 126c813..7286b3e 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 ); |