LCOV - code coverage report
Current view: top level - library/spdm_requester_lib - libspdm_req_get_version.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 85.8 % 113 97
Test Date: 2025-06-29 08:09:00 Functions: 100.0 % 2 2

            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 reserved;
      13              :     uint8_t version_number_entry_count;
      14              :     spdm_version_number_t version_number_entry[LIBSPDM_MAX_VERSION_COUNT];
      15              : } libspdm_version_response_max_t;
      16              : #pragma pack()
      17              : 
      18              : /**
      19              :  * This function sends GET_VERSION and receives VERSION.
      20              :  *
      21              :  * @param  spdm_context         A pointer to the SPDM context.
      22              :  * @param  version_count        The number of SPDM versions that the Responder supports.
      23              :  * @param  VersionNumberEntries The list of SPDM versions that the Responder supports.
      24              :  *
      25              :  * @retval LIBSPDM_STATUS_SUCCESS
      26              :  *         GET_VERSION was sent and VERSION was received.
      27              :  * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE
      28              :  *         The size of the VERSION response is invalid.
      29              :  * @retval LIBSPDM_STATUS_INVALID_MSG_FIELD
      30              :  *         The VERSION response contains one or more invalid fields.
      31              :  * @retval LIBSPDM_STATUS_ERROR_PEER
      32              :  *         The Responder returned an unexpected error.
      33              :  * @retval LIBSPDM_STATUS_BUSY_PEER
      34              :  *         The Responder continually returned Busy error messages.
      35              :  * @retval LIBSPDM_STATUS_RESYNCH_PEER
      36              :  *         The Responder returned a RequestResynch error message.
      37              :  * @retval LIBSPDM_STATUS_NEGOTIATION_FAIL
      38              :  *         The Requester and Responder do not support a common SPDM version.
      39              :  **/
      40           39 : static libspdm_return_t libspdm_try_get_version(libspdm_context_t *spdm_context,
      41              :                                                 uint8_t *version_number_entry_count,
      42              :                                                 spdm_version_number_t *version_number_entry)
      43              : {
      44              :     libspdm_return_t status;
      45              :     bool result;
      46              :     spdm_get_version_request_t *spdm_request;
      47              :     size_t spdm_request_size;
      48              :     libspdm_version_response_max_t *spdm_response;
      49              :     size_t spdm_response_size;
      50              :     spdm_version_number_t common_version;
      51              :     uint8_t *message;
      52              :     size_t message_size;
      53              :     size_t transport_header_size;
      54              : 
      55              :     /* -=[Set State Phase]=- */
      56           39 :     libspdm_reset_message_a(spdm_context);
      57           39 :     libspdm_reset_message_d(spdm_context);
      58           39 :     libspdm_reset_message_b(spdm_context);
      59           39 :     libspdm_reset_message_c(spdm_context);
      60           39 :     libspdm_reset_context(spdm_context);
      61           39 :     libspdm_reset_message_buffer_via_request_code(spdm_context, NULL, SPDM_GET_VERSION);
      62              : 
      63              :     /* -=[Construct Request Phase]=- */
      64           39 :     transport_header_size = spdm_context->local_context.capability.transport_header_size;
      65           39 :     status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
      66           39 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
      67            1 :         return status;
      68              :     }
      69           38 :     LIBSPDM_ASSERT (message_size >= transport_header_size +
      70              :                     spdm_context->local_context.capability.transport_tail_size);
      71           38 :     spdm_request = (void *)(message + transport_header_size);
      72           38 :     spdm_request_size = message_size - transport_header_size -
      73           38 :                         spdm_context->local_context.capability.transport_tail_size;
      74              : 
      75           38 :     LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_get_version_request_t));
      76           38 :     spdm_request->header.spdm_version = SPDM_MESSAGE_VERSION_10;
      77           38 :     spdm_request->header.request_response_code = SPDM_GET_VERSION;
      78           38 :     spdm_request->header.param1 = 0;
      79           38 :     spdm_request->header.param2 = 0;
      80           38 :     spdm_request_size = sizeof(spdm_get_version_request_t);
      81              : 
      82              :     /* -=[Send Request Phase]=- */
      83           38 :     status = libspdm_send_spdm_request(spdm_context, NULL, spdm_request_size, spdm_request);
      84           38 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
      85            1 :         libspdm_release_sender_buffer (spdm_context);
      86            1 :         return status;
      87              :     }
      88           37 :     libspdm_release_sender_buffer (spdm_context);
      89           37 :     spdm_request = (void *)spdm_context->last_spdm_request;
      90              : 
      91              :     /* -=[Receive Response Phase]=- */
      92           37 :     status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
      93           37 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
      94            1 :         return status;
      95              :     }
      96           36 :     LIBSPDM_ASSERT (message_size >= transport_header_size);
      97           36 :     spdm_response = (void *)(message);
      98           36 :     spdm_response_size = message_size;
      99              : 
     100           36 :     status = libspdm_receive_spdm_response(spdm_context, NULL, &spdm_response_size,
     101              :                                            (void **)&spdm_response);
     102           36 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     103            1 :         goto receive_done;
     104              :     }
     105              : 
     106              :     /* -=[Validate Response Phase]=- */
     107           35 :     if (spdm_response_size < sizeof(spdm_message_header_t)) {
     108            0 :         status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     109            0 :         goto receive_done;
     110              :     }
     111           35 :     if (spdm_response->header.spdm_version != SPDM_MESSAGE_VERSION_10) {
     112            1 :         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     113            1 :         goto receive_done;
     114              :     }
     115           34 :     if (spdm_response->header.request_response_code == SPDM_ERROR) {
     116              :         /* Responder shall not respond to the GET_VERSION request message with ErrorCode=ResponseNotReady.*/
     117           23 :         if (spdm_response->header.param1 == SPDM_ERROR_CODE_RESPONSE_NOT_READY) {
     118              :             /* Received an unexpected error message. */
     119            1 :             status = LIBSPDM_STATUS_ERROR_PEER;
     120            1 :             goto receive_done;
     121              :         }
     122           22 :         status = libspdm_handle_simple_error_response(spdm_context, spdm_response->header.param1);
     123           22 :         if (LIBSPDM_STATUS_IS_ERROR(status)) {
     124           22 :             goto receive_done;
     125              :         }
     126           11 :     } else if (spdm_response->header.request_response_code != SPDM_VERSION) {
     127            1 :         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     128            1 :         goto receive_done;
     129              :     }
     130           10 :     if (spdm_response_size < sizeof(spdm_version_response_t)) {
     131            1 :         status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     132            1 :         goto receive_done;
     133              :     }
     134            9 :     if (spdm_response->version_number_entry_count > LIBSPDM_MAX_VERSION_COUNT) {
     135            1 :         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     136            1 :         goto receive_done;
     137              :     }
     138            8 :     if (spdm_response->version_number_entry_count == 0) {
     139            1 :         status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     140            1 :         goto receive_done;
     141              :     }
     142            7 :     if (spdm_response_size < sizeof(spdm_version_response_t) +
     143            7 :         spdm_response->version_number_entry_count * sizeof(spdm_version_number_t)) {
     144            1 :         status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
     145            1 :         goto receive_done;
     146              :     }
     147            6 :     spdm_response_size = sizeof(spdm_version_response_t) +
     148            6 :                          spdm_response->version_number_entry_count * sizeof(spdm_version_number_t);
     149              : 
     150              :     /* -=[Process Response Phase]=- */
     151            6 :     status = libspdm_append_message_a(spdm_context, spdm_request, spdm_request_size);
     152            6 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     153            0 :         goto receive_done;
     154              :     }
     155              : 
     156            6 :     status = libspdm_append_message_a(spdm_context, spdm_response, spdm_response_size);
     157            6 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     158            0 :         libspdm_reset_message_a(spdm_context);
     159            0 :         goto receive_done;
     160              :     }
     161              : 
     162            6 :     result = libspdm_negotiate_connection_version (
     163              :         &common_version,
     164            6 :         spdm_context->local_context.version.spdm_version,
     165            6 :         spdm_context->local_context.version.spdm_version_count,
     166            6 :         spdm_response->version_number_entry,
     167            6 :         spdm_response->version_number_entry_count);
     168            6 :     if (result == false) {
     169            1 :         libspdm_reset_message_a(spdm_context);
     170            1 :         status = LIBSPDM_STATUS_NEGOTIATION_FAIL;
     171            1 :         goto receive_done;
     172              :     }
     173              : 
     174            5 :     libspdm_copy_mem(&(spdm_context->connection_info.version),
     175              :                      sizeof(spdm_context->connection_info.version),
     176              :                      &(common_version), sizeof(spdm_version_number_t));
     177              : 
     178            5 :     if (version_number_entry_count != NULL && version_number_entry != NULL) {
     179            0 :         if (*version_number_entry_count < spdm_response->version_number_entry_count) {
     180            0 :             *version_number_entry_count = spdm_response->version_number_entry_count;
     181            0 :             libspdm_reset_message_a(spdm_context);
     182            0 :             status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
     183            0 :             goto receive_done;
     184              :         } else {
     185            0 :             *version_number_entry_count = spdm_response->version_number_entry_count;
     186            0 :             libspdm_copy_mem(version_number_entry,
     187            0 :                              spdm_response->version_number_entry_count *
     188              :                              sizeof(spdm_version_number_t),
     189            0 :                              spdm_response->version_number_entry,
     190            0 :                              spdm_response->version_number_entry_count *
     191              :                              sizeof(spdm_version_number_t));
     192            0 :             libspdm_version_number_sort (version_number_entry, *version_number_entry_count);
     193              :         }
     194              :     }
     195              : 
     196              :     /* -=[Update State Phase]=- */
     197            5 :     spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_AFTER_VERSION;
     198            5 :     status = LIBSPDM_STATUS_SUCCESS;
     199              : 
     200              :     /* -=[Log Message Phase]=- */
     201              :     #if LIBSPDM_ENABLE_MSG_LOG
     202            5 :     libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
     203              :     #endif /* LIBSPDM_ENABLE_MSG_LOG */
     204              : 
     205              :     /*Set the role of device*/
     206            5 :     spdm_context->local_context.is_requester = true;
     207              : 
     208           36 : receive_done:
     209           36 :     libspdm_release_receiver_buffer (spdm_context);
     210           36 :     return status;
     211              : }
     212              : 
     213           38 : libspdm_return_t libspdm_get_version(libspdm_context_t *spdm_context,
     214              :                                      uint8_t *version_number_entry_count,
     215              :                                      spdm_version_number_t *version_number_entry)
     216              : {
     217              :     size_t retry;
     218              :     uint64_t retry_delay_time;
     219              :     libspdm_return_t status;
     220              : 
     221           38 :     spdm_context->crypto_request = false;
     222           38 :     retry = spdm_context->retry_times;
     223           38 :     retry_delay_time = spdm_context->retry_delay_time;
     224              :     do {
     225           39 :         status = libspdm_try_get_version(spdm_context,
     226              :                                          version_number_entry_count, version_number_entry);
     227           39 :         if (status != LIBSPDM_STATUS_BUSY_PEER) {
     228           37 :             return status;
     229              :         }
     230              : 
     231            2 :         libspdm_sleep(retry_delay_time);
     232            2 :     } while (retry-- != 0);
     233              : 
     234            1 :     return status;
     235              : }
        

Generated by: LCOV version 2.0-1