Skip to content

File syn_uds.c

File List > proto > syn_uds.c

Go to the documentation of this file

#include "syn_uds.h"

#include "../crypto/syn_aes.h"
#include "../util/syn_pack.h"

#include <string.h>

bool syn_uds_init(SYN_UDS_Server *server)
{
    if (server == NULL) {
        return false;
    }

    memset(server, 0, sizeof(*server));
    server->session = SYN_UDS_SESSION_DEFAULT;
    server->security_state = SYN_UDS_SECURITY_LOCKED;
    server->current_seed = 0x12345678U;
    server->active_seed = 0x12345678U;
    server->use_aes128_security = false;
    memset(server->aes_security_key, 0, sizeof(server->aes_security_key));
    static const uint8_t default_seed_16[16] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF,
                                                0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10};
    memcpy(server->current_seed_bytes, default_seed_16, 16);
    memcpy(server->active_seed_bytes, default_seed_16, 16);
    server->s3_timer_ms = 0U;
    server->security_error_count = 0U;
    server->security_delay_timer_ms = 0U;
    server->comm_control_state = SYN_UDS_COMM_ENABLE_RX_AND_TX;
    server->p2_max_ms = 50U;
    server->p2_star_max_10ms = 500U;
    server->active_p2_max_ms = 50U;
    server->active_p2_star_max_10ms = 500U;
    server->timing_cb = NULL;
    server->timing_ctx = NULL;
    server->memory_cb = NULL;
    server->memory_ctx = NULL;
    server->auth_cb = NULL;
    server->auth_ctx = NULL;
    server->file_transfer_cb = NULL;
    server->file_transfer_ctx = NULL;
    server->dtc_cb = NULL;
    server->dtc_ctx = NULL;
    server->did_count = 0U;
    server->dtc_count = 0U;
    server->transfer_state = SYN_UDS_TRANSFER_IDLE;
    server->transfer_address = 0U;
    server->transfer_size = 0U;
    server->transfer_bytes_processed = 0U;
    server->expected_block_seq = 1U;
    server->reset_type_requested = 0U;
    server->reset_cb = NULL;
    server->reset_ctx = NULL;
    server->reset_tx_wait_ms = SYN_UDS_DEFAULT_RESET_TX_WAIT_MS;
    server->reset_wait_elapsed_ms = 0U;
    server->session_transition_cb = NULL;
    server->session_transition_ctx = NULL;
    server->custom_session_count = 0U;
    server->custom_security_count = 0U;

    return true;
}

static int find_did_index(const SYN_UDS_Server *server, uint16_t did)
{
    /* LCOV_EXCL_START: Defensive null check */
    if (server == NULL) {
        return -1;
    }
    /* LCOV_EXCL_STOP */
    for (uint8_t i = 0U; i < server->did_count; i++) {
        if (server->did_table[i].did == did) {
            return (int)i;
        }
    }
    return -1;
}

bool syn_uds_enable_aes128_security(SYN_UDS_Server *server, const uint8_t key[16])
{
    if (server == NULL || key == NULL) {
        return false;
    }
    server->use_aes128_security = true;
    memcpy(server->aes_security_key, key, 16);
    return true;
}

bool syn_uds_disable_aes128_security(SYN_UDS_Server *server)
{
    if (server == NULL) {
        return false;
    }
    server->use_aes128_security = false;
    memset(server->aes_security_key, 0, sizeof(server->aes_security_key));
    return true;
}

bool syn_uds_set_security_seed_bytes(SYN_UDS_Server *server, const uint8_t seed[16])
{
    if (server == NULL || seed == NULL) {
        return false;
    }
    memcpy(server->current_seed_bytes, seed, 16);
    return true;
}

void syn_uds_tick(SYN_UDS_Server *server, uint32_t dt_ms)
{
    if (server == NULL) {
        return;
    }

    /* 1. Security delay countdown */
    if (server->security_delay_timer_ms > 0U) {
        if (dt_ms >= server->security_delay_timer_ms) {
            server->security_delay_timer_ms = 0U;
            if (server->security_error_count > 0U) {
                server->security_error_count--;
            }
        } else {
            server->security_delay_timer_ms -= dt_ms;
        }
    }

    /* 2. S3 server session timeout countdown */
    if (server->session != SYN_UDS_SESSION_DEFAULT) {
        if (dt_ms >= server->s3_timer_ms) {
            /* S3 timer expired -> revert to DEFAULT session, lock security, and restore comm */
            server->session = SYN_UDS_SESSION_DEFAULT;
            server->security_state = SYN_UDS_SECURITY_LOCKED;
            server->comm_control_state = SYN_UDS_COMM_ENABLE_RX_AND_TX;
            server->transfer_state = SYN_UDS_TRANSFER_IDLE;
            server->s3_timer_ms = 0U;
        } else {
            server->s3_timer_ms -= dt_ms;
        }
    } else {
        server->s3_timer_ms = 0U;
    }

    /* 3. Deferred ECU reset countdown */
    if (server->reset_type_requested > 0U) {
        server->reset_wait_elapsed_ms += dt_ms;
        if (server->reset_wait_elapsed_ms >= (uint32_t)server->reset_tx_wait_ms) {
            uint8_t reset_type = server->reset_type_requested;
            server->reset_type_requested = 0U;
            server->reset_wait_elapsed_ms = 0U;
            if (server->reset_cb != NULL) {
                server->reset_cb(reset_type, server->reset_ctx);
            }
        }
    } else {
        server->reset_wait_elapsed_ms = 0U;
    }
}

void syn_uds_set_session_transition_handler(SYN_UDS_Server *server,
                                            SYN_UDS_SessionTransitionHandler cb, void *ctx)
{
    if (server != NULL) {
        server->session_transition_cb = cb;
        server->session_transition_ctx = ctx;
    }
}

void syn_uds_set_reset_handler(SYN_UDS_Server *server, SYN_UDS_ResetHandler cb, void *ctx)
{
    if (server != NULL) {
        server->reset_cb = cb;
        server->reset_ctx = ctx;
    }
}

void syn_uds_set_reset_wait_ms(SYN_UDS_Server *server, uint16_t wait_ms)
{
    if (server != NULL) {
        server->reset_tx_wait_ms = wait_ms;
    }
}

uint8_t syn_uds_get_pending_reset(const SYN_UDS_Server *server)
{
    if (server == NULL) {
        return 0U;
    }
    return server->reset_type_requested;
}

void syn_uds_clear_pending_reset(SYN_UDS_Server *server)
{
    if (server != NULL) {
        server->reset_type_requested = 0U;
        server->reset_wait_elapsed_ms = 0U;
    }
}

bool syn_uds_register_did_ext(SYN_UDS_Server *server, uint16_t did, uint8_t *data, uint16_t len,
                              bool writable, uint8_t session_mask, uint16_t security_mask)
{
    if ((server == NULL) || (data == NULL) || (len == 0U)) {
        return false;
    }

    if (server->did_count >= SYN_UDS_MAX_DIDS) {
        return false;
    }

    SYN_UDS_DIDEntry *entry = &server->did_table[server->did_count];
    entry->did = did;
    entry->data = data;
    entry->len = len;
    entry->writable = writable;
    entry->session_mask = session_mask;
    entry->security_mask = security_mask;

    server->did_count++;
    return true;
}

bool syn_uds_register_did(SYN_UDS_Server *server, uint16_t did, uint8_t *data, uint16_t len,
                          bool writable)
{
    return syn_uds_register_did_ext(server, did, data, len, writable, SYN_UDS_SESSION_MASK_ALL,
                                    SYN_UDS_SECURITY_MASK_ALL);
}

bool syn_uds_register_comm_control(SYN_UDS_Server *server, SYN_UDS_CommControlHandler handler,
                                   void *ctx)
{
    if (server == NULL) {
        return false;
    }
    server->comm_control_cb = handler;
    server->comm_control_ctx = ctx;
    return true;
}

bool syn_uds_register_access_timing(SYN_UDS_Server *server, SYN_UDS_AccessTimingHandler handler,
                                    void *ctx)
{
    if (server == NULL) {
        return false;
    }
    server->timing_cb = handler;
    server->timing_ctx = ctx;
    return true;
}

bool syn_uds_register_secured_data(SYN_UDS_Server *server, SYN_UDS_SecuredDataHandler handler,
                                   void *ctx)
{
    if (server == NULL) {
        return false;
    }
    server->secured_data_cb = handler;
    server->secured_data_ctx = ctx;
    return true;
}

bool syn_uds_register_memory_handler(SYN_UDS_Server *server, SYN_UDS_MemoryHandler handler,
                                     void *ctx)
{
    if (server == NULL) {
        return false;
    }
    server->memory_cb = handler;
    server->memory_ctx = ctx;
    return true;
}

bool syn_uds_register_auth_handler(SYN_UDS_Server *server, SYN_UDS_AuthHandler handler, void *ctx)
{
    if (server == NULL) {
        return false;
    }
    server->auth_cb = handler;
    server->auth_ctx = ctx;
    return true;
}

bool syn_uds_register_file_transfer(SYN_UDS_Server *server, SYN_UDS_FileTransferHandler handler,
                                    void *ctx)
{
    if (server == NULL) {
        return false;
    }
    server->file_transfer_cb = handler;
    server->file_transfer_ctx = ctx;
    return true;
}

bool syn_uds_register_routine_control(SYN_UDS_Server *server, SYN_UDS_RoutineControlHandler handler,
                                      void *ctx)
{
    if (server == NULL) {
        return false;
    }
    server->routine_cb = handler;
    server->routine_ctx = ctx;
    return true;
}

bool syn_uds_register_io_control(SYN_UDS_Server *server, SYN_UDS_IOControlHandler handler,
                                 void *ctx)
{
    if (server == NULL) {
        return false;
    }
    server->io_control_cb = handler;
    server->io_control_ctx = ctx;
    return true;
}

bool syn_uds_register_link_control(SYN_UDS_Server *server, SYN_UDS_LinkControlHandler handler,
                                   void *ctx)
{
    if (server == NULL) {
        return false;
    }
    server->link_control_cb = handler;
    server->link_control_ctx = ctx;
    return true;
}

bool syn_uds_register_roe_handler(SYN_UDS_Server *server, SYN_UDS_ResponseOnEventHandler handler,
                                  void *ctx)
{
    if (server == NULL) {
        return false;
    }
    server->roe_cb = handler;
    server->roe_ctx = ctx;
    return true;
}

bool syn_uds_register_scaling_data_handler(SYN_UDS_Server *server,
                                           SYN_UDS_ScalingDataHandler handler, void *ctx)
{
    if (server == NULL) {
        return false;
    }
    server->scaling_cb = handler;
    server->scaling_ctx = ctx;
    return true;
}

bool syn_uds_register_periodic_data_handler(SYN_UDS_Server *server,
                                            SYN_UDS_PeriodicDataHandler handler, void *ctx)
{
    if (server == NULL) {
        return false;
    }
    server->periodic_cb = handler;
    server->periodic_ctx = ctx;
    return true;
}

bool syn_uds_register_dynamic_did_handler(SYN_UDS_Server *server, SYN_UDS_DynamicDIDHandler handler,
                                          void *ctx)
{
    if (server == NULL) {
        return false;
    }
    server->dynamic_did_cb = handler;
    server->dynamic_did_ctx = ctx;
    return true;
}

bool syn_uds_register_dtc(SYN_UDS_Server *server, uint32_t dtc, uint8_t status, uint8_t severity)
{
    if (server == NULL || server->dtc_count >= SYN_UDS_MAX_DTCS) {
        return false;
    }
    server->dtc_table[server->dtc_count].dtc = dtc & 0xFFFFFFU;
    server->dtc_table[server->dtc_count].status = status;
    server->dtc_table[server->dtc_count].severity = severity;
    server->dtc_table[server->dtc_count].fault_cnt = 0;
    server->dtc_count++;
    return true;
}

bool syn_uds_register_dtc_handler(SYN_UDS_Server *server, SYN_UDS_DTCHandler handler, void *ctx)
{
    if (server == NULL) {
        return false;
    }
    server->dtc_cb = handler;
    server->dtc_ctx = ctx;
    return true;
}

static bool make_negative_response(uint8_t sid, uint8_t nrc, uint8_t *resp_buf, uint16_t *resp_len,
                                   SYN_UDS_AddrMode addr_mode)
{
    if (addr_mode == SYN_UDS_ADDR_FUNCTIONAL &&
        (nrc == SYN_UDS_NRC_SERVICE_NOT_SUPPORTED || nrc == SYN_UDS_NRC_SUBFUNCTION_NOT_SUPPORTED ||
         nrc == SYN_UDS_NRC_SUBFUNCTION_NOT_SUPPORTED_IN_ACTIVE_SESSION)) {
        *resp_len = 0U;
        return true;
    }
    resp_buf[0] = SYN_UDS_RESPONSE_NEGATIVE;
    resp_buf[1] = sid;
    resp_buf[2] = nrc;
    *resp_len = 3U;
    return true;
}
bool syn_uds_is_sid_functional_supported(uint8_t sid)
{
    switch (sid) {
    case SYN_UDS_SID_DIAGNOSTIC_SESSION_CONTROL:   /* 0x10 */
    case SYN_UDS_SID_ECU_RESET:                    /* 0x11 */
    case SYN_UDS_SID_CLEAR_DIAGNOSTIC_INFORMATION: /* 0x14 */
    case SYN_UDS_SID_READ_DTC_INFORMATION:         /* 0x19 */
    case SYN_UDS_SID_READ_DATA_BY_IDENTIFIER:      /* 0x22 */
    case SYN_UDS_SID_COMMUNICATION_CONTROL:        /* 0x28 */
    case SYN_UDS_SID_AUTHENTICATION:               /* 0x29 */
    case SYN_UDS_SID_ROUTINE_CONTROL:              /* 0x31 */
    case SYN_UDS_SID_TESTER_PRESENT:               /* 0x3E */
    case SYN_UDS_SID_ACCESS_TIMING_PARAMETER:      /* 0x83 */
    case SYN_UDS_SID_CONTROL_DTC_SETTING:          /* 0x85 */
    case SYN_UDS_SID_LINK_CONTROL:                 /* 0x87 */
        return true;
    default:
        return false;
    }
}

static bool get_sid_functional_support(uint8_t sid)
{
    return syn_uds_is_sid_functional_supported(sid);
}

static uint8_t session_to_mask(SYN_UDS_Session session)
{
    switch (session) {
    case SYN_UDS_SESSION_DEFAULT:
        return SYN_UDS_SESSION_MASK_DEFAULT;
    case SYN_UDS_SESSION_PROGRAMMING:
        return SYN_UDS_SESSION_MASK_PROGRAMMING;
    case SYN_UDS_SESSION_EXTENDED:
        return SYN_UDS_SESSION_MASK_EXTENDED;
    case SYN_UDS_SESSION_SAFETY_SYSTEM:
        return SYN_UDS_SESSION_MASK_SAFETY;
    /* LCOV_EXCL_START: Unreachable session enum guard */
    default:
        return 0U;
        /* LCOV_EXCL_STOP */
    }
}

static uint8_t get_sid_allowed_session_mask(const SYN_UDS_Server *server, uint8_t sid)
{
    if (server != NULL) {
        for (uint8_t i = 0U; i < server->custom_session_count; i++) {
            if (server->custom_session_sids[i] == sid) {
                return server->custom_session_masks[i];
            }
        }
    }
    return SYN_UDS_SESSION_MASK_ALL;
}

static uint16_t get_sid_required_security_mask(const SYN_UDS_Server *server, uint8_t sid)
{
    if (server != NULL) {
        for (uint8_t i = 0U; i < server->custom_security_count; i++) {
            if (server->custom_security_sids[i] == sid) {
                return server->custom_security_masks[i];
            }
        }
    }
    return 0U;
}

static uint16_t get_active_security_mask(const SYN_UDS_Server *server)
{
    uint16_t mask = (1U << 0);
    if (server != NULL && server->security_state == SYN_UDS_SECURITY_UNLOCKED) {
        mask |= (uint16_t)(1U << server->security_level);
    }
    return mask;
}

bool syn_uds_set_service_session_mask(SYN_UDS_Server *server, uint8_t sid, uint8_t session_mask)
{
    if (server == NULL) {
        return false;
    }
    for (uint8_t i = 0U; i < server->custom_session_count; i++) {
        if (server->custom_session_sids[i] == sid) {
            /* LCOV_EXCL_START: Update existing service session mask override */
            server->custom_session_masks[i] = session_mask;
            return true;
            /* LCOV_EXCL_STOP */
        }
    }
    if (server->custom_session_count < SYN_UDS_MAX_SERVICE_OVERRIDES) {
        uint8_t idx = server->custom_session_count++;
        server->custom_session_sids[idx] = sid;
        server->custom_session_masks[idx] = session_mask;
        return true;
    }
    return false;
}

bool syn_uds_set_service_security_mask(SYN_UDS_Server *server, uint8_t sid, uint16_t security_mask)
{
    if (server == NULL) {
        return false;
    }
    for (uint8_t i = 0U; i < server->custom_security_count; i++) {
        if (server->custom_security_sids[i] == sid) {
            /* LCOV_EXCL_START: Update existing service security mask override */
            server->custom_security_masks[i] = security_mask;
            return true;
            /* LCOV_EXCL_STOP */
        }
    }
    if (server->custom_security_count < SYN_UDS_MAX_SERVICE_OVERRIDES) {
        uint8_t idx = server->custom_security_count++;
        server->custom_security_sids[idx] = sid;
        server->custom_security_masks[idx] = security_mask;
        return true;
    }
    return false;
}

bool syn_uds_process_request(SYN_UDS_Server *server, const uint8_t *req, uint16_t req_len,
                             uint8_t *resp_buf, uint16_t max_resp_len, uint16_t *resp_len,
                             SYN_UDS_AddrMode addr_mode)
{
    if ((server == NULL) || (req == NULL) || (req_len == 0U) || (resp_buf == NULL) ||
        (max_resp_len < 3U) || (resp_len == NULL)) {
        return false;
    }

    uint8_t sid = req[0];
    bool success = false;

    if (addr_mode == SYN_UDS_ADDR_FUNCTIONAL && !get_sid_functional_support(sid)) {
        *resp_len = 0U;
        return true;
    }

    uint8_t allowed_mask = get_sid_allowed_session_mask(server, sid);
    uint8_t current_mask = session_to_mask(server->session);
    if ((sid != SYN_UDS_SID_DIAGNOSTIC_SESSION_CONTROL) && ((allowed_mask & current_mask) == 0U)) {
        return make_negative_response(sid, SYN_UDS_NRC_SUBFUNCTION_NOT_SUPPORTED_IN_ACTIVE_SESSION,
                                      resp_buf, resp_len, addr_mode);
    }

    uint16_t req_sec_mask = get_sid_required_security_mask(server, sid);
    if (req_sec_mask != 0U) {
        if ((get_active_security_mask(server) & req_sec_mask) == 0U) {
            return make_negative_response(sid, SYN_UDS_NRC_SECURITY_ACCESS_DENIED, resp_buf,
                                          resp_len, addr_mode);
        }
    }

    switch (sid) {
    case SYN_UDS_SID_DIAGNOSTIC_SESSION_CONTROL: {
        if (req_len < 2U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint8_t sub = req[1] & 0x7FU;
        if ((sub != SYN_UDS_SESSION_DEFAULT) && (sub != SYN_UDS_SESSION_PROGRAMMING) &&
            (sub != SYN_UDS_SESSION_EXTENDED) && (sub != SYN_UDS_SESSION_SAFETY_SYSTEM)) {
            return make_negative_response(sid, SYN_UDS_NRC_SUBFUNCTION_NOT_SUPPORTED, resp_buf,
                                          resp_len, addr_mode);
        }

        if (server->session_transition_cb != NULL) {
            if (!server->session_transition_cb(server->session, (SYN_UDS_Session)sub,
                                               server->session_transition_ctx)) {
                return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                              resp_len, addr_mode);
            }
        }

        server->session = (SYN_UDS_Session)sub;
        if (server->session == SYN_UDS_SESSION_DEFAULT) {
            server->security_state = SYN_UDS_SECURITY_LOCKED;
            server->comm_control_state = SYN_UDS_COMM_ENABLE_RX_AND_TX;
            server->transfer_state = SYN_UDS_TRANSFER_IDLE;
            server->s3_timer_ms = 0U;
        } else {
            server->s3_timer_ms = SYN_UDS_S3_TIMEOUT_MS;
            if (server->session == SYN_UDS_SESSION_PROGRAMMING) {
                /* ISO 14229: Switching to programming session clears power-on safety delay */
                server->security_delay_timer_ms = 0U;
            }
        }

        resp_buf[0] = sid + 0x40U;
        resp_buf[1] = sub;
        syn_poke_u16(server->active_p2_max_ms, resp_buf, 2);
        syn_poke_u16(server->active_p2_star_max_10ms, resp_buf, 4);
        *resp_len = 6U;
        success = true;
        break;
    }

    case SYN_UDS_SID_ECU_RESET: {
        if (req_len < 2U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint8_t sub = req[1] & 0x7FU;
        if ((sub < SYN_UDS_RESET_HARD) || (sub > SYN_UDS_RESET_DISABLE_RAPID_POWER_SHUTDOWN)) {
            return make_negative_response(sid, SYN_UDS_NRC_SUBFUNCTION_NOT_SUPPORTED, resp_buf,
                                          resp_len, addr_mode);
        }
        server->reset_type_requested = sub;
        server->reset_wait_elapsed_ms = 0U;
        resp_buf[0] = sid + 0x40U;
        resp_buf[1] = sub;
        *resp_len = 2U;
        success = true;
        break;
    }

    case SYN_UDS_SID_SECURITY_ACCESS: {
        if (req_len < 2U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint8_t sub = req[1] & 0x7FU;
        if (sub == 0x00U || sub == 0x7FU) {
            return make_negative_response(sid, SYN_UDS_NRC_SUBFUNCTION_NOT_SUPPORTED, resp_buf,
                                          resp_len, addr_mode);
        }
        if ((sub & 1U) != 0U) { /* Odd subfunction = Request Seed (0x01, 0x03, 0x05...) */
            if (server->security_delay_timer_ms > 0U) {
                return make_negative_response(sid, SYN_UDS_NRC_REQUIRED_TIME_DELAY_NOT_EXPIRED,
                                              resp_buf, resp_len, addr_mode);
            }
            resp_buf[0] = sid + 0x40U;
            resp_buf[1] = sub;
            server->security_state = SYN_UDS_SECURITY_SEED_SENT;
            server->active_seed_subfunction = sub;
            if (server->use_aes128_security) {
                memcpy(server->active_seed_bytes, server->current_seed_bytes, 16);
                memcpy(&resp_buf[2], server->current_seed_bytes, 16);
                *resp_len = 18U;
            } else {
                server->active_seed = server->current_seed;
                syn_poke_u32(server->current_seed, resp_buf, 2);
                *resp_len = 6U;
            }
            success = true;
        } else if ((sub & 1U) == 0U &&
                   sub != 0x00U) { /* Even subfunction = Send Key (0x02, 0x04...) */
            if (server->security_state != SYN_UDS_SECURITY_SEED_SENT) {
                return make_negative_response(sid, SYN_UDS_NRC_REQUEST_SEQUENCE_ERROR, resp_buf,
                                              resp_len, addr_mode);
            }
            if (sub != (server->active_seed_subfunction + 1U)) {
                return make_negative_response(sid, SYN_UDS_NRC_REQUEST_SEQUENCE_ERROR, resp_buf,
                                              resp_len, addr_mode);
            }
            if (server->use_aes128_security) {
                if (req_len < 18U) {
                    return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH,
                                                  resp_buf, resp_len, addr_mode);
                }
                SYN_AES_Context aes_ctx;
                (void)syn_aes_init(&aes_ctx, server->aes_security_key, 16U);
                uint8_t expected_key[16];
                syn_aes_encrypt_block(&aes_ctx, server->active_seed_bytes, expected_key);

                if (memcmp(&req[2], expected_key, 16) == 0) {
                    server->security_state = SYN_UDS_SECURITY_UNLOCKED;
                    server->security_level = sub / 2U;
                    server->security_error_count = 0U;
                    resp_buf[0] = sid + 0x40U;
                    resp_buf[1] = sub;
                    *resp_len = 2U;
                    success = true;
                } else {
                    server->security_state = SYN_UDS_SECURITY_LOCKED;
                    server->security_level = 0U;
                    server->security_error_count++;
                    if (server->security_error_count >= SYN_UDS_SECURITY_MAX_ATTEMPTS) {
                        server->security_delay_timer_ms = SYN_UDS_SECURITY_DELAY_MS;
                        return make_negative_response(sid, SYN_UDS_NRC_EXCEEDED_NUMBER_OF_ATTEMPTS,
                                                      resp_buf, resp_len, addr_mode);
                    }
                    return make_negative_response(sid, SYN_UDS_NRC_INVALID_KEY, resp_buf, resp_len,
                                                  addr_mode);
                }
            } else {
                if (req_len < 6U) {
                    return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH,
                                                  resp_buf, resp_len, addr_mode);
                }
                uint32_t key = syn_peek_u32(req, 2);
                /* Key calculation algorithm: key = seed ^ 0xA5A5A5A5 */
                uint32_t expected_key = server->active_seed ^ 0xA5A5A5A5U;
                if (key == expected_key) {
                    server->security_state = SYN_UDS_SECURITY_UNLOCKED;
                    server->security_level = sub / 2U;
                    server->security_error_count = 0U;
                    resp_buf[0] = sid + 0x40U;
                    resp_buf[1] = sub;
                    *resp_len = 2U;
                    success = true;
                } else {
                    server->security_state = SYN_UDS_SECURITY_LOCKED;
                    server->security_level = 0U;
                    server->security_error_count++;
                    if (server->security_error_count >= SYN_UDS_SECURITY_MAX_ATTEMPTS) {
                        server->security_delay_timer_ms = SYN_UDS_SECURITY_DELAY_MS;
                        return make_negative_response(sid, SYN_UDS_NRC_EXCEEDED_NUMBER_OF_ATTEMPTS,
                                                      resp_buf, resp_len, addr_mode);
                    }
                    return make_negative_response(sid, SYN_UDS_NRC_INVALID_KEY, resp_buf, resp_len,
                                                  addr_mode);
                }
            }
        } else {
            /* LCOV_EXCL_START: UDS negative response NRC return */
            return make_negative_response(sid, SYN_UDS_NRC_SUBFUNCTION_NOT_SUPPORTED, resp_buf,
                                          resp_len, addr_mode);
            /* LCOV_EXCL_STOP */
        }
        break;
    }

    case SYN_UDS_SID_COMMUNICATION_CONTROL: {
        if (req_len < 3U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint8_t sub = req[1] & 0x7FU;
        if (sub > 0x05U) {
            return make_negative_response(sid, SYN_UDS_NRC_SUBFUNCTION_NOT_SUPPORTED, resp_buf,
                                          resp_len, addr_mode);
        }
        uint8_t comm_type = req[2];
        if (comm_type == 0U) {
            return make_negative_response(sid, SYN_UDS_NRC_REQUEST_OUT_OF_RANGE, resp_buf, resp_len,
                                          addr_mode);
        }

        if (server->comm_control_cb != NULL) {
            if (!server->comm_control_cb((SYN_UDS_CommControlType)sub, comm_type,
                                         server->comm_control_ctx)) {
                return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                              resp_len, addr_mode);
            }
        }

        server->comm_control_state = (SYN_UDS_CommControlType)sub;
        server->comm_type = comm_type;

        resp_buf[0] = sid + 0x40U;
        resp_buf[1] = sub;
        *resp_len = 2U;
        success = true;
        break;
    }

    case SYN_UDS_SID_READ_DATA_BY_IDENTIFIER: {
        if (req_len < 3U || ((req_len - 1U) % 2U) != 0U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }

        resp_buf[0] = sid + 0x40U;
        size_t out_pos = 1U;

        for (size_t req_pos = 1U; req_pos < req_len; req_pos += 2U) {
            uint16_t target_did = syn_peek_u16(req, req_pos);
            SYN_UDS_DIDEntry *matched_entry = NULL;
            for (uint8_t i = 0U; i < server->did_count; i++) {
                if (server->did_table[i].did == target_did) {
                    matched_entry = &server->did_table[i];
                    break;
                }
            }
            if (matched_entry == NULL) {
                return make_negative_response(sid, SYN_UDS_NRC_REQUEST_OUT_OF_RANGE, resp_buf,
                                              resp_len, addr_mode);
            }
            if ((matched_entry->session_mask & session_to_mask(server->session)) == 0U) {
                return make_negative_response(
                    sid, SYN_UDS_NRC_SUBFUNCTION_NOT_SUPPORTED_IN_ACTIVE_SESSION, resp_buf,
                    resp_len, addr_mode);
            }
            if ((get_active_security_mask(server) & matched_entry->security_mask) == 0U) {
                return make_negative_response(sid, SYN_UDS_NRC_SECURITY_ACCESS_DENIED, resp_buf,
                                              resp_len, addr_mode);
            }
            if (out_pos + 2U + matched_entry->len > max_resp_len) {
                return make_negative_response(sid, SYN_UDS_NRC_RESPONSE_TOO_LONG, resp_buf,
                                              resp_len, addr_mode);
            }

            syn_poke_u16(target_did, resp_buf, out_pos);
            out_pos += 2U;
            memcpy(&resp_buf[out_pos], matched_entry->data, matched_entry->len);
            out_pos += matched_entry->len;
        }

        *resp_len = out_pos;
        success = true;
        break;
    }

    case SYN_UDS_SID_WRITE_DATA_BY_IDENTIFIER: {
        if (req_len < 4U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint16_t target_did = syn_peek_u16(req, 1);
        SYN_UDS_DIDEntry *matched_entry = NULL;
        for (uint8_t i = 0U; i < server->did_count; i++) {
            if (server->did_table[i].did == target_did) {
                matched_entry = &server->did_table[i];
                break;
            }
        }
        if (matched_entry == NULL) {
            return make_negative_response(sid, SYN_UDS_NRC_REQUEST_OUT_OF_RANGE, resp_buf, resp_len,
                                          addr_mode);
        }
        if ((matched_entry->session_mask & session_to_mask(server->session)) == 0U) {
            return make_negative_response(sid,
                                          SYN_UDS_NRC_SUBFUNCTION_NOT_SUPPORTED_IN_ACTIVE_SESSION,
                                          resp_buf, resp_len, addr_mode);
        }
        if (!matched_entry->writable) {
            return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                          resp_len, addr_mode);
        }
        if ((server->security_state != SYN_UDS_SECURITY_UNLOCKED &&
             matched_entry->security_mask == SYN_UDS_SECURITY_MASK_ALL) ||
            ((get_active_security_mask(server) & matched_entry->security_mask) == 0U)) {
            return make_negative_response(sid, SYN_UDS_NRC_SECURITY_ACCESS_DENIED, resp_buf,
                                          resp_len, addr_mode);
        }
        uint16_t data_len = req_len - 3U;
        if (data_len > matched_entry->len) {
            data_len = matched_entry->len;
        }
        memcpy(matched_entry->data, &req[3], data_len);
        resp_buf[0] = sid + 0x40U;
        syn_poke_u16(target_did, resp_buf, 1);
        *resp_len = 3U;
        success = true;
        break;
    }

    case SYN_UDS_SID_ROUTINE_CONTROL: {
        if (req_len < 4U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint8_t sub = req[1] & 0x7FU;
        if (sub < 0x01U || sub > 0x03U) {
            return make_negative_response(sid, SYN_UDS_NRC_SUBFUNCTION_NOT_SUPPORTED, resp_buf,
                                          resp_len, addr_mode);
        }
        uint16_t routine_id = syn_peek_u16(req, 2);
        if (server->routine_cb != NULL) {
            uint16_t out_payload_len = 0U;
            if (!server->routine_cb(sub, routine_id, &req[4], req_len - 4U, &resp_buf[4],
                                    max_resp_len - 4U, &out_payload_len, server->routine_ctx)) {
                return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                              resp_len, addr_mode);
            }
            resp_buf[0] = sid + 0x40U;
            resp_buf[1] = sub;
            syn_poke_u16(routine_id, resp_buf, 2);
            *resp_len = 4U + out_payload_len;
        } else {
            resp_buf[0] = sid + 0x40U;
            resp_buf[1] = sub;
            syn_poke_u16(routine_id, resp_buf, 2);
            *resp_len = 4U;
        }
        success = true;
        break;
    }

    case SYN_UDS_SID_TESTER_PRESENT: {
        if (req_len < 2U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint8_t sub = req[1] & 0x7FU;
        if (sub != 0x00U) {
            return make_negative_response(sid, SYN_UDS_NRC_SUBFUNCTION_NOT_SUPPORTED, resp_buf,
                                          resp_len, addr_mode);
        }
        resp_buf[0] = sid + 0x40U;
        resp_buf[1] = sub;
        *resp_len = 2U;
        success = true;
        break;
    }

    case SYN_UDS_SID_ACCESS_TIMING_PARAMETER: {
        if (req_len < 2U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint8_t sub = req[1] & 0x7FU;
        switch (sub) {
        case SYN_UDS_TIMING_READ_EXTENDED: {
            if (req_len != 2U) {
                return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                              resp_len, addr_mode);
            }
            if (max_resp_len < 6U) {
                return make_negative_response(sid, SYN_UDS_NRC_RESPONSE_TOO_LONG, resp_buf,
                                              resp_len, addr_mode);
            }
            uint16_t p2 = server->p2_max_ms;
            uint16_t p2_star = server->p2_star_max_10ms;
            if (server->timing_cb != NULL) {
                if (!server->timing_cb(SYN_UDS_TIMING_READ_EXTENDED, &p2, &p2_star,
                                       server->timing_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                                  resp_len, addr_mode);
                }
            }
            resp_buf[0] = sid + 0x40U;
            resp_buf[1] = sub;
            syn_poke_u16(p2, resp_buf, 2);
            syn_poke_u16(p2_star, resp_buf, 4);
            *resp_len = 6U;
            success = true;
            break;
        }

        case SYN_UDS_TIMING_SET_TO_DEFAULT: {
            if (req_len != 2U) {
                return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                              resp_len, addr_mode);
            }
            uint16_t p2 = server->p2_max_ms;
            uint16_t p2_star = server->p2_star_max_10ms;
            if (server->timing_cb != NULL) {
                if (!server->timing_cb(SYN_UDS_TIMING_SET_TO_DEFAULT, &p2, &p2_star,
                                       server->timing_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                                  resp_len, addr_mode);
                }
            }
            server->active_p2_max_ms = p2;
            server->active_p2_star_max_10ms = p2_star;
            resp_buf[0] = sid + 0x40U;
            resp_buf[1] = sub;
            *resp_len = 2U;
            success = true;
            break;
        }

        case SYN_UDS_TIMING_READ_ACTIVE: {
            if (req_len != 2U) {
                return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                              resp_len, addr_mode);
            }
            if (max_resp_len < 6U) {
                return make_negative_response(sid, SYN_UDS_NRC_RESPONSE_TOO_LONG, resp_buf,
                                              resp_len, addr_mode);
            }
            uint16_t p2 = server->active_p2_max_ms;
            uint16_t p2_star = server->active_p2_star_max_10ms;
            if (server->timing_cb != NULL) {
                if (!server->timing_cb(SYN_UDS_TIMING_READ_ACTIVE, &p2, &p2_star,
                                       server->timing_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                                  resp_len, addr_mode);
                }
            }
            resp_buf[0] = sid + 0x40U;
            resp_buf[1] = sub;
            syn_poke_u16(p2, resp_buf, 2);
            syn_poke_u16(p2_star, resp_buf, 4);
            *resp_len = 6U;
            success = true;
            break;
        }

        case SYN_UDS_TIMING_SET_TO_GIVEN: {
            if (req_len != 6U) {
                return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                              resp_len, addr_mode);
            }
            uint16_t given_p2 = syn_peek_u16(req, 2);
            uint16_t given_p2_star = syn_peek_u16(req, 4);
            if (server->timing_cb != NULL) {
                if (!server->timing_cb(SYN_UDS_TIMING_SET_TO_GIVEN, &given_p2, &given_p2_star,
                                       server->timing_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_REQUEST_OUT_OF_RANGE, resp_buf,
                                                  resp_len, addr_mode);
                }
            }
            server->active_p2_max_ms = given_p2;
            server->active_p2_star_max_10ms = given_p2_star;
            resp_buf[0] = sid + 0x40U;
            resp_buf[1] = sub;
            *resp_len = 2U;
            success = true;
            break;
        }

        default: {
            return make_negative_response(sid, SYN_UDS_NRC_SUBFUNCTION_NOT_SUPPORTED, resp_buf,
                                          resp_len, addr_mode);
        }
        }
        break;
    }

    case SYN_UDS_SID_SECURED_DATA_TRANSMISSION: {
        if (req_len < 2U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        if (server->security_state != SYN_UDS_SECURITY_UNLOCKED) {
            return make_negative_response(sid, SYN_UDS_NRC_SECURITY_ACCESS_DENIED, resp_buf,
                                          resp_len, addr_mode);
        }
        uint16_t sec_in_len = req_len - 1U;
        const uint8_t *sec_in_data = &req[1];
        uint16_t sec_out_len = 0U;

        if (server->secured_data_cb != NULL) {
            if (!server->secured_data_cb(sec_in_data, sec_in_len, &resp_buf[1], max_resp_len - 1U,
                                         &sec_out_len, server->secured_data_ctx)) {
                return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                              resp_len, addr_mode);
            }
        } else {
            if (sec_in_len > (max_resp_len - 1U)) {
                /* LCOV_EXCL_START: UDS negative response NRC return */
                return make_negative_response(sid, SYN_UDS_NRC_RESPONSE_TOO_LONG, resp_buf,
                                              resp_len, addr_mode);
                /* LCOV_EXCL_STOP */
            }
            memcpy(&resp_buf[1], sec_in_data, sec_in_len);
            sec_out_len = sec_in_len;
        }

        resp_buf[0] = sid + 0x40U;
        *resp_len = 1U + sec_out_len;
        success = true;
        break;
    }

    case SYN_UDS_SID_CLEAR_DIAGNOSTIC_INFORMATION: {
        if (req_len != 4U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint32_t group_of_dtc =
            ((uint32_t)req[1] << 16U) | ((uint32_t)req[2] << 8U) | (uint32_t)req[3];

        bool is_all = (group_of_dtc == SYN_UDS_DTC_GROUP_ALL);
        bool is_emissions = (group_of_dtc == SYN_UDS_DTC_GROUP_EMISSIONS);
        bool is_powertrain = (group_of_dtc == SYN_UDS_DTC_GROUP_POWERTRAIN);
        bool is_chassis = (group_of_dtc == SYN_UDS_DTC_GROUP_CHASSIS);
        bool is_body = (group_of_dtc == SYN_UDS_DTC_GROUP_BODY);
        bool is_network = (group_of_dtc == SYN_UDS_DTC_GROUP_NETWORK);

        bool matches_exact_dtc = false;
        for (uint8_t i = 0U; i < server->dtc_count; i++) {
            if (server->dtc_table[i].dtc == group_of_dtc) {
                matches_exact_dtc = true;
                break;
            }
        }

        if (!is_all && !is_emissions && !is_powertrain && !is_chassis && !is_body && !is_network &&
            !matches_exact_dtc) {
            return make_negative_response(sid, SYN_UDS_NRC_REQUEST_OUT_OF_RANGE, resp_buf, resp_len,
                                          addr_mode);
        }

        uint8_t write_idx = 0U;
        for (uint8_t i = 0U; i < server->dtc_count; i++) {
            uint32_t dtc = server->dtc_table[i].dtc;
            bool clear_dtc = false;

            if (is_all || (dtc == group_of_dtc)) {
                clear_dtc = true;
            } else if (is_emissions && (dtc <= 0x0FFFFFU)) {
                clear_dtc = true;
            } else if (is_powertrain && (dtc >= 0x100000U && dtc <= 0x3FFFFFU)) {
                clear_dtc = true;
            } else if (is_chassis && (dtc >= 0x400000U && dtc <= 0x7FFFFFU)) {
                clear_dtc = true;
            } else if (is_body && (dtc >= 0x800000U && dtc <= 0xBFFFFFU)) {
                clear_dtc = true;
            } else if (is_network && (dtc >= 0xC00000U && dtc <= 0xFEFFFFU)) {
                clear_dtc = true;
            }

            if (!clear_dtc) {
                if (write_idx != i) {
                    server->dtc_table[write_idx] = server->dtc_table[i];
                }
                write_idx++;
            }
        }
        server->dtc_count = write_idx;

        resp_buf[0] = sid + 0x40U;
        *resp_len = 1U;
        success = true;
        break;
    }

    case SYN_UDS_SID_READ_DTC_INFORMATION: {
        if (req_len < 2U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint8_t sub = req[1] & 0x7FU;
        switch (sub) {
        /* ISO 14229-1 Table 246: reportNumberOfDTCByStatusMask (0x01) */
        case SYN_UDS_DTC_REPORT_NUMBER_BY_STATUS_MASK:
        /* ISO 14229-1 Table 248: reportNumberOfMirrorMemoryDTCByStatusMask (0x11) */
        case SYN_UDS_DTC_REPORT_NUMBER_MIRROR_MEMORY_BY_STATUS_MASK:
        /* ISO 14229-1 Table 250: reportNumberOfEmissionsOBDDTCByStatusMask (0x12) */
        case SYN_UDS_DTC_REPORT_NUMBER_EMISSIONS_OBD_BY_STATUS_MASK: {
            if (server->dtc_cb != NULL) {
                uint16_t cb_out_len = 0U;
                if (!server->dtc_cb(sub, &req[2], req_len - 2U, &resp_buf[2], max_resp_len - 2U,
                                    &cb_out_len, server->dtc_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                                  resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                *resp_len = 2U + cb_out_len;
            } else {
                if (req_len != 3U) {
                    return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH,
                                                  resp_buf, resp_len, addr_mode);
                }
                if (max_resp_len < 6U) {
                    return make_negative_response(sid, SYN_UDS_NRC_RESPONSE_TOO_LONG, resp_buf,
                                                  resp_len, addr_mode);
                }
                uint8_t mask = req[2];
                uint16_t match_cnt = 0U;
                for (uint8_t i = 0U; i < server->dtc_count; i++) {
                    if ((server->dtc_table[i].status & mask) != 0U) {
                        match_cnt++;
                    }
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                resp_buf[2] = SYN_UDS_DTC_STATUS_AVAILABILITY_MASK;
                resp_buf[3] = SYN_UDS_DTC_FORMAT_ISO14229_1;
                syn_poke_u16(match_cnt, resp_buf, 4);
                *resp_len = 6U;
            }
            success = true;
            break;
        }

        /* ISO 14229-1 Table 252: reportDTCByStatusMask (0x02) */
        case SYN_UDS_DTC_REPORT_BY_STATUS_MASK:
        /* ISO 14229-1 Table 254: reportMirrorMemoryDTCByStatusMask (0x0F) */
        case SYN_UDS_DTC_REPORT_MIRROR_MEMORY_BY_STATUS_MASK:
        /* ISO 14229-1 Table 253: reportEmissionsOBDDTCByStatusMask (0x13) */
        case SYN_UDS_DTC_REPORT_EMISSIONS_OBD_BY_STATUS_MASK: {
            if (server->dtc_cb != NULL) {
                uint16_t cb_out_len = 0U;
                if (!server->dtc_cb(sub, &req[2], req_len - 2U, &resp_buf[2], max_resp_len - 2U,
                                    &cb_out_len, server->dtc_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                                  resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                *resp_len = 2U + cb_out_len;
            } else {
                if (req_len != 3U) {
                    return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH,
                                                  resp_buf, resp_len, addr_mode);
                }
                uint8_t mask = req[2];
                uint16_t pos = 3U;
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                resp_buf[2] = SYN_UDS_DTC_STATUS_AVAILABILITY_MASK;
                for (uint8_t i = 0U; i < server->dtc_count; i++) {
                    if ((server->dtc_table[i].status & mask) != 0U) {
                        if (pos + 4U > max_resp_len) {
                            return make_negative_response(sid, SYN_UDS_NRC_RESPONSE_TOO_LONG,
                                                          resp_buf, resp_len, addr_mode);
                        }
                        resp_buf[pos] = (uint8_t)(server->dtc_table[i].dtc >> 16U);
                        resp_buf[pos + 1U] = (uint8_t)(server->dtc_table[i].dtc >> 8U);
                        resp_buf[pos + 2U] = (uint8_t)(server->dtc_table[i].dtc);
                        resp_buf[pos + 3U] = server->dtc_table[i].status;
                        pos += 4U;
                    }
                }
                *resp_len = pos;
            }
            success = true;
            break;
        }

        /* ISO 14229-1 Table 255: reportSupportedDTC (0x0A) */
        case SYN_UDS_DTC_REPORT_SUPPORTED:
        /* ISO 14229-1 Table 255: reportDTCWithPermanentStatus (0x15) */
        case SYN_UDS_DTC_REPORT_WITH_PERMANENT_STATUS: {
            if (server->dtc_cb != NULL) {
                uint16_t cb_out_len = 0U;
                if (!server->dtc_cb(sub, &req[2], req_len - 2U, &resp_buf[2], max_resp_len - 2U,
                                    &cb_out_len, server->dtc_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                                  resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                *resp_len = 2U + cb_out_len;
            } else {
                if (req_len != 2U) {
                    return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH,
                                                  resp_buf, resp_len, addr_mode);
                }
                uint16_t pos = 3U;
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                resp_buf[2] = SYN_UDS_DTC_STATUS_AVAILABILITY_MASK;
                for (uint8_t i = 0U; i < server->dtc_count; i++) {
                    if (pos + 4U > max_resp_len) {
                        return make_negative_response(sid, SYN_UDS_NRC_RESPONSE_TOO_LONG, resp_buf,
                                                      resp_len, addr_mode);
                    }
                    resp_buf[pos] = (uint8_t)(server->dtc_table[i].dtc >> 16U);
                    resp_buf[pos + 1U] = (uint8_t)(server->dtc_table[i].dtc >> 8U);
                    resp_buf[pos + 2U] = (uint8_t)(server->dtc_table[i].dtc);
                    resp_buf[pos + 3U] = server->dtc_table[i].status;
                    pos += 4U;
                }
                *resp_len = pos;
            }
            success = true;
            break;
        }

        case SYN_UDS_DTC_REPORT_WWH_OBD_BY_MASK_RECORD: {
            if (server->dtc_cb != NULL) {
                uint16_t cb_out_len = 0U;
                if (!server->dtc_cb(sub, &req[2], req_len - 2U, &resp_buf[2], max_resp_len - 2U,
                                    &cb_out_len, server->dtc_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                                  resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                *resp_len = 2U + cb_out_len;
            } else {
                if (req_len != 8U) {
                    return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH,
                                                  resp_buf, resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                resp_buf[2] = SYN_UDS_DTC_STATUS_AVAILABILITY_MASK;
                resp_buf[3] = (req_len >= 7U) ? req[6] : 0x01U; /* Format Identifier */
                *resp_len = 4U;
            }
            success = true;
            break;
        }

        /* ISO 14229-1 Table 256: reportFirstTestFailedDTC (0x0B) */
        case SYN_UDS_DTC_REPORT_FIRST_TEST_FAILED:
        /* ISO 14229-1 Table 256: reportMostRecentTestFailedDTC (0x0D) */
        case SYN_UDS_DTC_REPORT_MOST_RECENT_TEST_FAILED:
        /* ISO 14229-1 Table 256: reportFirstConfirmedDTC (0x0C) */
        case SYN_UDS_DTC_REPORT_FIRST_CONFIRMED:
        /* ISO 14229-1 Table 256: reportMostRecentConfirmedDTC (0x0E) */
        case SYN_UDS_DTC_REPORT_MOST_RECENT_CONFIRMED: {
            if (req_len != 2U) {
                return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                              resp_len, addr_mode);
            }
            resp_buf[0] = sid + 0x40U;
            resp_buf[1] = sub;
            resp_buf[2] = SYN_UDS_DTC_STATUS_AVAILABILITY_MASK;
            uint8_t match_idx = 0xFFU;
            uint8_t target_mask = (sub == SYN_UDS_DTC_REPORT_FIRST_TEST_FAILED ||
                                   sub == SYN_UDS_DTC_REPORT_MOST_RECENT_TEST_FAILED)
                                      ? 0x01U
                                      : 0x08U;

            for (uint8_t i = 0U; i < server->dtc_count; i++) {
                if ((server->dtc_table[i].status & target_mask) != 0U) {
                    match_idx = i;
                    if (sub == SYN_UDS_DTC_REPORT_FIRST_TEST_FAILED ||
                        sub == SYN_UDS_DTC_REPORT_FIRST_CONFIRMED) {
                        break;
                    }
                }
            }

            if (match_idx != 0xFFU) {
                if (max_resp_len < 7U) {
                    return make_negative_response(sid, SYN_UDS_NRC_RESPONSE_TOO_LONG, resp_buf,
                                                  resp_len, addr_mode);
                }
                resp_buf[3] = (uint8_t)(server->dtc_table[match_idx].dtc >> 16U);
                resp_buf[4] = (uint8_t)(server->dtc_table[match_idx].dtc >> 8U);
                resp_buf[5] = (uint8_t)(server->dtc_table[match_idx].dtc);
                resp_buf[6] = server->dtc_table[match_idx].status;
                *resp_len = 7U;
            } else {
                *resp_len = 3U;
            }
            success = true;
            break;
        }

        case SYN_UDS_DTC_REPORT_NUMBER_BY_SEVERITY_MASK: {
            if (server->dtc_cb != NULL) {
                uint16_t cb_out_len = 0U;
                if (!server->dtc_cb(sub, &req[2], req_len - 2U, &resp_buf[2], max_resp_len - 2U,
                                    &cb_out_len, server->dtc_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                                  resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                *resp_len = 2U + cb_out_len;
            } else {
                if (req_len != 4U) {
                    return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH,
                                                  resp_buf, resp_len, addr_mode);
                }
                uint8_t sev_mask = req[2];
                uint8_t stat_mask = req[3];
                uint16_t match_cnt = 0U;
                for (uint8_t i = 0U; i < server->dtc_count; i++) {
                    if (((server->dtc_table[i].severity & sev_mask) != 0U) &&
                        ((server->dtc_table[i].status & stat_mask) != 0U)) {
                        match_cnt++;
                    }
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                resp_buf[2] = SYN_UDS_DTC_STATUS_AVAILABILITY_MASK;
                resp_buf[3] = SYN_UDS_DTC_FORMAT_ISO14229_1;
                syn_poke_u16(match_cnt, resp_buf, 4);
                *resp_len = 6U;
            }
            success = true;
            break;
        }

        case SYN_UDS_DTC_REPORT_BY_SEVERITY_MASK: {
            if (server->dtc_cb != NULL) {
                uint16_t cb_out_len = 0U;
                if (!server->dtc_cb(sub, &req[2], req_len - 2U, &resp_buf[2], max_resp_len - 2U,
                                    &cb_out_len, server->dtc_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                                  resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                *resp_len = 2U + cb_out_len;
            } else {
                if (req_len != 4U) {
                    return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH,
                                                  resp_buf, resp_len, addr_mode);
                }
                uint8_t sev_mask = req[2];
                uint8_t stat_mask = req[3];
                uint16_t pos = 3U;
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                resp_buf[2] = SYN_UDS_DTC_STATUS_AVAILABILITY_MASK;
                for (uint8_t i = 0U; i < server->dtc_count; i++) {
                    if (((server->dtc_table[i].severity & sev_mask) != 0U) &&
                        ((server->dtc_table[i].status & stat_mask) != 0U)) {
                        if (pos + 6U > max_resp_len) {
                            return make_negative_response(sid, SYN_UDS_NRC_RESPONSE_TOO_LONG,
                                                          resp_buf, resp_len, addr_mode);
                        }
                        resp_buf[pos] = server->dtc_table[i].severity;
                        resp_buf[pos + 1U] = 0x00U;
                        resp_buf[pos + 2U] = (uint8_t)(server->dtc_table[i].dtc >> 16U);
                        resp_buf[pos + 3U] = (uint8_t)(server->dtc_table[i].dtc >> 8U);
                        resp_buf[pos + 4U] = (uint8_t)(server->dtc_table[i].dtc);
                        resp_buf[pos + 5U] = server->dtc_table[i].status;
                        pos += 6U;
                    }
                }
                *resp_len = pos;
            }
            success = true;
            break;
        }

        case SYN_UDS_DTC_REPORT_SEVERITY_INFO: {
            if (server->dtc_cb != NULL) {
                uint16_t cb_out_len = 0U;
                if (!server->dtc_cb(sub, &req[2], req_len - 2U, &resp_buf[2], max_resp_len - 2U,
                                    &cb_out_len, server->dtc_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                                  resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                *resp_len = 2U + cb_out_len;
            } else {
                if (req_len != 5U) {
                    return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH,
                                                  resp_buf, resp_len, addr_mode);
                }
                uint32_t req_dtc =
                    ((uint32_t)req[2] << 16U) | ((uint32_t)req[3] << 8U) | (uint32_t)req[4];
                uint8_t match_idx = 0xFFU;
                for (uint8_t i = 0U; i < server->dtc_count; i++) {
                    if (server->dtc_table[i].dtc == req_dtc) {
                        match_idx = i;
                        break;
                    }
                }
                if (match_idx != 0xFFU) {
                    if (max_resp_len < 8U) {
                        return make_negative_response(sid, SYN_UDS_NRC_RESPONSE_TOO_LONG, resp_buf,
                                                      resp_len, addr_mode);
                    }
                    resp_buf[0] = sid + 0x40U;
                    resp_buf[1] = sub;
                    resp_buf[2] = server->dtc_table[match_idx].severity;
                    resp_buf[3] = 0x00U; /* Functional unit */
                    resp_buf[4] = req[2];
                    resp_buf[5] = req[3];
                    resp_buf[6] = req[4];
                    resp_buf[7] = server->dtc_table[match_idx].status;
                    *resp_len = 8U;
                } else {
                    resp_buf[0] = sid + 0x40U;
                    resp_buf[1] = sub;
                    *resp_len = 2U;
                }
            }
            success = true;
            break;
        }

        case SYN_UDS_DTC_REPORT_FAULT_DETECTION_COUNTER: {
            if (server->dtc_cb != NULL) {
                uint16_t cb_out_len = 0U;
                if (!server->dtc_cb(sub, &req[2], req_len - 2U, &resp_buf[2], max_resp_len - 2U,
                                    &cb_out_len, server->dtc_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                                  resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                *resp_len = 2U + cb_out_len;
            } else {
                if (req_len != 2U) {
                    return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH,
                                                  resp_buf, resp_len, addr_mode);
                }
                uint16_t pos = 2U;
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                for (uint8_t i = 0U; i < server->dtc_count; i++) {
                    if (pos + 4U > max_resp_len) {
                        return make_negative_response(sid, SYN_UDS_NRC_RESPONSE_TOO_LONG, resp_buf,
                                                      resp_len, addr_mode);
                    }
                    resp_buf[pos] = (uint8_t)(server->dtc_table[i].dtc >> 16U);
                    resp_buf[pos + 1U] = (uint8_t)(server->dtc_table[i].dtc >> 8U);
                    resp_buf[pos + 2U] = (uint8_t)(server->dtc_table[i].dtc);
                    resp_buf[pos + 3U] = (uint8_t)server->dtc_table[i].fault_cnt;
                    pos += 4U;
                }
                *resp_len = pos;
            }
            success = true;
            break;
        }

        case SYN_UDS_DTC_REPORT_WWH_OBD_WITH_PERMANENT_STATUS: {
            if (server->dtc_cb != NULL) {
                uint16_t cb_out_len = 0U;
                if (!server->dtc_cb(sub, &req[2], req_len - 2U, &resp_buf[2], max_resp_len - 2U,
                                    &cb_out_len, server->dtc_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                                  resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                *resp_len = 2U + cb_out_len;
            } else {
                if (req_len != 4U) {
                    return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH,
                                                  resp_buf, resp_len, addr_mode);
                }
                uint8_t mask = req[3];
                uint16_t pos = 3U;
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                resp_buf[2] = SYN_UDS_DTC_STATUS_AVAILABILITY_MASK;
                for (uint8_t i = 0U; i < server->dtc_count; i++) {
                    if ((server->dtc_table[i].status & mask) != 0U) {
                        if (pos + 4U > max_resp_len) {
                            return make_negative_response(sid, SYN_UDS_NRC_RESPONSE_TOO_LONG,
                                                          resp_buf, resp_len, addr_mode);
                        }
                        resp_buf[pos] = (uint8_t)(server->dtc_table[i].dtc >> 16U);
                        resp_buf[pos + 1U] = (uint8_t)(server->dtc_table[i].dtc >> 8U);
                        resp_buf[pos + 2U] = (uint8_t)(server->dtc_table[i].dtc);
                        resp_buf[pos + 3U] = server->dtc_table[i].status;
                        pos += 4U;
                    }
                }
                *resp_len = pos;
            }
            success = true;
            break;
        }

        /* ISO 14229-1 Table 257: reportDTCSnapshotRecordByDTCNumber (0x04) */
        case SYN_UDS_DTC_REPORT_SNAPSHOT_RECORD_BY_DTC: {
            if (server->dtc_cb != NULL) {
                uint16_t cb_out_len = 0U;
                if (!server->dtc_cb(sub, &req[2], req_len - 2U, &resp_buf[2], max_resp_len - 2U,
                                    &cb_out_len, server->dtc_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                                  resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                *resp_len = 2U + cb_out_len;
            } else {
                if (req_len != 6U) {
                    return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH,
                                                  resp_buf, resp_len, addr_mode);
                }
                if (max_resp_len < 6U) {
                    return make_negative_response(sid, SYN_UDS_NRC_RESPONSE_TOO_LONG, resp_buf,
                                                  resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                resp_buf[2] = req[2];
                resp_buf[3] = req[3];
                resp_buf[4] = req[4];
                resp_buf[5] = SYN_UDS_DTC_STATUS_AVAILABILITY_MASK;
                *resp_len = 6U;
            }
            success = true;
            break;
        }

        /* ISO 14229-1 Table 259: reportDTCExtDataRecordByDTCNumber (0x06),
         * reportMirrorMemoryDTCExtDataRecordByDTCNumber (0x10) */
        case SYN_UDS_DTC_REPORT_EXT_DATA_RECORD_BY_DTC:
        case SYN_UDS_DTC_REPORT_MIRROR_MEMORY_EXT_DATA: {
            if (server->dtc_cb != NULL) {
                uint16_t cb_out_len = 0U;
                if (!server->dtc_cb(sub, &req[2], req_len - 2U, &resp_buf[2], max_resp_len - 2U,
                                    &cb_out_len, server->dtc_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                                  resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                *resp_len = 2U + cb_out_len;
            } else {
                if (req_len != 6U) {
                    return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH,
                                                  resp_buf, resp_len, addr_mode);
                }
                if (max_resp_len < 6U) {
                    return make_negative_response(sid, SYN_UDS_NRC_RESPONSE_TOO_LONG, resp_buf,
                                                  resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                resp_buf[2] = req[2];
                resp_buf[3] = req[3];
                resp_buf[4] = req[4];
                resp_buf[5] = SYN_UDS_DTC_STATUS_AVAILABILITY_MASK;
                *resp_len = 6U;
            }
            success = true;
            break;
        }

        case SYN_UDS_DTC_REPORT_USER_DEF_MEMORY_SNAPSHOT_BY_DTC:
        case SYN_UDS_DTC_REPORT_USER_DEF_MEMORY_EXT_DATA_BY_DTC: {
            if (server->dtc_cb != NULL) {
                uint16_t cb_out_len = 0U;
                if (!server->dtc_cb(sub, &req[2], req_len - 2U, &resp_buf[2], max_resp_len - 2U,
                                    &cb_out_len, server->dtc_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                                  resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                *resp_len = 2U + cb_out_len;
            } else {
                if (req_len != 7U) {
                    return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH,
                                                  resp_buf, resp_len, addr_mode);
                }
                if (max_resp_len < 7U) {
                    return make_negative_response(sid, SYN_UDS_NRC_RESPONSE_TOO_LONG, resp_buf,
                                                  resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                resp_buf[2] = req[6]; /* Memory Selection */
                resp_buf[3] = req[2]; /* DTC high */
                resp_buf[4] = req[3]; /* DTC mid */
                resp_buf[5] = req[4]; /* DTC low */
                resp_buf[6] = SYN_UDS_DTC_STATUS_AVAILABILITY_MASK;
                *resp_len = 7U;
            }
            success = true;
            break;
        }

        case SYN_UDS_DTC_REPORT_SNAPSHOT_IDENTIFICATION: {
            if (server->dtc_cb != NULL) {
                uint16_t cb_out_len = 0U;
                if (!server->dtc_cb(sub, &req[2], req_len - 2U, &resp_buf[2], max_resp_len - 2U,
                                    &cb_out_len, server->dtc_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                                  resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                *resp_len = 2U + cb_out_len;
            } else {
                if (req_len != 2U) {
                    return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH,
                                                  resp_buf, resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                *resp_len = 2U;
            }
            success = true;
            break;
        }

        case SYN_UDS_DTC_REPORT_STORED_DATA_BY_RECORD_NUM:
        case SYN_UDS_DTC_REPORT_EXT_DATA_RECORD_BY_RECORD_NUM: {
            if (server->dtc_cb != NULL) {
                uint16_t cb_out_len = 0U;
                if (!server->dtc_cb(sub, &req[2], req_len - 2U, &resp_buf[2], max_resp_len - 2U,
                                    &cb_out_len, server->dtc_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                                  resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                *resp_len = 2U + cb_out_len;
            } else {
                if (req_len != 3U) {
                    return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH,
                                                  resp_buf, resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                resp_buf[2] = req[2]; /* Record Number */
                *resp_len = 3U;
            }
            success = true;
            break;
        }

        case SYN_UDS_DTC_REPORT_USER_DEF_MEMORY_BY_STATUS_MASK: {
            if (server->dtc_cb != NULL) {
                uint16_t cb_out_len = 0U;
                if (!server->dtc_cb(sub, &req[2], req_len - 2U, &resp_buf[2], max_resp_len - 2U,
                                    &cb_out_len, server->dtc_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                                  resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                *resp_len = 2U + cb_out_len;
            } else {
                if (req_len != 4U) {
                    return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH,
                                                  resp_buf, resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                resp_buf[2] = req[3]; /* Memory Selection */
                resp_buf[3] = SYN_UDS_DTC_STATUS_AVAILABILITY_MASK;
                *resp_len = 4U;
            }
            success = true;
            break;
        }

        default: {
            uint16_t cb_out_len = 0U;
            if (server->dtc_cb != NULL) {
                if (!server->dtc_cb(sub, &req[2], req_len - 2U, &resp_buf[2], max_resp_len - 2U,
                                    &cb_out_len, server->dtc_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                                  resp_len, addr_mode);
                }
                resp_buf[0] = sid + 0x40U;
                resp_buf[1] = sub;
                *resp_len = 2U + cb_out_len;
                success = true;
            } else {
                return make_negative_response(sid, SYN_UDS_NRC_SUBFUNCTION_NOT_SUPPORTED, resp_buf,
                                              resp_len, addr_mode);
            }
            break;
        }
        }
        break;
    }

    case SYN_UDS_SID_CONTROL_DTC_SETTING: {
        if (req_len < 2U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint8_t sub = req[1] & 0x7FU;
        if (sub != 0x01U && sub != 0x02U) {
            return make_negative_response(sid, SYN_UDS_NRC_SUBFUNCTION_NOT_SUPPORTED, resp_buf,
                                          resp_len, addr_mode);
        }
        resp_buf[0] = sid + 0x40U;
        resp_buf[1] = sub;
        *resp_len = 2U;
        success = true;
        break;
    }

    case SYN_UDS_SID_RESPONSE_ON_EVENT: {
        if (req_len < 2U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint8_t sub = req[1] & 0x7FU;
        if (sub > 0x07U) {
            return make_negative_response(sid, SYN_UDS_NRC_SUBFUNCTION_NOT_SUPPORTED, resp_buf,
                                          resp_len, addr_mode);
        }
        if (server->roe_cb != NULL) {
            uint16_t out_payload_len = 0U;
            if (!server->roe_cb(sub, &req[2], req_len - 2U, &resp_buf[2], max_resp_len - 2U,
                                &out_payload_len, server->roe_ctx)) {
                return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                              resp_len, addr_mode);
            }
            resp_buf[0] = sid + 0x40U;
            resp_buf[1] = sub;
            *resp_len = 2U + out_payload_len;
        } else {
            if (max_resp_len < 4U) {
                /* clang-format off */
                return make_negative_response(sid, SYN_UDS_NRC_RESPONSE_TOO_LONG, resp_buf, resp_len, addr_mode);
                /* clang-format on */
            }
            resp_buf[0] = sid + 0x40U;
            resp_buf[1] = sub;
            if (sub == 0x04U) {
                resp_buf[2] = 0x00U;
                *resp_len = 3U;
            } else {
                resp_buf[2] = 0x00U;
                resp_buf[3] = 0x02U;
                *resp_len = 4U;
            }
        }
        success = true;
        break;
    }

    case SYN_UDS_SID_REQUEST_DOWNLOAD:
    case SYN_UDS_SID_REQUEST_UPLOAD: {
        if (req_len < 3U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint8_t alfid = req[2];
        uint8_t addr_len = alfid & 0x0FU;
        uint8_t size_len = (alfid >> 4U) & 0x0FU;
        if (req_len < (3U + addr_len + size_len)) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        if (server->security_state != SYN_UDS_SECURITY_UNLOCKED) {
            return make_negative_response(sid, SYN_UDS_NRC_SECURITY_ACCESS_DENIED, resp_buf,
                                          resp_len, addr_mode);
        }

        uint32_t addr = 0U;
        for (uint8_t i = 0U; i < addr_len; i++) {
            addr = (addr << 8U) | req[3U + i];
        }

        uint32_t size = 0U;
        for (uint8_t i = 0U; i < size_len; i++) {
            size = (size << 8U) | req[3U + addr_len + i];
        }

        server->transfer_state = (sid == SYN_UDS_SID_REQUEST_DOWNLOAD) ? SYN_UDS_TRANSFER_DOWNLOAD
                                                                       : SYN_UDS_TRANSFER_UPLOAD;
        server->transfer_address = addr;
        server->transfer_size = size;
        server->transfer_bytes_processed = 0U;
        server->expected_block_seq = 1U;

        if (max_resp_len < 4U) {
            return make_negative_response(sid, SYN_UDS_NRC_RESPONSE_TOO_LONG, resp_buf, resp_len,
                                          addr_mode);
        }

        resp_buf[0] = sid + 0x40U;
        resp_buf[1] = 0x20U;
        syn_poke_u16(0x0400U, resp_buf, 2);
        *resp_len = 4U;
        success = true;
        break;
    }

    case SYN_UDS_SID_TRANSFER_DATA: {
        if (req_len < 2U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        if (server->transfer_state == SYN_UDS_TRANSFER_IDLE) {
            return make_negative_response(sid, SYN_UDS_NRC_REQUEST_SEQUENCE_ERROR, resp_buf,
                                          resp_len, addr_mode);
        }

        uint8_t block_seq = req[1];
        if (block_seq == (uint8_t)(server->expected_block_seq - 1U)) {
            /* Repeated block sequence counter -> echo previous response */
            resp_buf[0] = sid + 0x40U;
            resp_buf[1] = block_seq;
            *resp_len = 2U;
            success = true;
            break;
        }

        if (block_seq != server->expected_block_seq) {
            return make_negative_response(sid, SYN_UDS_NRC_WRONG_BLOCK_SEQUENCE_COUNTER, resp_buf,
                                          resp_len, addr_mode);
        }

        if (server->transfer_state == SYN_UDS_TRANSFER_DOWNLOAD) {
            uint16_t payload_len = req_len - 2U;
            if (server->transfer_size > 0U &&
                (server->transfer_bytes_processed + payload_len > server->transfer_size)) {
                return make_negative_response(sid, SYN_UDS_NRC_TRANSFER_DATA_SUSPENDED, resp_buf,
                                              resp_len, addr_mode);
            }
            if (server->memory_cb != NULL) {
                if (!server->memory_cb(true,
                                       server->transfer_address + server->transfer_bytes_processed,
                                       payload_len, (uint8_t *)&req[2], server->memory_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_GENERAL_PROGRAMMING_FAILURE,
                                                  resp_buf, resp_len, addr_mode);
                }
            }
            server->transfer_bytes_processed += payload_len;
            server->expected_block_seq++;
            resp_buf[0] = sid + 0x40U;
            resp_buf[1] = block_seq;
            *resp_len = 2U;
            success = true;
        } else {
            uint16_t chunk_len = 0x03FEU;
            if (server->transfer_size > 0U) {
                uint32_t remaining = server->transfer_size - server->transfer_bytes_processed;
                if (remaining < chunk_len) {
                    chunk_len = (uint16_t)remaining;
                }
            }
            if ((uint32_t)2U + chunk_len > max_resp_len) {
                /* LCOV_EXCL_START: UDS negative response NRC return */
                return make_negative_response(sid, SYN_UDS_NRC_RESPONSE_TOO_LONG, resp_buf,
                                              resp_len, addr_mode);
                /* LCOV_EXCL_STOP */
            }
            if (server->memory_cb != NULL) {
                if (!server->memory_cb(false,
                                       server->transfer_address + server->transfer_bytes_processed,
                                       chunk_len, &resp_buf[2], server->memory_ctx)) {
                    return make_negative_response(sid, SYN_UDS_NRC_GENERAL_PROGRAMMING_FAILURE,
                                                  resp_buf, resp_len, addr_mode);
                }
            }
            server->transfer_bytes_processed += chunk_len;
            server->expected_block_seq++;
            resp_buf[0] = sid + 0x40U;
            resp_buf[1] = block_seq;
            *resp_len = 2U + chunk_len;
            success = true;
        }
        break;
    }

    case SYN_UDS_SID_REQUEST_TRANSFER_EXIT: {
        if (server->transfer_state == SYN_UDS_TRANSFER_IDLE) {
            return make_negative_response(sid, SYN_UDS_NRC_REQUEST_SEQUENCE_ERROR, resp_buf,
                                          resp_len, addr_mode);
        }
        server->transfer_state = SYN_UDS_TRANSFER_IDLE;
        resp_buf[0] = sid + 0x40U;
        *resp_len = 1U;
        success = true;
        break;
    }

    case SYN_UDS_SID_READ_MEMORY_BY_ADDRESS: {
        if (req_len < 3U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        if (server->security_state != SYN_UDS_SECURITY_UNLOCKED) {
            return make_negative_response(sid, SYN_UDS_NRC_SECURITY_ACCESS_DENIED, resp_buf,
                                          resp_len, addr_mode);
        }
        uint8_t alfid = req[1];
        uint8_t addr_len = alfid & 0x0FU;
        uint8_t size_len = (alfid >> 4U) & 0x0FU;
        if (req_len < (2U + addr_len + size_len)) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint32_t address = 0U;
        for (uint8_t i = 0U; i < addr_len && i < 4U; i++) {
            address = (address << 8U) | req[2U + i];
        }
        uint32_t size = 0U;
        for (uint8_t i = 0U; i < size_len && i < 4U; i++) {
            size = (size << 8U) | req[2U + addr_len + i];
        }
        if (max_resp_len < 1U || size > (uint32_t)(max_resp_len - 1U)) {
            return make_negative_response(sid, SYN_UDS_NRC_RESPONSE_TOO_LONG, resp_buf, resp_len,
                                          addr_mode);
        }
        if (server->memory_cb != NULL) {
            if (!server->memory_cb(false, address, size, &resp_buf[1], server->memory_ctx)) {
                return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                              resp_len, addr_mode);
            }
        } else {
            memset(&resp_buf[1], 0, size);
        }
        resp_buf[0] = sid + 0x40U;
        *resp_len = 1U + (uint16_t)size;
        success = true;
        break;
    }

    case SYN_UDS_SID_READ_SCALING_DATA_BY_IDENTIFIER: {
        if (req_len < 3U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint16_t target_did = syn_peek_u16(req, 1);
        int did_idx = find_did_index(server, target_did);
        if (did_idx < 0 && server->scaling_cb == NULL) {
            return make_negative_response(sid, SYN_UDS_NRC_REQUEST_OUT_OF_RANGE, resp_buf, resp_len,
                                          addr_mode);
        }
        resp_buf[0] = sid + 0x40U;
        syn_poke_u16(target_did, resp_buf, 1);
        if (server->scaling_cb != NULL) {
            uint16_t out_payload_len = 0U;
            if (!server->scaling_cb(target_did, &resp_buf[3], max_resp_len - 3U, &out_payload_len,
                                    server->scaling_ctx)) {
                return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                              resp_len, addr_mode);
            }
            *resp_len = 3U + out_payload_len;
        } else {
            resp_buf[3] = 0x01U;
            *resp_len = 4U;
        }
        success = true;
        break;
    }

    case SYN_UDS_SID_AUTHENTICATION: {
        if (req_len < 2U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint8_t sub = req[1] & 0x7FU;
        if (sub > 0x08U) {
            return make_negative_response(sid, SYN_UDS_NRC_SUBFUNCTION_NOT_SUPPORTED, resp_buf,
                                          resp_len, addr_mode);
        }
        uint16_t out_payload_len = 0U;
        if (server->auth_cb != NULL) {
            if (!server->auth_cb(sub, &req[2], req_len - 2U, &resp_buf[2], max_resp_len - 2U,
                                 &out_payload_len, server->auth_ctx)) {
                return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                              resp_len, addr_mode);
            }
        }
        resp_buf[0] = sid + 0x40U;
        resp_buf[1] = sub;
        *resp_len = 2U + out_payload_len;
        success = true;
        break;
    }

    case SYN_UDS_SID_READ_DATA_BY_PERIODIC_IDENTIFIER: {
        if (req_len < 3U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint8_t mode = req[1];
        if (mode < 0x01U || mode > 0x04U) {
            return make_negative_response(sid, SYN_UDS_NRC_REQUEST_OUT_OF_RANGE, resp_buf, resp_len,
                                          addr_mode);
        }
        if (server->periodic_cb != NULL) {
            uint16_t out_payload_len = 0U;
            if (!server->periodic_cb(mode, &req[2], req_len - 2U, &resp_buf[2], max_resp_len - 2U,
                                     &out_payload_len, server->periodic_ctx)) {
                return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                              resp_len, addr_mode);
            }
            resp_buf[0] = sid + 0x40U;
            resp_buf[1] = req[2];
            *resp_len = 2U + out_payload_len;
        } else {
            resp_buf[0] = sid + 0x40U;
            resp_buf[1] = req[2];
            *resp_len = 2U;
        }
        success = true;
        break;
    }

    case SYN_UDS_SID_DYNAMICALLY_DEFINE_DATA_IDENTIFIER: {
        if (req_len < 4U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint8_t sub = req[1] & 0x7FU;
        if (sub < 0x01U || sub > 0x03U) {
            return make_negative_response(sid, SYN_UDS_NRC_SUBFUNCTION_NOT_SUPPORTED, resp_buf,
                                          resp_len, addr_mode);
        }
        uint16_t dyn_did = syn_peek_u16(req, 2);
        if (server->dynamic_did_cb != NULL) {
            uint16_t out_payload_len = 0U;
            if (!server->dynamic_did_cb(sub, dyn_did, &req[4], req_len - 4U, &resp_buf[4],
                                        max_resp_len - 4U, &out_payload_len,
                                        server->dynamic_did_ctx)) {
                return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                              resp_len, addr_mode);
            }
            resp_buf[0] = sid + 0x40U;
            resp_buf[1] = sub;
            syn_poke_u16(dyn_did, resp_buf, 2);
            *resp_len = 4U + out_payload_len;
        } else {
            resp_buf[0] = sid + 0x40U;
            resp_buf[1] = sub;
            syn_poke_u16(dyn_did, resp_buf, 2);
            *resp_len = 4U;
        }
        success = true;
        break;
    }

    case SYN_UDS_SID_INPUT_OUTPUT_CONTROL_BY_IDENTIFIER: {
        if (req_len < 4U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint16_t target_did = syn_peek_u16(req, 1);
        uint8_t control_opt = req[3];
        if (control_opt > 0x03U) {
            return make_negative_response(sid, SYN_UDS_NRC_REQUEST_OUT_OF_RANGE, resp_buf, resp_len,
                                          addr_mode);
        }
        int did_idx = find_did_index(server, target_did);
        if (did_idx < 0 && server->io_control_cb == NULL) {
            return make_negative_response(sid, SYN_UDS_NRC_REQUEST_OUT_OF_RANGE, resp_buf, resp_len,
                                          addr_mode);
        }
        if (server->io_control_cb != NULL) {
            uint16_t out_payload_len = 0U;
            if (!server->io_control_cb(target_did, control_opt, &req[4], req_len - 4U, &resp_buf[4],
                                       max_resp_len - 4U, &out_payload_len,
                                       server->io_control_ctx)) {
                return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                              resp_len, addr_mode);
            }
            resp_buf[0] = sid + 0x40U;
            syn_poke_u16(target_did, resp_buf, 1);
            resp_buf[3] = control_opt;
            *resp_len = 4U + out_payload_len;
        } else {
            resp_buf[0] = sid + 0x40U;
            syn_poke_u16(target_did, resp_buf, 1);
            resp_buf[3] = control_opt;
            *resp_len = 4U;
        }
        success = true;
        break;
    }

    case SYN_UDS_SID_REQUEST_FILE_TRANSFER: {
        if (req_len < 3U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint8_t mode = req[1];
        if (mode < 0x01U || mode > 0x05U) {
            return make_negative_response(sid, SYN_UDS_NRC_REQUEST_OUT_OF_RANGE, resp_buf, resp_len,
                                          addr_mode);
        }
        uint16_t out_len = 0U;
        if (server->file_transfer_cb != NULL) {
            uint16_t path_len = req_len - 2U;
            if (!server->file_transfer_cb(mode, (const char *)&req[2], path_len, &resp_buf[2],
                                          max_resp_len - 2U, &out_len, server->file_transfer_ctx)) {
                return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                              resp_len, addr_mode);
            }
        } else {
            resp_buf[2] = 0x20U;
            syn_poke_u16(0x0400U, resp_buf, 3);
            out_len = 3U;
        }
        resp_buf[0] = sid + 0x40U;
        resp_buf[1] = mode;
        *resp_len = 2U + out_len;
        success = true;
        break;
    }

    case SYN_UDS_SID_WRITE_MEMORY_BY_ADDRESS: {
        if (req_len < 3U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        if (server->security_state != SYN_UDS_SECURITY_UNLOCKED) {
            return make_negative_response(sid, SYN_UDS_NRC_SECURITY_ACCESS_DENIED, resp_buf,
                                          resp_len, addr_mode);
        }
        uint8_t alfid = req[1];
        uint8_t addr_len = alfid & 0x0FU;
        uint8_t size_len = (alfid >> 4U) & 0x0FU;
        if (req_len < (2U + addr_len + size_len)) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint32_t address = 0U;
        for (uint8_t i = 0U; i < addr_len && i < 4U; i++) {
            address = (address << 8U) | req[2U + i];
        }
        uint32_t size = 0U;
        for (uint8_t i = 0U; i < size_len && i < 4U; i++) {
            size = (size << 8U) | req[2U + addr_len + i];
        }
        uint16_t header_len = 2U + addr_len + size_len;
        if (req_len < header_len || size > (uint32_t)(req_len - header_len)) {
            /* LCOV_EXCL_START: UDS negative response NRC return */
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
            /* LCOV_EXCL_STOP */
        }
        if (server->memory_cb != NULL) {
            if (!server->memory_cb(true, address, size, (uint8_t *)&req[header_len],
                                   server->memory_ctx)) {
                return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                              resp_len, addr_mode);
            }
        }
        resp_buf[0] = sid + 0x40U;
        resp_buf[1] = alfid;
        memcpy(&resp_buf[2], &req[2], addr_len + size_len);
        *resp_len = 2U + addr_len + size_len;
        success = true;
        break;
    }

    case SYN_UDS_SID_LINK_CONTROL: {
        if (req_len < 2U) {
            return make_negative_response(sid, SYN_UDS_NRC_INCORRECT_MESSAGE_LENGTH, resp_buf,
                                          resp_len, addr_mode);
        }
        uint8_t sub = req[1] & 0x7FU;
        if (sub < 0x01U || sub > 0x03U) {
            return make_negative_response(sid, SYN_UDS_NRC_SUBFUNCTION_NOT_SUPPORTED, resp_buf,
                                          resp_len, addr_mode);
        }
        if (server->link_control_cb != NULL) {
            uint16_t out_payload_len = 0U;
            if (!server->link_control_cb(sub, &req[2], req_len - 2U, &resp_buf[2],
                                         max_resp_len - 2U, &out_payload_len,
                                         server->link_control_ctx)) {
                return make_negative_response(sid, SYN_UDS_NRC_CONDITIONS_NOT_CORRECT, resp_buf,
                                              resp_len, addr_mode);
            }
            resp_buf[0] = sid + 0x40U;
            resp_buf[1] = sub;
            *resp_len = 2U + out_payload_len;
        } else {
            resp_buf[0] = sid + 0x40U;
            resp_buf[1] = sub;
            *resp_len = 2U;
        }
        success = true;
        break;
    }

    default: {
        return make_negative_response(sid, SYN_UDS_NRC_SERVICE_NOT_SUPPORTED, resp_buf, resp_len,
                                      addr_mode);
    }
    }

    if (success) {
        if (server->session != SYN_UDS_SESSION_DEFAULT) {
            server->s3_timer_ms = SYN_UDS_S3_TIMEOUT_MS;
        }

        /* ISO 14229-1: Suppress positive response if bit 7 (0x80) of sub-function is set */
        if (req_len >= 2U) {
            if ((sid == SYN_UDS_SID_DIAGNOSTIC_SESSION_CONTROL || sid == SYN_UDS_SID_ECU_RESET ||
                 sid == SYN_UDS_SID_SECURITY_ACCESS || sid == SYN_UDS_SID_COMMUNICATION_CONTROL ||
                 sid == SYN_UDS_SID_ROUTINE_CONTROL || sid == SYN_UDS_SID_TESTER_PRESENT ||
                 sid == SYN_UDS_SID_ACCESS_TIMING_PARAMETER ||
                 sid == SYN_UDS_SID_CONTROL_DTC_SETTING || sid == SYN_UDS_SID_RESPONSE_ON_EVENT ||
                 sid == SYN_UDS_SID_LINK_CONTROL) &&
                ((req[1] & 0x80U) != 0U)) {
                *resp_len = 0U;
            }
        }
    }

    return true;
}

bool syn_uds_dtc_report_test_result(SYN_UDS_Server *server, uint32_t dtc, bool failed)
{
    if (server == NULL) {
        return false;
    }

    for (uint8_t i = 0U; i < server->dtc_count; i++) {
        if (server->dtc_table[i].dtc == dtc) {
            uint8_t status = server->dtc_table[i].status;

            if (failed) {
                status |= (uint8_t)SYN_UDS_DTC_STATUS_TEST_FAILED;
                status |= (uint8_t)SYN_UDS_DTC_STATUS_TEST_FAILED_THIS_OP_CYCLE;
                status |= (uint8_t)SYN_UDS_DTC_STATUS_PENDING_DTC;
                status |= (uint8_t)SYN_UDS_DTC_STATUS_CONFIRMED_DTC;
                status |= (uint8_t)SYN_UDS_DTC_STATUS_TEST_FAILED_SINCE_LAST_CLEAR;
                status &= (uint8_t)~(uint8_t)SYN_UDS_DTC_STATUS_TEST_NOT_COMPLETED_SINCE_LAST_CLEAR;
                status &= (uint8_t)~(uint8_t)SYN_UDS_DTC_STATUS_TEST_NOT_COMPLETED_THIS_OP_CYCLE;

                if (server->dtc_table[i].fault_cnt < 127) {
                    server->dtc_table[i].fault_cnt++;
                }
            } else {
                status &= (uint8_t)~(uint8_t)SYN_UDS_DTC_STATUS_TEST_FAILED;
                status &= (uint8_t)~(uint8_t)SYN_UDS_DTC_STATUS_TEST_NOT_COMPLETED_SINCE_LAST_CLEAR;
                status &= (uint8_t)~(uint8_t)SYN_UDS_DTC_STATUS_TEST_NOT_COMPLETED_THIS_OP_CYCLE;

                if (server->dtc_table[i].fault_cnt > -128) {
                    server->dtc_table[i].fault_cnt--;
                }
            }

            server->dtc_table[i].status = status;
            return true;
        }
    }

    return false;
}

bool syn_uds_dtc_start_operation_cycle(SYN_UDS_Server *server)
{
    if (server == NULL) {
        return false;
    }

    for (uint8_t i = 0U; i < server->dtc_count; i++) {
        uint8_t status = server->dtc_table[i].status;
        status &= (uint8_t)~(uint8_t)SYN_UDS_DTC_STATUS_TEST_FAILED_THIS_OP_CYCLE;
        status |= (uint8_t)SYN_UDS_DTC_STATUS_TEST_NOT_COMPLETED_THIS_OP_CYCLE;
        server->dtc_table[i].status = status;
    }

    return true;
}

bool syn_uds_dtc_get_status(SYN_UDS_Server *server, uint32_t dtc, uint8_t *out_status)
{
    if (server == NULL || out_status == NULL) {
        return false;
    }

    for (uint8_t i = 0U; i < server->dtc_count; i++) {
        if (server->dtc_table[i].dtc == dtc) {
            *out_status = server->dtc_table[i].status;
            return true;
        }
    }

    return false;
}

uint8_t syn_uds_get_security_level(const SYN_UDS_Server *server)
{
    if (server == NULL || server->security_state != SYN_UDS_SECURITY_UNLOCKED) {
        return 0U;
    }
    return server->security_level;
}