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

Generated by: LCOV version 2.0-1