LCOV - code coverage report
Current view: top level - library/spdm_responder_lib - libspdm_rsp_chunk_send_ack.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 89.7 % 126 113
Test Date: 2025-06-29 08:09:00 Functions: 100.0 % 1 1

            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_responder_lib.h"
       8              : 
       9              : #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
      10              : 
      11           23 : libspdm_return_t libspdm_get_response_chunk_send(libspdm_context_t *spdm_context,
      12              :                                                  size_t request_size,
      13              :                                                  const void *request,
      14              :                                                  size_t *response_size,
      15              :                                                  void *response)
      16              : {
      17              :     const spdm_chunk_send_request_t *spdm_request;
      18              :     spdm_chunk_send_ack_response_t *spdm_response;
      19              :     libspdm_chunk_info_t *send_info;
      20           23 :     libspdm_return_t status = LIBSPDM_STATUS_SUCCESS;
      21              :     const uint8_t *chunk;
      22              :     uint32_t large_message_size;
      23              :     uint32_t calc_max_chunk_size;
      24              :     uint8_t *scratch_buffer;
      25              :     size_t scratch_buffer_size;
      26              :     uint8_t* chunk_response;
      27              :     size_t chunk_response_size;
      28              :     uint64_t max_chunk_data_transfer_size;
      29              : 
      30           23 :     spdm_request = (const spdm_chunk_send_request_t*) request;
      31              : 
      32           23 :     if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_12) {
      33            0 :         return libspdm_generate_error_response(spdm_context,
      34              :                                                SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
      35              :                                                SPDM_CHUNK_SEND,
      36              :                                                response_size, response);
      37              :     }
      38              : 
      39           23 :     if (!libspdm_is_capabilities_flag_supported(
      40              :             spdm_context, false, SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP,
      41              :             SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP)) {
      42            1 :         return libspdm_generate_error_response(
      43              :             spdm_context,
      44              :             SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
      45              :             response_size, response);
      46              :     }
      47              : 
      48              :     /*chunk mechanism can be used for normal or encap state*/
      49           22 :     if ((spdm_context->response_state != LIBSPDM_RESPONSE_STATE_NORMAL) &&
      50            1 :         (spdm_context->response_state != LIBSPDM_RESPONSE_STATE_PROCESSING_ENCAP)) {
      51            1 :         return libspdm_responder_handle_response_state(
      52              :             spdm_context,
      53            1 :             spdm_request->header.request_response_code,
      54              :             response_size, response);
      55              :     }
      56              : 
      57           21 :     if (spdm_context->connection_info.connection_state <
      58              :         LIBSPDM_CONNECTION_STATE_AFTER_CAPABILITIES) {
      59            1 :         libspdm_generate_error_response(
      60              :             spdm_context, SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
      61              :             response_size, response);
      62            1 :         return LIBSPDM_STATUS_SUCCESS;
      63              :     }
      64              : 
      65           20 :     if (request_size < sizeof(spdm_chunk_send_request_t)) {
      66            1 :         libspdm_generate_error_response(
      67              :             spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0,
      68              :             response_size, response);
      69            1 :         return LIBSPDM_STATUS_SUCCESS;
      70              :     }
      71              : 
      72           19 :     if (spdm_request->header.spdm_version < SPDM_MESSAGE_VERSION_12) {
      73            1 :         return libspdm_generate_error_response(
      74              :             spdm_context, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST, SPDM_CHUNK_SEND,
      75              :             response_size, response);
      76              :     }
      77              : 
      78           18 :     if (spdm_request->header.spdm_version
      79           18 :         != libspdm_get_connection_version(spdm_context)) {
      80            1 :         return libspdm_generate_error_response(
      81              :             spdm_context, SPDM_ERROR_CODE_VERSION_MISMATCH, 0,
      82              :             response_size, response);
      83              :     }
      84              : 
      85           17 :     if (spdm_context->chunk_context.get.chunk_in_use) {
      86              :         /* Specification does not support simultaneous chunk send and chunk get. */
      87            1 :         return libspdm_generate_error_response(
      88              :             spdm_context, SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
      89              :             response_size, response);
      90              :     }
      91              : 
      92           16 :     send_info = &spdm_context->chunk_context.send;
      93              : 
      94           16 :     if (!send_info->chunk_in_use) {
      95              : 
      96            7 :         if (request_size < sizeof(spdm_chunk_send_request_t) + sizeof(uint32_t)) {
      97            0 :             libspdm_generate_error_response(
      98              :                 spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0,
      99              :                 response_size, response);
     100            0 :             return LIBSPDM_STATUS_SUCCESS;
     101              :         }
     102              : 
     103            7 :         large_message_size = *(const uint32_t*) (spdm_request + 1);
     104            7 :         chunk = (((const uint8_t*) (spdm_request + 1)) + sizeof(uint32_t));
     105            7 :         calc_max_chunk_size =
     106            7 :             (uint32_t)request_size - (sizeof(spdm_chunk_send_request_t) + sizeof(uint32_t));
     107            7 :         max_chunk_data_transfer_size =
     108            7 :             ((size_t) spdm_context->local_context.capability.data_transfer_size
     109            7 :              - sizeof(spdm_chunk_send_request_t)) * 65536 - sizeof(uint32_t);
     110              : 
     111            7 :         if (spdm_request->chunk_seq_no != 0
     112            6 :             || (spdm_request->chunk_size
     113              :                 < SPDM_MIN_DATA_TRANSFER_SIZE_VERSION_12
     114              :                 - sizeof(spdm_chunk_send_request_t)
     115              :                 - sizeof(uint32_t))
     116            6 :             || spdm_request->chunk_size > calc_max_chunk_size
     117            5 :             || (uint32_t)request_size > spdm_context->local_context.capability.data_transfer_size
     118            4 :             || large_message_size > spdm_context->local_context.capability.max_spdm_msg_size
     119            2 :             || large_message_size > max_chunk_data_transfer_size
     120            2 :             || large_message_size <= SPDM_MIN_DATA_TRANSFER_SIZE_VERSION_12
     121            2 :             || (spdm_request->header.param1 & SPDM_CHUNK_SEND_REQUEST_ATTRIBUTE_LAST_CHUNK)
     122              :             ) {
     123            6 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     124              :         } else {
     125            1 :             libspdm_get_scratch_buffer(spdm_context, (void**) &scratch_buffer,
     126              :                                        &scratch_buffer_size);
     127              : 
     128            1 :             send_info->chunk_in_use = true;
     129            1 :             send_info->chunk_handle = spdm_request->header.param2;
     130            1 :             send_info->chunk_seq_no = spdm_request->chunk_seq_no;
     131              : 
     132            2 :             send_info->large_message = scratch_buffer +
     133            1 :                                        libspdm_get_scratch_buffer_large_message_offset(spdm_context);
     134            1 :             send_info->large_message_capacity =
     135            1 :                 libspdm_get_scratch_buffer_large_message_capacity(spdm_context);
     136            1 :             send_info->large_message_size = large_message_size;
     137            1 :             send_info->chunk_bytes_transferred = spdm_request->chunk_size;
     138              : 
     139            1 :             libspdm_copy_mem(
     140              :                 send_info->large_message, send_info->large_message_capacity,
     141            1 :                 chunk, spdm_request->chunk_size);
     142              :         }
     143              :     } else {
     144              : 
     145            9 :         chunk = (const uint8_t*) (spdm_request + 1);
     146            9 :         calc_max_chunk_size =
     147            9 :             (uint32_t)request_size - sizeof(spdm_chunk_send_request_t);
     148              : 
     149            9 :         if (spdm_request->chunk_seq_no != send_info->chunk_seq_no + 1
     150            4 :             || spdm_request->header.param2 != send_info->chunk_handle
     151            3 :             || spdm_request->chunk_size > calc_max_chunk_size
     152            3 :             || spdm_request->chunk_size + send_info->chunk_bytes_transferred
     153            3 :             > send_info->large_message_size) {
     154            8 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     155            1 :         } else if ((spdm_request->header.param1 & SPDM_CHUNK_SEND_REQUEST_ATTRIBUTE_LAST_CHUNK)
     156            1 :                    && (spdm_request->chunk_size + send_info->chunk_bytes_transferred
     157            1 :                        != send_info->large_message_size)) {
     158            0 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     159            1 :         } else if (!(spdm_request->header.param1 & SPDM_CHUNK_SEND_REQUEST_ATTRIBUTE_LAST_CHUNK)
     160            0 :                    && ((spdm_request->chunk_size + send_info->chunk_bytes_transferred
     161            0 :                         > send_info->large_message_size)
     162            0 :                        || (spdm_request->chunk_size
     163              :                            < SPDM_MIN_DATA_TRANSFER_SIZE_VERSION_12
     164              :                            - sizeof(spdm_chunk_send_request_t))
     165            0 :                        || ((uint32_t) request_size
     166            0 :                            > spdm_context->local_context.capability.data_transfer_size))) {
     167            0 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     168            1 :         } else if (spdm_request->chunk_seq_no == 0) {
     169              :             /* Chunk seq no wrapped */
     170            0 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     171              :         } else {
     172              : 
     173            1 :             libspdm_copy_mem(
     174            1 :                 (uint8_t*)send_info->large_message + send_info->chunk_bytes_transferred,
     175            1 :                 send_info->large_message_size - send_info->chunk_bytes_transferred,
     176            1 :                 chunk, spdm_request->chunk_size);
     177              : 
     178            1 :             send_info->chunk_seq_no = spdm_request->chunk_seq_no;
     179            1 :             send_info->chunk_bytes_transferred += spdm_request->chunk_size;
     180            1 :             if (spdm_request->header.param1 & SPDM_CHUNK_SEND_REQUEST_ATTRIBUTE_LAST_CHUNK) {
     181            1 :                 send_info->chunk_in_use= false;
     182              :             }
     183              :         }
     184              :     }
     185              : 
     186           16 :     LIBSPDM_ASSERT(*response_size >= sizeof(spdm_chunk_send_ack_response_t));
     187              : 
     188           16 :     libspdm_zero_mem(response, *response_size);
     189           16 :     spdm_response = response;
     190              : 
     191           16 :     spdm_response->header.spdm_version = spdm_request->header.spdm_version;
     192           16 :     spdm_response->header.request_response_code = SPDM_CHUNK_SEND_ACK;
     193           16 :     spdm_response->header.param1 = 0;
     194           16 :     spdm_response->header.param2 = spdm_request->header.param2; /* handle */
     195           16 :     spdm_response->chunk_seq_no = spdm_request->chunk_seq_no;
     196              : 
     197           16 :     chunk_response = (uint8_t*) (spdm_response + 1);
     198           16 :     chunk_response_size = *response_size - sizeof(spdm_chunk_send_ack_response_t);
     199              : 
     200           16 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     201              :         /* Set the EARLY_ERROR_DETECTED bit here, because one of the CHUNK_SEND requests failed.
     202              :          * If there is an error after all chunks have been sent by the requester correctly,
     203              :          * the responder reflects the error in the ChunkSendAck.ResponseToLargeRequest buffer,
     204              :          * and not in the EARLY_ERROR_DETECTED bit. */
     205              : 
     206           14 :         spdm_response->header.param1
     207           14 :             |= SPDM_CHUNK_SEND_ACK_RESPONSE_ATTRIBUTE_EARLY_ERROR_DETECTED;
     208              : 
     209           14 :         libspdm_generate_error_response(
     210              :             spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0,
     211              :             &chunk_response_size, chunk_response);
     212              : 
     213           14 :         *response_size = sizeof(spdm_chunk_send_ack_response_t) + chunk_response_size;
     214              : 
     215           14 :         send_info->chunk_in_use = false;
     216           14 :         send_info->chunk_handle = 0;
     217           14 :         send_info->chunk_seq_no = 0;
     218           14 :         send_info->chunk_bytes_transferred = 0;
     219           14 :         send_info->large_message = NULL;
     220           14 :         send_info->large_message_size = 0;
     221            2 :     } else if (send_info->chunk_bytes_transferred == send_info->large_message_size) {
     222              :         uint8_t opcode;
     223              : 
     224            1 :         opcode = ((spdm_message_header_t*)send_info->large_message)->request_response_code;
     225              :         libspdm_get_spdm_response_func response_func =
     226            1 :             libspdm_get_response_func_via_request_code(opcode);
     227              : 
     228            1 :         if ((response_func != NULL) &&
     229            1 :             (opcode != SPDM_CHUNK_SEND) && (opcode != SPDM_CHUNK_GET)) {
     230            1 :             status = response_func(
     231              :                 spdm_context,
     232            1 :                 send_info->large_message_size, send_info->large_message,
     233              :                 &chunk_response_size, chunk_response);
     234              :         } else {
     235            0 :             status = LIBSPDM_STATUS_SUCCESS;
     236            0 :             libspdm_generate_error_response(
     237              :                 spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0,
     238              :                 &chunk_response_size, chunk_response);
     239              :         }
     240              : 
     241            1 :         send_info->chunk_in_use = false;
     242            1 :         send_info->chunk_handle = 0;
     243            1 :         send_info->chunk_seq_no = 0;
     244            1 :         send_info->chunk_bytes_transferred = 0;
     245            1 :         send_info->large_message = NULL;
     246            1 :         send_info->large_message_size = 0;
     247              : 
     248            1 :         *response_size = sizeof(spdm_chunk_send_ack_response_t) + chunk_response_size;
     249              :     } else {
     250            1 :         *response_size = sizeof(spdm_chunk_send_ack_response_t);
     251              :     }
     252              : 
     253           16 :     return status;
     254              : }
     255              : 
     256              : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
        

Generated by: LCOV version 2.0-1