]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[efi] Pad transmit buffer length to work around vendor driver bugs 1177/head
authorMichael Brown <mcb30@ipxe.org>
Mon, 18 Mar 2024 15:21:04 +0000 (15:21 +0000)
committerMichael Brown <mcb30@ipxe.org>
Mon, 18 Mar 2024 22:52:05 +0000 (22:52 +0000)
The Mellanox/Nvidia UEFI driver is built from the same codebase as the
iPXE driver, and appears to contain the bug that was fixed in commit
c11734e ("[golan] Use ETH_HLEN for inline header size").  This results
in identical failures when using the SNP or NII interface (via
e.g. snponly.efi) to drive a Mellanox card while EAPoL is enabled.

Work around the underlying UEFI driver bug by padding transmit I/O
buffers to the minimum Ethernet frame length before passing them to
the underlying driver's transmit function.

This padding is not technically necessary, since almost all modern
hardware will insert transmit padding as necessary (and where the
hardware does not support doing so, the underlying UEFI driver is
responsible for adding any necessary padding).  However, it is
guaranteed to be harmless (other than a miniscule performance impact):
the Ethernet specification requires zero padding up to the minimum
frame length for packets that are transmitted onto the wire, and so
the receiver will see the same packet whether or not we manually
insert this padding in software.

The additional padding causes the underlying Mellanox driver to avoid
its faulty code path, since it will never be asked to transmit a very
short packet.

Tested-by: Eric Hagberg <ehagberg@janestreet.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/drivers/net/efi/nii.c
src/drivers/net/efi/snpnet.c

index 8dd17e4b5f7c84460f3add2fd8210dbf4b5dc258..16e9e10dfbb24a80fc4b086d3583aeb2832b1836 100644 (file)
@@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 #include <errno.h>
 #include <ipxe/netdevice.h>
 #include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
 #include <ipxe/umalloc.h>
 #include <ipxe/efi/efi.h>
 #include <ipxe/efi/efi_driver.h>
@@ -998,6 +999,12 @@ static int nii_transmit ( struct net_device *netdev,
                return 0;
        }
 
+       /* Pad to minimum Ethernet length, to work around underlying
+        * drivers that do not correctly handle frame padding
+        * themselves.
+        */
+       iob_pad ( iobuf, ETH_ZLEN );
+
        /* Construct parameter block */
        memset ( &cpb, 0, sizeof ( cpb ) );
        cpb.FrameAddr = ( ( intptr_t ) iobuf->data );
index c66aa7d28d3a19ec512a05c84f04681fe0eafc5d..b8bf963e91ec3a870d862154cfc96534bfe4e73e 100644 (file)
@@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/iobuf.h>
 #include <ipxe/netdevice.h>
 #include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
 #include <ipxe/vsprintf.h>
 #include <ipxe/timer.h>
 #include <ipxe/efi/efi.h>
@@ -187,6 +188,12 @@ static int snpnet_transmit ( struct net_device *netdev,
                return 0;
        }
 
+       /* Pad to minimum Ethernet length, to work around underlying
+        * drivers that do not correctly handle frame padding
+        * themselves.
+        */
+       iob_pad ( iobuf, ETH_ZLEN );
+
        /* Transmit packet */
        if ( ( efirc = snp->snp->Transmit ( snp->snp, 0, iob_len ( iobuf ),
                                            iobuf->data, NULL, NULL,