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