Skip to content

Commit

Permalink
prevent sending partial multi-frame transfers
Browse files Browse the repository at this point in the history
check that we have sufficient blocks available in the allocator before
we start a multi-frame transfer to ensure we don't send a corrupt
message by sending a subset of the frames. This can prevent a bus
overload condition where the sender retries on a failed transfer, but
the failed transfer consumes bus traffic and reduces the number of
blocks available for the next transfer
  • Loading branch information
tridge committed Sep 24, 2024
1 parent f11bdf7 commit e6e2906
Showing 1 changed file with 15 additions and 1 deletion.
16 changes: 15 additions & 1 deletion canard.c
Original file line number Diff line number Diff line change
Expand Up @@ -1206,6 +1206,20 @@ CANARD_INTERNAL int16_t enqueueTxFrames(CanardInstance* ins,
uint8_t toggle = 0;
uint8_t sot_eot = 0x80;

/*
see if we are going to be able to allocate enough blocks for
this transfer. If not then stop now, otherwise we will end
up doing a partial (corrupt) transfer which will just make
the situation worse as it will waste bus bandwidth
*/
const uint16_t total_bytes = transfer->payload_len + 2; // including CRC
const uint8_t bytes_per_frame = frame_max_data_len-1; // sot/eot byte consumes one byte
const uint16_t frames_needed = (total_bytes + (bytes_per_frame-1)) / bytes_per_frame;
const uint16_t blocks_available = ins->allocator.statistics.capacity_blocks - ins->allocator.statistics.current_usage_blocks;
if (blocks_available < frames_needed) {
return -CANARD_ERROR_OUT_OF_MEMORY;
}

CanardTxQueueItem* queue_item = NULL;

while (transfer->payload_len - data_index != 0)
Expand All @@ -1214,7 +1228,7 @@ CANARD_INTERNAL int16_t enqueueTxFrames(CanardInstance* ins,
if (queue_item == NULL)
{
CANARD_ASSERT(false);
return -CANARD_ERROR_OUT_OF_MEMORY; // TODO: Purge all frames enqueued so far
return -CANARD_ERROR_OUT_OF_MEMORY;
}

uint16_t i = 0;
Expand Down

0 comments on commit e6e2906

Please sign in to comment.