Skip to content

Feature Request: Option to suppress 'tsize' in OACK (workaround for buggy UEFI PXE clients) #125

@aktive

Description

@aktive

Hi Dmitri,

First off, thanks for pin/tftp - it's been great for building a PXE boot server. We're using it to serve iPXE binaries (~1.1MB) to UEFI clients during network boot.

We've hit a specific issue with UEFI firmware TFTP implementations (Aptio V/AMI) that we're hoping you might have insight on.

Environment

  • Library: pin/tftp v3.1.0
  • Clients: Multiple UEFI clients (Gigabyte Aero 15XV8 Laptop/Aptio 2019, Lenovo m715q-1, brand new ASUS Prime B760M-A AX LGA 1700 w BIOS Ver / Date: 1812 x64 / 01/21/2025) - all exhibit identical behavior.

The Issue

UEFI TFTP clients send an RRQ with tsize=0 and blksize=1468.

  1. If the server responds with an OACK containing tsize=<actual_size>, the client immediately sends ERROR code 8 ("User aborted") and disconnects.
  2. The client then retries the request without the tsize option.
  3. The server responds with an OACK (only blksize), and the transfer succeeds.

It appears these UEFI stacks request tsize but panic/crash if they actually receive it (perhaps due to buffer allocation logic in the firmware).

Workaround Attempts

  1. Wrapped Reader: We wrapped our file in a struct that hides io.Seeker (exposing only io.Reader). We expected this to cause the library to omit tsize.
    • Result: The OACK correctly omitted tsize, but the client failed with "NBP filesize is 0 bytes" and did not retry. It seems these clients interpret "no tsize response to a tsize request" as "0 bytes".
  2. Current Solution: We are currently accepting the "Fail-then-Retry" behavior. It works, but the initial failure creates noise in our error logs (WARN) and adds a ~1-2s delay to the boot process.

Investigation

I noticed in sender.go that tsize is automatically added to the options if the Reader implements Size() or Seek().

Feature Request

Would it be possible to add a hook or option to explicitly suppress tsize from the OACK, even if the Reader supports it?

Something like:

rf.(tftp.OutgoingTransfer).SuppressTSize()

This would allow servers to negotiate blksize (for speed) while hiding tsize (to prevent UEFI crashes) without breaking the Reader interface needed for efficient retransmits.

Packet Capture Evidence

Request 1 (Fail):

Client: RRQ "file.efi" tsize=0 blksize=1468
Server: OACK tsize=1125376 blksize=1468
Client: ERROR code=8 (User Aborted)

Request 2 (Success):

Client: RRQ "file.efi" blksize=1468
Server: OACK blksize=1468
Client: ACK (Transfer begins)

Happy to provide packet captures or test builds if needed. Thanks for your time!

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions