]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[cachedhcp] Include VLAN tag in filter for applying cached DHCPACK
authorMichael Brown <mcb30@ipxe.org>
Thu, 22 Dec 2022 14:59:29 +0000 (14:59 +0000)
committerMichael Brown <mcb30@ipxe.org>
Thu, 22 Dec 2022 14:59:29 +0000 (14:59 +0000)
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>
src/arch/x86/interface/pcbios/bios_cachedhcp.c
src/core/cachedhcp.c
src/include/ipxe/cachedhcp.h
src/include/ipxe/efi/efi_cachedhcp.h
src/interface/efi/efi_cachedhcp.c
src/interface/efi/efiprefix.c

index 277c40d6fd49aeb57148611f751e50b1a2d70659..bea803d6e86594f1b4d41ddfa2d82b7956083b13 100644 (file)
@@ -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",
index c4ca46e3ab7a944815167a060103afe9f262b8dd..ef2146626f2814a24729bec51d56a2fe25cfc1dc 100644 (file)
@@ -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;
 }
index 39ce745433ae66cacab1ff37479216dde2665951..4ce4a9f2a8ad41c6f614374a5cf9a1bcee85c2ef 100644 (file)
@@ -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 */
index cd60d4095d09ab66fce550f48c935c5b6cd33ff4..5968a1ea223dc66dd9421c7fb8cea799646b0a60 100644 (file)
@@ -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 */
index 1d4b98fd6881845c840a9af819d6a6323b1107f6..b9e49cf487379f9e020b567047d84f33e3fa1a65 100644 (file)
@@ -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",
index 126c813d718b990fc45e2ba6a2b1e9aa1d93547a..7286b3e033f2c4d90c775b9be1fb13b246ed7b74 100644 (file)
@@ -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 );