Code coverage report for DMTF/libspdm
Current view: top level - library/spdm_responder_lib - libspdm_rsp_chunk_send_ack.c (source / functions) Coverage Total Hit
Test: 36148b912f76d231c18d216d6dee5c0858575bb1 Lines: 96.1 % 154 148
Test Date: 2026-10-25 08:40:22 Functions: 100.0 % 1 1
Branches: 84.4 % 90 76

             Branch data     Line data    Source code
       1                 :             : /**
       2                 :             :  *  Copyright Notice:
       3                 :             :  *  Copyright 2021-2026 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                 :          64 : 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                 :          64 :     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                 :          64 :     spdm_request = (const spdm_chunk_send_request_t*) request;
      35                 :             : 
      36         [ -  + ]:          64 :     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         [ +  + ]:          64 :     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                 :           2 :         return libspdm_generate_error_response(
      47                 :             :             spdm_context,
      48                 :             :             SPDM_ERROR_CODE_UNSUPPORTED_REQUEST, SPDM_CHUNK_SEND,
      49                 :             :             response_size, response);
      50                 :             :     }
      51                 :             : 
      52                 :             :     /*chunk mechanism can be used for normal or encap state*/
      53         [ +  + ]:          62 :     if (spdm_context->response_state != LIBSPDM_RESPONSE_STATE_NORMAL) {
      54                 :           2 :         return libspdm_responder_handle_response_state(
      55                 :             :             spdm_context,
      56                 :           2 :             spdm_request->header.request_response_code,
      57                 :             :             response_size, response);
      58                 :             :     }
      59                 :             : 
      60         [ +  + ]:          60 :     if (spdm_context->connection_info.connection_state <
      61                 :             :         LIBSPDM_CONNECTION_STATE_AFTER_CAPABILITIES) {
      62                 :           2 :         libspdm_generate_error_response(
      63                 :             :             spdm_context, SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
      64                 :             :             response_size, response);
      65                 :           2 :         return LIBSPDM_STATUS_SUCCESS;
      66                 :             :     }
      67                 :             : 
      68                 :             :     LIBSPDM_ASSERT(sizeof(spdm_chunk_send_request_t) == sizeof(spdm_chunk_send_request_14_t));
      69         [ +  + ]:          58 :     if (request_size < sizeof(spdm_chunk_send_request_t)) {
      70                 :           2 :         libspdm_generate_error_response(
      71                 :             :             spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0,
      72                 :             :             response_size, response);
      73                 :           2 :         return LIBSPDM_STATUS_SUCCESS;
      74                 :             :     }
      75                 :             : 
      76         [ +  + ]:          56 :     if (spdm_request->header.spdm_version < SPDM_MESSAGE_VERSION_12) {
      77                 :           2 :         return libspdm_generate_error_response(
      78                 :             :             spdm_context, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST, SPDM_CHUNK_SEND,
      79                 :             :             response_size, response);
      80                 :             :     }
      81                 :             : 
      82         [ +  + ]:          54 :     if (spdm_request->header.spdm_version
      83                 :          54 :         != libspdm_get_connection_version(spdm_context)) {
      84                 :           2 :         return libspdm_generate_error_response(
      85                 :             :             spdm_context, SPDM_ERROR_CODE_VERSION_MISMATCH, 0,
      86                 :             :             response_size, response);
      87                 :             :     }
      88                 :             : 
      89         [ +  + ]:          52 :     if (spdm_context->chunk_context.get.chunk_in_use) {
      90                 :             :         /* Specification does not support simultaneous chunk send and chunk get. */
      91                 :           2 :         return libspdm_generate_error_response(
      92                 :             :             spdm_context, SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
      93                 :             :             response_size, response);
      94                 :             :     }
      95                 :             : 
      96         [ +  + ]:          50 :     if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_14) {
      97                 :          46 :         chunk_seq_no = spdm_request->chunk_seq_no;
      98                 :             :     } else {
      99                 :           4 :         spdm_request_14 = (const spdm_chunk_send_request_14_t *) spdm_request;
     100                 :           4 :         chunk_seq_no = spdm_request_14->chunk_seq_no;
     101                 :             :     }
     102                 :             : 
     103                 :          50 :     send_info = &spdm_context->chunk_context.send;
     104                 :             : 
     105   [ +  +  +  + ]:          50 :     if (send_info->chunk_in_use && !libspdm_chunk_is_same_session(spdm_context, send_info)) {
     106                 :             :         /* Another session owns the transfer. Leave it untouched. */
     107                 :           4 :         return libspdm_generate_error_response(
     108                 :             :             spdm_context, SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
     109                 :             :             response_size, response);
     110                 :             :     }
     111                 :             : 
     112         [ +  + ]:          46 :     if (!send_info->chunk_in_use) {
     113                 :             : 
     114         [ -  + ]:          20 :         if (request_size < sizeof(spdm_chunk_send_request_t) + sizeof(uint32_t)) {
     115                 :           0 :             libspdm_generate_error_response(
     116                 :             :                 spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0,
     117                 :             :                 response_size, response);
     118                 :           0 :             return LIBSPDM_STATUS_SUCCESS;
     119                 :             :         }
     120                 :             : 
     121                 :          20 :         large_message_size = libspdm_read_uint32((const uint8_t *)(spdm_request + 1));
     122                 :          20 :         chunk = (((const uint8_t*) (spdm_request + 1)) + sizeof(uint32_t));
     123                 :          20 :         calc_max_chunk_size =
     124                 :          20 :             (uint32_t)request_size - (sizeof(spdm_chunk_send_request_t) + sizeof(uint32_t));
     125                 :             : 
     126         [ +  + ]:          20 :         if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_14) {
     127                 :          18 :             max_chunk_data_transfer_size =
     128                 :          18 :                 ((size_t) spdm_context->local_context.capability.data_transfer_size
     129                 :          18 :                  - sizeof(spdm_chunk_send_request_t)) * 65536 - sizeof(uint32_t);
     130                 :             :         } else {
     131                 :             :             /* chunk seq no wrap not considered in spdm 1.4+ */
     132                 :           2 :             max_chunk_data_transfer_size = UINT64_MAX;
     133                 :             :         }
     134                 :             : 
     135         [ +  + ]:          20 :         if (chunk_seq_no != 0
     136         [ +  - ]:          18 :             || (spdm_request->chunk_size
     137                 :             :                 < SPDM_MIN_DATA_TRANSFER_SIZE_VERSION_12
     138                 :             :                 - sizeof(spdm_chunk_send_request_t)
     139                 :             :                 - sizeof(uint32_t))
     140         [ +  + ]:          18 :             || spdm_request->chunk_size > calc_max_chunk_size
     141         [ +  + ]:          16 :             || (uint32_t)request_size > spdm_context->local_context.capability.data_transfer_size
     142         [ +  + ]:          14 :             || large_message_size > spdm_context->local_context.capability.max_spdm_msg_size
     143         [ +  - ]:          10 :             || large_message_size > max_chunk_data_transfer_size
     144         [ +  - ]:          10 :             || large_message_size <= SPDM_MIN_DATA_TRANSFER_SIZE_VERSION_12
     145         [ +  + ]:          10 :             || (spdm_request->header.param1 & SPDM_CHUNK_SEND_REQUEST_ATTRIBUTE_LAST_CHUNK)
     146                 :             :             ) {
     147                 :          12 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     148                 :             :         } else {
     149                 :           8 :             libspdm_get_scratch_buffer(spdm_context, (void**) &scratch_buffer,
     150                 :             :                                        &scratch_buffer_size);
     151                 :             : 
     152                 :           8 :             send_info->chunk_in_use = true;
     153                 :           8 :             send_info->session_id_valid = spdm_context->last_spdm_request_session_id_valid;
     154                 :           8 :             send_info->session_id = spdm_context->last_spdm_request_session_id;
     155                 :           8 :             send_info->chunk_handle = spdm_request->header.param2;
     156                 :           8 :             send_info->chunk_seq_no = chunk_seq_no;
     157                 :          16 :             send_info->large_message = scratch_buffer +
     158                 :           8 :                                        libspdm_get_scratch_buffer_large_message_offset(spdm_context);
     159                 :           8 :             send_info->large_message_capacity =
     160                 :           8 :                 libspdm_get_scratch_buffer_large_message_capacity(spdm_context);
     161                 :           8 :             send_info->large_message_size = large_message_size;
     162                 :           8 :             send_info->chunk_bytes_transferred = spdm_request->chunk_size;
     163                 :             : 
     164                 :           8 :             libspdm_copy_mem(
     165                 :             :                 send_info->large_message, send_info->large_message_capacity,
     166                 :           8 :                 chunk, spdm_request->chunk_size);
     167                 :             :         }
     168                 :             :     } else {
     169                 :             : 
     170                 :          26 :         chunk = (const uint8_t*) (spdm_request + 1);
     171                 :          26 :         calc_max_chunk_size =
     172                 :          26 :             (uint32_t)request_size - sizeof(spdm_chunk_send_request_t);
     173                 :             : 
     174         [ +  + ]:          26 :         if (chunk_seq_no != send_info->chunk_seq_no + 1) {
     175                 :          10 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     176                 :             :         }
     177                 :             : 
     178         [ +  + ]:          26 :         if (spdm_request->header.param2 != send_info->chunk_handle
     179         [ +  - ]:          24 :             || spdm_request->chunk_size > calc_max_chunk_size
     180                 :          24 :             || spdm_request->chunk_size + send_info->chunk_bytes_transferred
     181         [ +  + ]:          24 :             > send_info->large_message_size) {
     182                 :           8 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     183         [ +  + ]:          18 :         } else if ((spdm_request->header.param1 & SPDM_CHUNK_SEND_REQUEST_ATTRIBUTE_LAST_CHUNK)
     184                 :           8 :                    && (spdm_request->chunk_size + send_info->chunk_bytes_transferred
     185         [ -  + ]:           8 :                        != send_info->large_message_size)) {
     186                 :           0 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     187         [ +  + ]:          18 :         } else if (!(spdm_request->header.param1 & SPDM_CHUNK_SEND_REQUEST_ATTRIBUTE_LAST_CHUNK)
     188                 :          10 :                    && ((spdm_request->chunk_size + send_info->chunk_bytes_transferred
     189         [ +  - ]:          10 :                         > send_info->large_message_size)
     190         [ +  + ]:          10 :                        || (spdm_request->chunk_size
     191                 :             :                            < SPDM_MIN_DATA_TRANSFER_SIZE_VERSION_12
     192                 :             :                            - sizeof(spdm_chunk_send_request_t))
     193                 :           4 :                        || ((uint32_t) request_size
     194         [ -  + ]:           4 :                            > spdm_context->local_context.capability.data_transfer_size))) {
     195                 :           6 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     196         [ +  + ]:          12 :         } else if (chunk_seq_no == 0) {
     197                 :             :             /* Chunk seq no wrapped */
     198                 :           2 :             status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
     199                 :             :         } else {
     200                 :             : 
     201                 :          10 :             libspdm_copy_mem(
     202                 :          10 :                 (uint8_t*)send_info->large_message + send_info->chunk_bytes_transferred,
     203                 :          10 :                 send_info->large_message_size - send_info->chunk_bytes_transferred,
     204                 :          10 :                 chunk, spdm_request->chunk_size);
     205                 :             : 
     206                 :          10 :             send_info->chunk_seq_no = chunk_seq_no;
     207                 :          10 :             send_info->chunk_bytes_transferred += spdm_request->chunk_size;
     208         [ +  + ]:          10 :             if (spdm_request->header.param1 & SPDM_CHUNK_SEND_REQUEST_ATTRIBUTE_LAST_CHUNK) {
     209                 :           8 :                 send_info->chunk_in_use= false;
     210                 :             :             }
     211                 :             :         }
     212                 :             :     }
     213                 :             : 
     214         [ +  + ]:          46 :     if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_14) {
     215                 :          42 :         response_header_size = sizeof(spdm_chunk_send_ack_response_t);
     216                 :             :     } else {
     217                 :           4 :         response_header_size = sizeof(spdm_chunk_send_ack_response_14_t);
     218                 :             :     }
     219                 :          46 :     LIBSPDM_ASSERT(*response_size >= response_header_size);
     220                 :          46 :     libspdm_zero_mem(response, *response_size);
     221                 :          46 :     spdm_response = response;
     222                 :             : 
     223                 :          46 :     spdm_response->header.spdm_version = spdm_request->header.spdm_version;
     224                 :          46 :     spdm_response->header.request_response_code = SPDM_CHUNK_SEND_ACK;
     225                 :          46 :     spdm_response->header.param1 = 0;
     226                 :          46 :     spdm_response->header.param2 = spdm_request->header.param2; /* handle */
     227                 :             : 
     228         [ +  + ]:          46 :     if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_14) {
     229                 :          42 :         spdm_response->chunk_seq_no = (uint16_t) chunk_seq_no;
     230                 :             :     } else {
     231                 :           4 :         spdm_response_14 = response;
     232                 :           4 :         spdm_response_14->chunk_seq_no = chunk_seq_no;
     233                 :             :     }
     234                 :             : 
     235                 :          46 :     chunk_response = (uint8_t*) spdm_response + response_header_size;
     236                 :          46 :     chunk_response_size = *response_size - response_header_size;
     237                 :             : 
     238         [ +  + ]:          46 :     if (LIBSPDM_STATUS_IS_ERROR(status)) {
     239                 :             :         /* Set the EARLY_ERROR_DETECTED bit here, because one of the CHUNK_SEND requests failed.
     240                 :             :          * If there is an error after all chunks have been sent by the requester correctly,
     241                 :             :          * the responder reflects the error in the ChunkSendAck.ResponseToLargeRequest buffer,
     242                 :             :          * and not in the EARLY_ERROR_DETECTED bit. */
     243                 :             : 
     244                 :          28 :         spdm_response->header.param1
     245                 :          28 :             |= SPDM_CHUNK_SEND_ACK_RESPONSE_ATTRIBUTE_EARLY_ERROR_DETECTED;
     246                 :             : 
     247                 :          28 :         libspdm_generate_error_response(
     248                 :             :             spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0,
     249                 :             :             &chunk_response_size, chunk_response);
     250                 :             : 
     251                 :          28 :         *response_size = response_header_size + chunk_response_size;
     252                 :             : 
     253                 :             :         /* Return success so that libspdm_build_response() does not overwrite the
     254                 :             :          * CHUNK_SEND_ACK with EarlyErrorDetected with a generic error. */
     255                 :          28 :         status = LIBSPDM_STATUS_SUCCESS;
     256                 :             : 
     257         [ +  + ]:          28 :         if (send_info->large_message != NULL) {
     258                 :           2 :             libspdm_zero_mem(send_info->large_message, send_info->large_message_capacity);
     259                 :             :         }
     260                 :             : 
     261                 :          28 :         send_info->chunk_in_use = false;
     262                 :          28 :         send_info->chunk_handle = 0;
     263                 :          28 :         send_info->chunk_seq_no = 0;
     264                 :          28 :         send_info->chunk_bytes_transferred = 0;
     265                 :          28 :         send_info->large_message = NULL;
     266                 :          28 :         send_info->large_message_size = 0;
     267                 :          28 :         send_info->large_message_capacity = 0;
     268         [ +  + ]:          18 :     } else if (send_info->chunk_bytes_transferred == send_info->large_message_size) {
     269                 :             :         uint8_t opcode;
     270                 :           8 :         uint8_t reject_error_code = 0;
     271                 :             : 
     272                 :           8 :         opcode = ((spdm_message_header_t*)send_info->large_message)->request_response_code;
     273                 :             :         libspdm_get_spdm_response_func response_func =
     274                 :           8 :             libspdm_get_response_func_via_request_code(opcode);
     275                 :             : 
     276   [ +  -  +  - ]:           8 :         if ((response_func == NULL) ||
     277         [ -  + ]:           8 :             (opcode == SPDM_CHUNK_SEND) || (opcode == SPDM_CHUNK_GET)) {
     278                 :           0 :             status = LIBSPDM_STATUS_SUCCESS;
     279                 :           0 :             libspdm_generate_error_response(
     280                 :             :                 spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0,
     281                 :             :                 &chunk_response_size, chunk_response);
     282         [ +  + ]:           8 :         } else if (libspdm_is_request_unexpected_for_mut_auth_encap(
     283                 :             :                        spdm_context,
     284         [ -  + ]:           8 :                        spdm_context->last_spdm_request_session_id_valid ?
     285                 :             :                        &spdm_context->last_spdm_request_session_id : NULL,
     286                 :             :                        opcode, &reject_error_code)) {
     287                 :             :             /* libspdm_build_response() saw CHUNK_SEND, so the ordering checks are applied
     288                 :             :              * here to the assembled request. */
     289                 :           2 :             status = LIBSPDM_STATUS_SUCCESS;
     290                 :           2 :             libspdm_generate_error_response(
     291                 :             :                 spdm_context, reject_error_code, 0,
     292                 :             :                 &chunk_response_size, chunk_response);
     293                 :             :         } else {
     294                 :           6 :             status = response_func(
     295                 :             :                 spdm_context,
     296                 :           6 :                 send_info->large_message_size, send_info->large_message,
     297                 :             :                 &chunk_response_size, chunk_response);
     298                 :             :         }
     299                 :             : 
     300                 :           8 :         send_info->chunk_in_use = false;
     301                 :           8 :         send_info->chunk_handle = 0;
     302                 :           8 :         send_info->chunk_seq_no = 0;
     303                 :           8 :         send_info->chunk_bytes_transferred = 0;
     304         [ +  - ]:           8 :         if (send_info->large_message != NULL) {
     305                 :           8 :             libspdm_zero_mem(send_info->large_message, send_info->large_message_capacity);
     306                 :             :         }
     307                 :           8 :         send_info->large_message = NULL;
     308                 :           8 :         send_info->large_message_size = 0;
     309                 :           8 :         send_info->large_message_capacity = 0;
     310                 :             : 
     311                 :           8 :         *response_size = response_header_size + chunk_response_size;
     312                 :             :     } else {
     313                 :          10 :         *response_size = response_header_size;
     314                 :             :     }
     315                 :             : 
     316                 :          46 :     return status;
     317                 :             : }
     318                 :             : 
     319                 :             : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
        

Generated by: LCOV version 2.0-1