diff --git a/protocol/authz_record_test.cc b/protocol/authz_record_test.cc index c46b5e3..cb3218a 100644 --- a/protocol/authz_record_test.cc +++ b/protocol/authz_record_test.cc @@ -49,7 +49,7 @@ TEST_F(LibHothTest, authz_erase_test) { .WillOnce(DoAll(CopyResp(&dummy, 0), Return(LIBHOTH_ERR_TIMEOUT))); EXPECT_EQ(libhoth_authz_record_erase(&hoth_dev_), - LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_NONE, HOTH_HOST_SPACE_LIBHOTH, LIBHOTH_ERR_TIMEOUT)); } diff --git a/protocol/host_cmd.c b/protocol/host_cmd.c index 7eda0c1..5b55008 100644 --- a/protocol/host_cmd.c +++ b/protocol/host_cmd.c @@ -224,11 +224,12 @@ libhoth_error libhoth_hostcmd_exec_v2(struct libhoth_device* dev, return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_POSIX, -status); } - status = libhoth_send_request(dev, &req, sizeof(req.hdr) + req_payload_size); - if (status != LIBHOTH_OK) { - fprintf(stderr, "libhoth_send_request() failed: %d\n", status); - return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, - status); + libhoth_error err = + libhoth_send_request_v2(dev, &req, sizeof(req.hdr) + req_payload_size); + if (err != HOTH_SUCCESS) { + fprintf(stderr, "libhoth_send_request_v2() failed: 0x%016llx\n", + (unsigned long long)err); + return err; } struct { struct hoth_host_response hdr; @@ -236,12 +237,12 @@ libhoth_error libhoth_hostcmd_exec_v2(struct libhoth_device* dev, payload_buf[LIBHOTH_MAILBOX_SIZE - sizeof(struct hoth_host_response)]; } resp; size_t resp_size = 0; - status = libhoth_receive_response(dev, &resp, sizeof(resp), &resp_size, + err = libhoth_receive_response_v2(dev, &resp, sizeof(resp), &resp_size, HOTH_CMD_TIMEOUT_MS_DEFAULT); - if (status != LIBHOTH_OK) { - fprintf(stderr, "libhoth_receive_response() failed: %d\n", status); - return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, - status); + if (err != HOTH_SUCCESS) { + fprintf(stderr, "libhoth_receive_response_v2() failed: 0x%016llx\n", + (unsigned long long)err); + return err; } status = validate_ec_response_header(&resp.hdr, resp.payload_buf, resp_size); if (status != 0) { diff --git a/protocol/test/libhoth_device_mock.cc b/protocol/test/libhoth_device_mock.cc index ed17d63..b45e62f 100644 --- a/protocol/test/libhoth_device_mock.cc +++ b/protocol/test/libhoth_device_mock.cc @@ -20,6 +20,7 @@ static int reconnect(struct libhoth_device* dev) { } LibHothTest::LibHothTest() { + std::memset(&hoth_dev_, 0, sizeof(hoth_dev_)); hoth_dev_.user_ctx = &mock_; hoth_dev_.send = send; hoth_dev_.receive = receive; diff --git a/transports/BUILD b/transports/BUILD index 6915bc7..9424ef1 100644 --- a/transports/BUILD +++ b/transports/BUILD @@ -6,6 +6,9 @@ cc_library( name = "libhoth_device", srcs = ["libhoth_device.c"], hdrs = ["libhoth_device.h"], + deps = [ + "//protocol:libhoth_status", + ], ) cc_library( diff --git a/transports/libhoth_device.c b/transports/libhoth_device.c index 7a56c3f..a5a8b19 100644 --- a/transports/libhoth_device.c +++ b/transports/libhoth_device.c @@ -21,12 +21,46 @@ #include "libhoth_device.h" +static libhoth_error libhoth_error_from_legacy(uint16_t context, int status) { + if (status == 0) { + return HOTH_SUCCESS; + } + if (status < 0) { + return LIBHOTH_ERR_CONSTRUCT(context, HOTH_HOST_SPACE_POSIX, -status); + } + return LIBHOTH_ERR_CONSTRUCT(context, HOTH_HOST_SPACE_LIBHOTH, + (uint32_t)status); +} + +static int libhoth_error_to_legacy(libhoth_error err) { + if (err == HOTH_SUCCESS) { + return 0; + } + uint32_t space = LIBHOTH_ERR_GET_SPACE(err); + uint32_t code = LIBHOTH_ERR_GET_CODE(err); + + if (space == HOTH_HOST_SPACE_LIBHOTH) { + return (int)code; + } + if (space == HOTH_HOST_SPACE_POSIX || space == HOTH_HOST_SPACE_LIBUSB) { + return -(int)code; + } + return LIBHOTH_ERR_FAIL; +} + int libhoth_send_request(struct libhoth_device* dev, const void* request, size_t request_size) { if (dev == NULL) { return LIBHOTH_ERR_INVALID_PARAMETER; } - return dev->send(dev, request, request_size); + if (dev->send != NULL) { + return dev->send(dev, request, request_size); + } + if (dev->send_v2 != NULL) { + libhoth_error err = dev->send_v2(dev, request, request_size); + return libhoth_error_to_legacy(err); + } + return LIBHOTH_ERR_FAIL; } int libhoth_receive_response(struct libhoth_device* dev, void* response, @@ -35,36 +69,150 @@ int libhoth_receive_response(struct libhoth_device* dev, void* response, if (dev == NULL) { return LIBHOTH_ERR_INVALID_PARAMETER; } - return dev->receive(dev, response, max_response_size, actual_size, - timeout_ms); + if (dev->receive != NULL) { + return dev->receive(dev, response, max_response_size, actual_size, + timeout_ms); + } + if (dev->receive_v2 != NULL) { + libhoth_error err = dev->receive_v2(dev, response, max_response_size, + actual_size, timeout_ms); + return libhoth_error_to_legacy(err); + } + return LIBHOTH_ERR_FAIL; } -int libhoth_device_reconnect(struct libhoth_device* dev) { +libhoth_error libhoth_send_request_v2(struct libhoth_device* dev, + const void* request, + size_t request_size) { if (dev == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_INVALID_PARAMETER); + } + if (dev->send_v2 != NULL) { + return dev->send_v2(dev, request, request_size); + } + if (dev->send != NULL) { + int status = dev->send(dev, request, request_size); + return libhoth_error_from_legacy(HOTH_CTX_NONE, status); } + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_FAIL); +} - if (dev->reconnect == NULL) { - return LIBHOTH_ERR_UNSUPPORTED_VERSION; +libhoth_error libhoth_receive_response_v2(struct libhoth_device* dev, + void* response, + size_t max_response_size, + size_t* actual_size, int timeout_ms) { + if (dev == NULL) { + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_INVALID_PARAMETER); } + if (dev->receive_v2 != NULL) { + return dev->receive_v2(dev, response, max_response_size, actual_size, + timeout_ms); + } + if (dev->receive != NULL) { + int status = + dev->receive(dev, response, max_response_size, actual_size, timeout_ms); + return libhoth_error_from_legacy(HOTH_CTX_NONE, status); + } + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_FAIL); +} - return dev->reconnect(dev); +int libhoth_device_reconnect(struct libhoth_device* dev) { + if (dev == NULL) { + return LIBHOTH_ERR_INVALID_PARAMETER; + } + if (dev->reconnect != NULL) { + return dev->reconnect(dev); + } + if (dev->reconnect_v2 != NULL) { + libhoth_error err = dev->reconnect_v2(dev); + return libhoth_error_to_legacy(err); + } + return LIBHOTH_ERR_UNSUPPORTED_VERSION; } int libhoth_device_close(struct libhoth_device* dev) { if (dev == NULL) { return LIBHOTH_ERR_INVALID_PARAMETER; } - - int status = dev->close(dev); + int status = 0; + if (dev->close != NULL) { + status = dev->close(dev); + } else if (dev->close_v2 != NULL) { + libhoth_error err = dev->close_v2(dev); + status = libhoth_error_to_legacy(err); + } else { + status = LIBHOTH_ERR_FAIL; + } free(dev); return status; } +libhoth_error libhoth_device_reconnect_v2(struct libhoth_device* dev) { + if (dev == NULL) { + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_INVALID_PARAMETER); + } + if (dev->reconnect_v2 != NULL) { + return dev->reconnect_v2(dev); + } + if (dev->reconnect != NULL) { + int status = dev->reconnect(dev); + return libhoth_error_from_legacy(HOTH_CTX_NONE, status); + } + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_UNSUPPORTED_VERSION); +} + +libhoth_error libhoth_device_close_v2(struct libhoth_device* dev) { + if (dev == NULL) { + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_INVALID_PARAMETER); + } + libhoth_error err = HOTH_SUCCESS; + if (dev->close_v2 != NULL) { + err = dev->close_v2(dev); + } else if (dev->close != NULL) { + int status = dev->close(dev); + err = libhoth_error_from_legacy(HOTH_CTX_NONE, status); + } + free(dev); + return err; +} + int libhoth_claim_device(struct libhoth_device* dev, uint32_t timeout_us) { + if (dev == NULL) { + return LIBHOTH_ERR_INVALID_PARAMETER; + } + libhoth_error err = libhoth_claim_device_v2(dev, timeout_us); + return libhoth_error_to_legacy(err); +} + +int libhoth_release_device(struct libhoth_device* dev) { + if (dev == NULL) { + return LIBHOTH_ERR_INVALID_PARAMETER; + } + if (dev->release != NULL) { + return dev->release(dev); + } + if (dev->release_v2 != NULL) { + libhoth_error err = dev->release_v2(dev); + return libhoth_error_to_legacy(err); + } + return LIBHOTH_ERR_FAIL; +} + +libhoth_error libhoth_claim_device_v2(struct libhoth_device* dev, + uint32_t timeout_us) { + if (dev == NULL) { + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_INVALID_PARAMETER); + } + enum { - // The maximum time to sleep per attempt. - // Limited by `usleep()` to <1 second. MAX_SINGLE_SLEEP_US = 1000 * 1000 - 1, BACKOFF_FACTOR = 2, INITIAL_WAIT_US = 10 * 1000, @@ -74,20 +222,29 @@ int libhoth_claim_device(struct libhoth_device* dev, uint32_t timeout_us) { uint32_t total_waiting_us = 0; while (true) { - int status = dev->claim(dev); + libhoth_error err = HOTH_SUCCESS; + if (dev->claim_v2 != NULL) { + err = dev->claim_v2(dev); + } else if (dev->claim != NULL) { + int status = dev->claim(dev); + err = libhoth_error_from_legacy(HOTH_CTX_NONE, status); + } else { + err = LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_FAIL); + } - if (status != LIBHOTH_ERR_INTERFACE_BUSY) { - // We either claimed the device or encountered an unexpected error. Let - // the caller know. - return status; + uint32_t space = LIBHOTH_ERR_GET_SPACE(err); + uint32_t code = LIBHOTH_ERR_GET_CODE(err); + if (err == HOTH_SUCCESS || space != HOTH_HOST_SPACE_LIBHOTH || + code != LIBHOTH_ERR_INTERFACE_BUSY) { + return err; } if (total_waiting_us >= timeout_us) { - // We've exhausted our waiting budget. We couldn't claim the device - // within the configured timeout. fprintf(stderr, "libhoth: timed out claiming transport after %dus\n", timeout_us); - return LIBHOTH_ERR_INTERFACE_BUSY; + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_INTERFACE_BUSY); } usleep(wait_us); @@ -95,22 +252,32 @@ int libhoth_claim_device(struct libhoth_device* dev, uint32_t timeout_us) { if (total_waiting_us <= UINT32_MAX - wait_us) { total_waiting_us += wait_us; } else { - // Saturate at integer upper bound to prevent overflow. total_waiting_us = UINT32_MAX; } if (wait_us <= MAX_SINGLE_SLEEP_US / BACKOFF_FACTOR) { wait_us *= BACKOFF_FACTOR; } else { - // Saturate at the `usleep()` max sleep bound. wait_us = MAX_SINGLE_SLEEP_US; } } - // Unreachable - return LIBHOTH_ERR_FAIL; + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_FAIL); } -int libhoth_release_device(struct libhoth_device* dev) { - return dev->release(dev); +libhoth_error libhoth_release_device_v2(struct libhoth_device* dev) { + if (dev == NULL) { + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_INVALID_PARAMETER); + } + if (dev->release_v2 != NULL) { + return dev->release_v2(dev); + } + if (dev->release != NULL) { + int status = dev->release(dev); + return libhoth_error_from_legacy(HOTH_CTX_NONE, status); + } + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_FAIL); } diff --git a/transports/libhoth_device.h b/transports/libhoth_device.h index d15585c..9b52fa5 100644 --- a/transports/libhoth_device.h +++ b/transports/libhoth_device.h @@ -18,6 +18,8 @@ #include #include +#include "protocol/status.h" + #ifdef __cplusplus extern "C" { #endif @@ -53,6 +55,17 @@ struct libhoth_device { int (*reconnect)(struct libhoth_device* dev); void* user_ctx; + + // --- New Interface (V2) --- + libhoth_error (*send_v2)(struct libhoth_device* dev, const void* request, + size_t request_size); + libhoth_error (*receive_v2)(struct libhoth_device* dev, void* response, + size_t max_response_size, size_t* actual_size, + int timeout_ms); + libhoth_error (*close_v2)(struct libhoth_device* dev); + libhoth_error (*claim_v2)(struct libhoth_device* dev); + libhoth_error (*release_v2)(struct libhoth_device* dev); + libhoth_error (*reconnect_v2)(struct libhoth_device* dev); }; // Request is a buffer containing the EC request header and trailing payload. @@ -84,6 +97,24 @@ int libhoth_claim_device(struct libhoth_device* dev, uint32_t timeout_us); int libhoth_release_device(struct libhoth_device* dev); +// --- New V2 Helper Functions --- +libhoth_error libhoth_send_request_v2(struct libhoth_device* dev, + const void* request, size_t request_size); + +libhoth_error libhoth_receive_response_v2(struct libhoth_device* dev, + void* response, + size_t max_response_size, + size_t* actual_size, int timeout_ms); + +libhoth_error libhoth_device_reconnect_v2(struct libhoth_device* dev); + +libhoth_error libhoth_device_close_v2(struct libhoth_device* dev); + +libhoth_error libhoth_claim_device_v2(struct libhoth_device* dev, + uint32_t timeout_us); + +libhoth_error libhoth_release_device_v2(struct libhoth_device* dev); + #ifdef __cplusplus } #endif