Skip to content

Commit

Permalink
netboot: Convert TFTP error codes to EFI status codes
Browse files Browse the repository at this point in the history
This allows the caller to make a more informed decision about how to
handle the error. The error code is available in the TftpError field of
the Mode interface. In particular, by mapping the TFTP errors to
EFI_INVALID_PARAMTER and EFI_NOT_FOUND, shim will try to fetch the
default second stage image like it does when loading images from disk.

Unfortunately, some firmware doesn't fill in the error fields, so a
generic EFI_TFTP_ERROR to EFI_NOT_FOUND conversion is included.

Signed-off-by: Dan Nicholson <dbn@endlessos.org>
  • Loading branch information
dbnicholson committed Oct 4, 2024
1 parent 41623f7 commit 4fa0495
Showing 1 changed file with 57 additions and 2 deletions.
59 changes: 57 additions & 2 deletions netboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@
#define ntohs(x) __builtin_bswap16(x) /* supported both by GCC and clang */
#define htons(x) ntohs(x)

/* TFTP error codes from RFC 1350 */
#define TFTP_ERROR_NOT_DEFINED 0 /* Not defined, see error message (if any). */
#define TFTP_ERROR_NOT_FOUND 1 /* File not found. */
#define TFTP_ERROR_ACCESS 2 /* Access violation. */
#define TFTP_ERROR_NO_SPACE 3 /* Disk full or allocation exceeded. */
#define TFTP_ERROR_ILLEGAL_OP 4 /* Illegal TFTP operation. */
#define TFTP_ERROR_UNKNOWN_ID 5 /* Unknown transfer ID. */
#define TFTP_ERROR_EXISTS 6 /* File already exists. */
#define TFTP_ERROR_NO_USER 7 /* No such user. */

static EFI_PXE_BASE_CODE *pxe;
static EFI_IP_ADDRESS tftp_addr;
static CHAR8 *full_path;
Expand Down Expand Up @@ -333,6 +343,31 @@ EFI_STATUS parseNetbootinfo(EFI_HANDLE image_handle UNUSED, CHAR8 *netbootname)
return efi_status;
}

/* Convert a TFTP error code to an EFI status code. */
static EFI_STATUS
status_from_error(UINT8 error_code)
{
switch (error_code) {
case TFTP_ERROR_NOT_FOUND:
return EFI_NOT_FOUND;
case TFTP_ERROR_ACCESS:
case TFTP_ERROR_NO_USER:
return EFI_ACCESS_DENIED;
case TFTP_ERROR_NO_SPACE:
return EFI_VOLUME_FULL;
case TFTP_ERROR_ILLEGAL_OP:
return EFI_PROTOCOL_ERROR;
case TFTP_ERROR_UNKNOWN_ID:
return EFI_INVALID_PARAMETER;
case TFTP_ERROR_EXISTS:
return EFI_WRITE_PROTECTED;
case TFTP_ERROR_NOT_DEFINED:
default:
/* Use a generic TFTP error for anything else. */
return EFI_TFTP_ERROR;
}
}

EFI_STATUS FetchNetbootimage(EFI_HANDLE image_handle UNUSED, VOID **buffer, UINT64 *bufsiz)
{
EFI_STATUS efi_status;
Expand Down Expand Up @@ -362,8 +397,28 @@ EFI_STATUS FetchNetbootimage(EFI_HANDLE image_handle UNUSED, VOID **buffer, UINT
goto try_again;
}

if (EFI_ERROR(efi_status) && *buffer) {
FreePool(*buffer);
if (EFI_ERROR(efi_status)) {
if (pxe->Mode->TftpErrorReceived) {
console_print(L"TFTP error %u: %a\n",
pxe->Mode->TftpError.ErrorCode,
pxe->Mode->TftpError.ErrorString);

efi_status = status_from_error(pxe->Mode->TftpError.ErrorCode);
} else if (efi_status == EFI_TFTP_ERROR) {
/*
* Unfortunately, some firmware doesn't fill in the
* error details. Treat all TFTP errors like file not
* found so shim falls back to the default loader.
*
* https://github.com/tianocore/edk2/pull/6287
*/
console_print(L"Unknown TFTP error, treating as file not found\n");
efi_status = EFI_NOT_FOUND;
}

if (*buffer) {
FreePool(*buffer);
}
}
return efi_status;
}

0 comments on commit 4fa0495

Please sign in to comment.