Line data Source code
1 : /**
2 : * Copyright Notice:
3 : * Copyright 2021-2024 DMTF. All rights reserved.
4 : * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md
5 : **/
6 :
7 : #include "internal/libspdm_requester_lib.h"
8 :
9 : #pragma pack(1)
10 : typedef struct {
11 : spdm_message_header_t header;
12 : uint8_t dummy_data[sizeof(spdm_error_data_response_not_ready_t)];
13 : } libspdm_heartbeat_response_mine_t;
14 : #pragma pack()
15 :
16 : /**
17 : * This function sends HEARTBEAT to an SPDM Session.
18 : *
19 : * @param spdm_context A pointer to the SPDM context.
20 : * @param session_id The session ID of the session.
21 : *
22 : **/
23 31 : static libspdm_return_t libspdm_try_heartbeat(libspdm_context_t *spdm_context, uint32_t session_id)
24 : {
25 : libspdm_return_t status;
26 : spdm_heartbeat_request_t *spdm_request;
27 : size_t spdm_request_size;
28 : libspdm_heartbeat_response_mine_t *spdm_response;
29 : size_t spdm_response_size;
30 : libspdm_session_info_t *session_info;
31 : libspdm_session_state_t session_state;
32 : uint8_t *message;
33 : size_t message_size;
34 : size_t transport_header_size;
35 :
36 : /* -=[Check Parameters Phase]=- */
37 31 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) {
38 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
39 : }
40 :
41 31 : session_info = libspdm_get_session_info_via_session_id(spdm_context, session_id);
42 31 : if (session_info == NULL) {
43 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
44 : }
45 :
46 : /* -=[Verify State Phase]=- */
47 31 : if (!libspdm_is_capabilities_flag_supported(
48 : spdm_context, true,
49 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HBEAT_CAP,
50 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HBEAT_CAP)) {
51 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
52 : }
53 31 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
54 1 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
55 : }
56 30 : session_state = libspdm_secured_message_get_session_state(
57 : session_info->secured_message_context);
58 30 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
59 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
60 : }
61 30 : if (session_info->heartbeat_period == 0) {
62 1 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
63 : }
64 :
65 : /* -=[Construct Request Phase]=- */
66 29 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
67 29 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
68 29 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
69 0 : return status;
70 : }
71 29 : LIBSPDM_ASSERT (message_size >= transport_header_size +
72 : spdm_context->local_context.capability.transport_tail_size);
73 29 : spdm_request = (void *)(message + transport_header_size);
74 29 : spdm_request_size = message_size - transport_header_size -
75 29 : spdm_context->local_context.capability.transport_tail_size;
76 :
77 29 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_heartbeat_request_t));
78 29 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
79 29 : spdm_request->header.request_response_code = SPDM_HEARTBEAT;
80 29 : spdm_request->header.param1 = 0;
81 29 : spdm_request->header.param2 = 0;
82 29 : spdm_request_size = sizeof(spdm_heartbeat_request_t);
83 :
84 : /* -=[Send Request Phase]=- */
85 29 : status = libspdm_send_spdm_request(spdm_context, &session_id, spdm_request_size, spdm_request);
86 29 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
87 1 : libspdm_release_sender_buffer (spdm_context);
88 1 : return status;
89 : }
90 28 : libspdm_release_sender_buffer (spdm_context);
91 28 : spdm_request = (void *)spdm_context->last_spdm_request;
92 :
93 28 : libspdm_reset_message_buffer_via_request_code(spdm_context, session_info, SPDM_HEARTBEAT);
94 :
95 : /* -=[Receive Response Phase]=- */
96 28 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
97 28 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
98 0 : return status;
99 : }
100 28 : LIBSPDM_ASSERT (message_size >= transport_header_size);
101 28 : spdm_response = (void *)(message);
102 28 : spdm_response_size = message_size;
103 :
104 28 : status = libspdm_receive_spdm_response(
105 : spdm_context, &session_id, &spdm_response_size, (void **)&spdm_response);
106 28 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
107 0 : goto receive_done;
108 : }
109 :
110 : /* -=[Validate Response Phase]=- */
111 28 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
112 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
113 0 : goto receive_done;
114 : }
115 28 : if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
116 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
117 0 : goto receive_done;
118 : }
119 28 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
120 25 : status = libspdm_handle_error_response_main(
121 : spdm_context, &session_id, &spdm_response_size,
122 : (void **)&spdm_response, SPDM_HEARTBEAT, SPDM_HEARTBEAT_ACK);
123 25 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
124 24 : goto receive_done;
125 : }
126 3 : } else if (spdm_response->header.request_response_code != SPDM_HEARTBEAT_ACK) {
127 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
128 0 : goto receive_done;
129 : }
130 : /* this message can only be in secured session
131 : * thus don't need to consider transport layer padding, just check its exact size */
132 4 : if (spdm_response_size != sizeof(spdm_heartbeat_response_t)) {
133 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
134 0 : goto receive_done;
135 : }
136 :
137 : /* -=[Log Message Phase]=- */
138 : #if LIBSPDM_ENABLE_MSG_LOG
139 4 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
140 : #endif /* LIBSPDM_ENABLE_MSG_LOG */
141 :
142 4 : status = LIBSPDM_STATUS_SUCCESS;
143 :
144 28 : receive_done:
145 28 : libspdm_release_receiver_buffer (spdm_context);
146 28 : return status;
147 : }
148 :
149 30 : libspdm_return_t libspdm_heartbeat(void *spdm_context, uint32_t session_id)
150 : {
151 : size_t retry;
152 : uint64_t retry_delay_time;
153 : libspdm_return_t status;
154 : libspdm_context_t *context;
155 :
156 30 : context = spdm_context;
157 30 : context->crypto_request = true;
158 30 : retry = context->retry_times;
159 30 : retry_delay_time = context->retry_delay_time;
160 : do {
161 31 : status = libspdm_try_heartbeat(context, session_id);
162 31 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
163 29 : return status;
164 : }
165 :
166 2 : libspdm_sleep(retry_delay_time);
167 2 : } while (retry-- != 0);
168 :
169 1 : return status;
170 : }
|