Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle network file not found like disks #695

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion httpboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,51 @@ convert_http_status_code (EFI_HTTP_STATUS_CODE status_code)
return 0;
}

/* Convert an HTTP status code to an EFI status code. */
static EFI_STATUS
efi_status_from_http_status(EFI_HTTP_STATUS_CODE status_code)
{
switch (status_code) {
case HTTP_STATUS_400_BAD_REQUEST:
case HTTP_STATUS_411_LENGTH_REQUIRED:
case HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE:
case HTTP_STATUS_414_REQUEST_URI_TOO_LARGE:
case HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE:
case HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED:
case HTTP_STATUS_417_EXPECTATION_FAILED:
return EFI_INVALID_PARAMETER;
case HTTP_STATUS_401_UNAUTHORIZED:
case HTTP_STATUS_402_PAYMENT_REQUIRED:
case HTTP_STATUS_403_FORBIDDEN:
case HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED:
return EFI_ACCESS_DENIED;
case HTTP_STATUS_404_NOT_FOUND:
case HTTP_STATUS_410_GONE:
return EFI_NOT_FOUND;
case HTTP_STATUS_405_METHOD_NOT_ALLOWED:
case HTTP_STATUS_501_NOT_IMPLEMENTED:
return EFI_UNSUPPORTED;
case HTTP_STATUS_406_NOT_ACCEPTABLE:
return EFI_NO_MEDIA;
case HTTP_STATUS_408_REQUEST_TIME_OUT:
case HTTP_STATUS_504_GATEWAY_TIME_OUT:
return EFI_TIMEOUT;
case HTTP_STATUS_409_CONFLICT:
case HTTP_STATUS_412_PRECONDITION_FAILED:
return EFI_MEDIA_CHANGED;
case HTTP_STATUS_500_INTERNAL_SERVER_ERROR:
case HTTP_STATUS_502_BAD_GATEWAY:
return EFI_DEVICE_ERROR;
case HTTP_STATUS_503_SERVICE_UNAVAILABLE:
return EFI_NOT_READY;
case HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED:
return EFI_INCOMPATIBLE_VERSION;
default:
/* Use a generic HTTP error for anything else. */
return EFI_HTTP_ERROR;
}
}

static EFI_DEVICE_PATH *devpath;
static EFI_MAC_ADDRESS mac_addr;
static IPv4_DEVICE_PATH ip4_node;
Expand Down Expand Up @@ -565,7 +610,7 @@ receive_http_response(EFI_HTTP_PROTOCOL *http, VOID **buffer, UINT64 *buf_size)
if (http_status != HTTP_STATUS_200_OK) {
perror(L"HTTP Status Code: %d\n",
convert_http_status_code(http_status));
efi_status = EFI_ABORTED;
efi_status = efi_status_from_http_status(http_status);
goto error;
}

Expand Down
3 changes: 3 additions & 0 deletions include/errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@
#ifndef EFI_SECURITY_VIOLATION
#define EFI_SECURITY_VIOLATION EFIERR(26)
#endif
#ifndef EFI_HTTP_ERROR
#define EFI_HTTP_ERROR EFIERR(35)
#endif

#endif /* SHIM_ERRORS_H */
1 change: 1 addition & 0 deletions lib/console.c
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,7 @@ static struct {
{ EFI_PROTOCOL_ERROR, L"Protocol Error"},
{ EFI_INCOMPATIBLE_VERSION, L"Incompatible Version"},
{ EFI_SECURITY_VIOLATION, L"Security Violation"},
{ EFI_HTTP_ERROR, L"HTTP Error"},

// warnings
{ EFI_WARN_UNKNOWN_GLYPH, L"Warning Unknown Glyph"},
Expand Down
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;
}