/*********************************************************************************************************************** * FILE DESCRIPTION * ------------------------------------------------------------------------------------------------------------------*/ /** \file * \brief Diagnostic services supported in boot mode * Declaration of functions, variables and constants * * -------------------------------------------------------------------------------------------------------------------- * COPYRIGHT * -------------------------------------------------------------------------------------------------------------------- * \par Copyright * \verbatim * Copyright (c) 2026 by Vector Informatik GmbH. All rights reserved. * * This software is copyright protected and proprietary to Vector Informatik GmbH. * Vector Informatik GmbH grants to you only those rights as set out in the license conditions. * All other rights remain with Vector Informatik GmbH. * \endverbatim */ /**********************************************************************************************************************/ /*********************************************************************************************************************** * REVISION HISTORY * -------------------------------------------------------------------------------------------------------------------- * Version Date Author Change Id Description * -------------------------------------------------------------------------------------------------------------------- * 05.00.00 2022-08-15 vistmo FBL-5514 Support Additional OTA functionality * ESCAN00112435 The verification of the flash driver always fails * ESCAN00112575 Ford tokens are wrongly rejected * 05.01.00 2022-10-04 jschmitding FBL-5917 Make FBL SWDL 008 Compliant * ESCAN00113919 No changes * 05.01.01 2022-10-17 fmenke ESCAN00112879 Routine Check Application Validity is failing * 05.01.02 2023-01-13 fmenke ESCAN00112890 DID D071 does not return the last successful token received * ESCAN00113612 Server message ID check does not work correctly * 05.02.00 2023-02-09 vistmo ESCAN00112972 Token with reserved bits set in SyncP is accepted * ESCAN00113292 Wrong NRC for invalid RoutineControlOptionRecord on Set OTA Update * ESCAN00113835 For token mode 5 reprogrammable keys are not extracted correctly * ESCAN00113843 Token with "Has Key ID" bit set in SyncP is accepted * ESCAN00113764 RID 7013 (token download) is always supported * FBL-6438 No changes * 05.02.01 2023-05-11 fmenke ESCAN00113831 Application validation fails in case of MAC update failure * regardless logical block is optional or mandatory * 05.03.00 2023-07-24 fmenke FBL-7335 Support new app signing handling * 05.03.01 2023-08-31 lhopfhauer ESCAN00115494 Bootloader does not enter programming session when * started from application * 05.03.02 2024-07-16 erizk ESCAN00117344 Compiler error: FblRealTimeSupportVoid undefined, assuming * extern returning int * 05.03.03 2025-02-06 virchl ESCAN00118587 No Response for the Routine Control "Check Valid Application" 0x0304 * 05.04.00 2025-02-28 jjohnson FBL-10065 Support App Signing Specification 2.1.3 * 05.04.01 2025-06-10 jostravsky ESCAN00120315 Response to programming session request may be wrong * 05.04.02 2025-07-08 visarcmijo ESCAN00119833 No NRC is returned to an RID 7013 requested without SBL activation * 05.05.00 2025-09-01 fmenke FBL-11218 Add support for NXP DSP firmware update * ESCAN00120917 SBL can be downloaded again and be executed without * signature verification * 05.06.00 2025-10-28 mpatil FBL-11690 Adding hooks and return values for callouts for Routine 7013 * 05.07.00 2026-01-13 dganesh FBL-12162 Support Ford SWDL 008.5 **********************************************************************************************************************/ #define FBL_DIAG_SOURCE /*********************************************************************************************************************** * INCLUDES **********************************************************************************************************************/ #include "fbl_inc.h" /* Common include files */ #include "fbl_diag.h" /*********************************************************************************************************************** * VERSION **********************************************************************************************************************/ #if ( FBLDIAG_14229_FORD_VERSION != 0x0507u ) || \ ( FBLDIAG_14229_FORD_RELEASE_VERSION != 0x00u ) # error "Error in fbl_diag.c: Source and header file are inconsistent!" #endif #if ( FBLDIAG_14229_FORD_VERSION != _FBLDIAG_OEM_VERSION ) || \ ( FBLDIAG_14229_FORD_RELEASE_VERSION != _FBLDIAG_OEM_RELEASE_VERSION ) # error "Error in fbl_diag.c: Source and v_ver.h are inconsistent!" #endif /*********************************************************************************************************************** * DEFINES **********************************************************************************************************************/ #define FBL_DIAG_IMPL_TYPE_OUTPUT 1 #define FBL_DIAG_IMPL_TYPE_STATEBITMAP 2 #define FBL_DIAG_IMPL_TYPE_SERVICEPROPERTY 3 #define FBL_DIAG_IMPL_TYPE_SERVICELIST 4 #define FBL_DIAG_IMPL_TYPE_SERVICELIST_HANDLER 5 #define FBL_DIAG_IMPL_TYPE_SERVICELIST_ENUM 6 #define kDiagInitSequenceNum ((vuint8) 0x01u) #define kDiagSegmentOutOfRange ((vuint8) 0xFFu) #define kDiagSubparamMask ((vuint8) 0x7Fu) /* Transfer types (used with transferType) */ # define DOWNLOAD_RAM ((vuint8) 0x10u) # define DOWNLOAD_FLASH ((vuint8) 0x40u) /* Allow external definition of RAM state table usage */ #if defined( FBL_DIAG_ENABLE_RAM_STATETABLES ) || \ defined( FBL_DIAG_DISABLE_RAM_STATETABLES ) #else # define FBL_DIAG_ENABLE_RAM_STATETABLES #endif #define FBL_DIAG_STATE_ARRAYS #if defined( FBL_DIAG_ENABLE_RAM_STATETABLES ) # define FBL_DIAG_SERVICE_LIST_HANDLES #endif #define FBL_DIAG_CHECK_LIST_HANDLES /* Maximum wait time for ECU reset request */ #if !defined( kCwMaxWaitTimeEcuResetRequest ) # define kFblDiagMaxWaitTimeEcuResetRequest kFblDiagTimeP2Star #else # define kFblDiagMaxWaitTimeEcuResetRequest (kCwMaxWaitTimeEcuResetRequest / FBL_REPEAT_CALL_CYCLE) #endif /* Macros to access the ecuReset timer value */ #define TimeoutEcuResetValue() ecuResetTimeout #define DecTimeoutEcuResetValue() (ecuResetTimeout--) #define ResetEcuResetTimeout() (ecuResetTimeout = (vuint16)(kFblDiagMaxWaitTimeEcuResetRequest/DIAG_CALL_CYCLE)) #define StopEcuResetTimeout() (ecuResetTimeout = 0) #if defined( FBL_DIAG_ENABLE_SESSION_PARAMETERS ) /* * Negative return value for FblDiagGetSessionIndex(). This value has to be greater than 0x7F because the SPRMIB bit * restricts the value range. */ # define kDiagSessionNotFound ((vuint8)0xFFu) #endif /* FBL_DIAG_ENABLE_SESSION_PARAMETERS */ #if defined( FBL_ENABLE_SEC_ADDITIONAL_LEVELS ) /* Indicator for non-initialized security level index */ # define kDiagInvalidSecLvlIdx ((vuint8)0xFFu) #endif /* FBL_ENABLE_SEC_ADDITIONAL_LEVELS */ /* Return values for DID 0xD021 - Current Diagnostic Application */ #define kFblDiagAppPbl 0x01u #define kFblDiagAppSbl 0x02u #define kFblDiagAppUnknown 0xFFu #if ( SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC ) /* Define for customer for getting FESN */ # if !defined( FblDiagGetFesn ) # define FblDiagGetFesn() fblCommonData.FordElectronicSerialNumber # endif /* Dynamic offset calculation macro */ # define FblDiagCalcDynamicSyncPHeaderOffset(offset) ((offset) - FBL_DIAG_TOKEN_FESN_LEN) /* Defines for token parameter offset */ # if defined( FBL_ENABLE_TOKEN_DOWNLOAD_HANDLING ) # define FBL_DIAG_TOKEN_PARAM_SYNCP_ENC_DATA_OFFSET 0u # define FBL_DIAG_TOKEN_PARAM_CPU_DEST_OFFSET 1u # define FBL_DIAG_TOKEN_PARAM_SERVICE_TYPE_OFFSET 2u # define FBL_DIAG_TOKEN_PARAM_CRYPTOTYPE_OFFSET 6u # define FBL_DIAG_TOKEN_PARAM_PAYLOAD_SIZE_OFFSET 7u # define FBL_DIAG_TOKEN_PARAM_FESN_OFFSET 11u # define FBL_DIAG_TOKEN_PARAM_SERVERMESSAGEID_OFFSET(token) FblDiagIsTokenFesnRequired(token) ? 27u : FblDiagCalcDynamicSyncPHeaderOffset(27u) # define FBL_DIAG_TOKEN_PARAM_CMD_OFFSET(token) FblDiagIsTokenFesnRequired(token) ? 35u : FblDiagCalcDynamicSyncPHeaderOffset(35u) # define FBL_DIAG_TOKEN_PARAM_KEY_INDEX_OFFSET(token) FblDiagIsTokenFesnRequired(token) ? 36u : FblDiagCalcDynamicSyncPHeaderOffset(36u) # define FBL_DIAG_TOKEN_PARAM_NAME_LENGTH_INDEX_OFFSET(token) FblDiagIsTokenFesnRequired(token) ? 37u : FblDiagCalcDynamicSyncPHeaderOffset(37u) # define FBL_DIAG_TOKEN_PARAM_NAME_INDEX_OFFSET(token) FblDiagIsTokenFesnRequired(token) ? 38u : FblDiagCalcDynamicSyncPHeaderOffset(38u) # define FBL_DIAG_TOKEN_PARAM_PAYLOAD_FESN_OFFSET(token) FblDiagIsTokenFesnRequired(token) ? 80u : FblDiagCalcDynamicSyncPHeaderOffset(80u) # define FBL_DIAG_TOKEN_PARAM_DEVKEY_OFFSET(token) FblDiagIsTokenFesnRequired(token) ? 107u : FblDiagCalcDynamicSyncPHeaderOffset(107u) # define FBL_DIAG_TOKEN_PARAM_PRODKEY_OFFSET(token) FblDiagIsTokenFesnRequired(token) ? 619u : FblDiagCalcDynamicSyncPHeaderOffset(619u) # define FBL_DIAG_TOKEN_PARAM_TOKENKEY_OFFSET(token) FblDiagIsTokenFesnRequired(token) ? 1131u : FblDiagCalcDynamicSyncPHeaderOffset(1131u) /* Generic Defines for token handling */ # define FBL_DIAG_TOKEN_RESBITS_REQ 0x03u # define FBL_DIAG_TOKEN_KEYID_REQ 0x04u # define FBL_DIAG_TOKEN_FESN_REQ 0x08u # define FBL_DIAG_TOKEN_FESN_SHIFT 0x03u # define FBL_DIAG_TOKEN_FESN_LEN 8u # define FBL_DIAG_TOKEN_MSGID_REQ 0x10u # define FBL_DIAG_TOKEN_MOD5_FESN_LEN 3u # define FBL_DIAG_TOKEN_CPU_DEST 0u # define FBL_DIAG_TOKEN_PROTOCOL_VERSION 0x20u # define FBL_DIAG_TOKEN_PROTOCOL_VERSION_MASK 0xE0u # define FBL_DIAG_TOKEN_NAME_LENGTH 0x0Bu # define FBL_DIAG_TOKEN_NAME "APP_SIGN_SW" # define FBL_DIAG_TOKEN_SERVICE_TYPE 0x110u # define FBL_DIAG_TOKEN_CRYPTOTYPE 0x0Fu /* Only RSA supported */ # define FBL_DIAG_TOKEN_PAYLOAD_SIZE_MODE0_4 43u # define FBL_DIAG_TOKEN_PAYLOAD_SIZE_MODE5 1606u # define FBL_DIAG_TOKEN_KEY_INDEX_0 0u /* Used for mode 5 tokens */ # define FBL_DIAG_TOKEN_KEY_INDEX_1 1u /* Used for mode 0-4 tokens */ # define FBL_DIAG_TOKEN_KEY_EXP_MAX 256u /* Defines Token Handling Commands */ # define FBL_DIAG_TOKEN_CMD_REVERTPROD 0u # define FBL_DIAG_TOKEN_CMD_USEDEVPERM 1u # define FBL_DIAG_TOKEN_CMD_USEDEVTEMP 2u # define FBL_DIAG_TOKEN_CMD_USEDEVDATE 3u # define FBL_DIAG_TOKEN_CMD_USEDEVIGNI 4u # define FBL_DIAG_TOKEN_CMD_PROGKEY 5u /* Defines Token Handling Macro */ # define FblDiagIsTokenProtocolVersionCorrect(token) (((token)[FBL_DIAG_TOKEN_PARAM_SYNCP_ENC_DATA_OFFSET] & FBL_DIAG_TOKEN_PROTOCOL_VERSION_MASK) == FBL_DIAG_TOKEN_PROTOCOL_VERSION) # define FblDiagIsTokenKeyIDRequired(token) (((token)[FBL_DIAG_TOKEN_PARAM_SYNCP_ENC_DATA_OFFSET] & FBL_DIAG_TOKEN_KEYID_REQ) == FBL_DIAG_TOKEN_KEYID_REQ) # define FblDiagIsTokenMsgIDRequired(token) (((token)[FBL_DIAG_TOKEN_PARAM_SYNCP_ENC_DATA_OFFSET] & FBL_DIAG_TOKEN_MSGID_REQ) == FBL_DIAG_TOKEN_MSGID_REQ) # define FblDiagIsTokenFesnRequired(token) (((token)[FBL_DIAG_TOKEN_PARAM_SYNCP_ENC_DATA_OFFSET] & FBL_DIAG_TOKEN_FESN_REQ) == FBL_DIAG_TOKEN_FESN_REQ) # define FblDiagIsTokenReserverdBitsSet(token) (((token)[FBL_DIAG_TOKEN_PARAM_SYNCP_ENC_DATA_OFFSET] & FBL_DIAG_TOKEN_RESBITS_REQ) != 0u) # define FblDiagGetTokenCPUDestination(token) ((token)[FBL_DIAG_TOKEN_PARAM_CPU_DEST_OFFSET]) # define FblDiagGetTokenServiceType(token) (((vuint16)(token)[FBL_DIAG_TOKEN_PARAM_SERVICE_TYPE_OFFSET] << 8u) | \ (vuint16)(token)[FBL_DIAG_TOKEN_PARAM_SERVICE_TYPE_OFFSET + 1u] ) # define FblDiagGetTokenCryptoType(token) ((token)[FBL_DIAG_TOKEN_PARAM_CRYPTOTYPE_OFFSET]) # define FblDiagGetTokenCommandType(token) ((token)[FBL_DIAG_TOKEN_PARAM_CMD_OFFSET(token)]) # define FblDiagGetTokenPayloadSize(token) (((vuint32)(token)[FBL_DIAG_TOKEN_PARAM_PAYLOAD_SIZE_OFFSET] << 24u) | \ ((vuint32)(token)[FBL_DIAG_TOKEN_PARAM_PAYLOAD_SIZE_OFFSET + 1u] << 16u) | \ ((vuint32)(token)[FBL_DIAG_TOKEN_PARAM_PAYLOAD_SIZE_OFFSET + 2u] << 8u) | \ (vuint32)(token)[FBL_DIAG_TOKEN_PARAM_PAYLOAD_SIZE_OFFSET + 3u]) # define FblDiagGetTokenTokenNameLength(token) ((vuint8)(token)[FBL_DIAG_TOKEN_PARAM_NAME_LENGTH_INDEX_OFFSET(token)]) # define FblDiagGetTokenTokenName(token) (&(token)[FBL_DIAG_TOKEN_PARAM_NAME_INDEX_OFFSET(token)]) # define FblDiagGetTokenFesn(token) (&(token)[FBL_DIAG_TOKEN_PARAM_FESN_OFFSET]) # define FblDiagGetTokenServerMsgIdPtr(token) (&(token)[FBL_DIAG_TOKEN_PARAM_SERVERMESSAGEID_OFFSET(token)]) # define FblDiagGetTokenPayloadFesn(token) (&(token)[FBL_DIAG_TOKEN_PARAM_PAYLOAD_FESN_OFFSET(token)]) # define FblDiagGetTokenKeyIndex(token) ((token)[FBL_DIAG_TOKEN_PARAM_KEY_INDEX_OFFSET(token)]) /* Define to get the key index from the token */ # define FblDiagGetTokenDevKeyIndex(token) (&(token)[FBL_DIAG_TOKEN_PARAM_DEVKEY_OFFSET(token)]) # define FblDiagGetTokenProdKeyIndex(token) (&(token)[FBL_DIAG_TOKEN_PARAM_PRODKEY_OFFSET(token)]) # define FblDiagGetTokenTokenKeyIndex(token) (&(token)[FBL_DIAG_TOKEN_PARAM_TOKENKEY_OFFSET(token)]) # endif /* FBL_ENABLE_TOKEN_DOWNLOAD_HANDLING */ #endif /* SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC */ /*****************************************************************************/ /* State handling ************************************************************/ /*****************************************************************************/ #define SPLIT_SHORT(id) ((vuint8)(((id) >> 8u) & 0xFFu)), ((vuint8)((id) & 0xFFu)) # define STATE_CHECK_COUNT 2u # define STATE_ADDCLR_COUNT 3u #define STATE_COUNT (STATE_CHECK_COUNT + STATE_ADDCLR_COUNT) /* State array build macros */ #define STATE_ARRAYENTRY(mask, idx) ((tStateBitmap)(((mask) >> ((idx) * STATE_BITS)) & kDiagStateMaskAll)) #if ( STATECHECK_ARRAYSIZE == 1u ) # define STATE_BUILDARRAYENTRIES(mask) STATE_ARRAYENTRY(mask, 0u) #endif #if ( STATECHECK_ARRAYSIZE == 2u ) # define STATE_BUILDARRAYENTRIES(mask) STATE_ARRAYENTRY(mask, 0u), STATE_ARRAYENTRY(mask, 1u) #endif #if ( STATECHECK_ARRAYSIZE == 3u ) # define STATE_BUILDARRAYENTRIES(mask) STATE_ARRAYENTRY(mask, 0u), STATE_ARRAYENTRY(mask, 1u), STATE_ARRAYENTRY(mask, 2u) #endif #if ( STATECHECK_ARRAYSIZE == 4u ) # define STATE_BUILDARRAYENTRIES(mask) STATE_ARRAYENTRY(mask, 0u), STATE_ARRAYENTRY(mask, 1u), STATE_ARRAYENTRY(mask, 2u), STATE_ARRAYENTRY(mask, 3u) #endif #if ( STATECHECK_ARRAYSIZE > 4u ) # error "Invalid array size for state check!" #endif #define STATE_BUILDARRAY(mask) { STATE_BUILDARRAYENTRIES(mask) } /* State masks and access macros */ #define kDiagStateMaskAllLong STATE_MULTIMASKLONG(0u, ((STATECHECK_ARRAYSIZE * STATE_BITS) - 1u)) #define kDiagStateMask(state) STATE_MASKLONG(state) #define SetDiagState(state) STATE_SET(fblStates, state) #define ClrDiagState(state) STATE_CLR(fblStates, state) #define kDiagStateNone (0x00uL) #define ClrDiagSession() STATE_MULTICLR(fblStates, kDiagStateIdxSessionDefault, kDiagStateIdxSessionProgramming) #define kDiagStateSessionDefault kDiagStateMask(kDiagStateIdxSessionDefault) #define SetDiagDefaultDiagSession() { \ ClrDiagSession(); \ SetDiagState(kDiagStateIdxSessionDefault); \ SetDiagSessionType(kDiagSubDefaultSession); \ } #define kDiagStateSessionProgramming kDiagStateMask(kDiagStateIdxSessionProgramming) #define SetDiagProgrammingSession() { \ ClrDiagSession(); \ SetDiagState(kDiagStateIdxSessionProgramming); \ SetDiagSessionType(kDiagSubProgrammingSession); \ } #define kDiagStateSessionDefaultProgramming (kDiagStateSessionDefault | kDiagStateSessionProgramming) #define kDiagStateSessionAll kDiagStateSessionDefaultProgramming #define kDiagStateSecurityKey01 kDiagStateMask(kDiagStateIdxSecurityKey01) #define GetSecurityKeyAllowed() GetDiagState(kDiagStateIdxSecurityKey01) #define SetSecurityKeyAllowed() SetDiagState(kDiagStateIdxSecurityKey01) #define ClrSecurityKeyAllowed() ClrDiagState(kDiagStateIdxSecurityKey01) #define kDiagStateSecurityKeyAll (kDiagStateSecurityKey01) #define kDiagStateSecurityAccess01 kDiagStateMask(kDiagStateIdxSecurityAccess01) #define GetSecurityAccess01() GetDiagState(kDiagStateIdxSecurityAccess01) #define SetSecurityAccess01() SetDiagState(kDiagStateIdxSecurityAccess01) #define ClrSecurityAccess01() ClrDiagState(kDiagStateIdxSecurityAccess01) #define SetCurrentSecLvl(secLvl) diagCurrentSecLvl = (secLvl) #define kDiagStateSecurityAccessAll (kDiagStateSecurityAccess01) /* Security access states are used in state machine definition */ #define kDiagStateSecurityAccessDelay01 kDiagStateNone #define kDiagStateSecurityAccessDelayAll (kDiagStateSecurityAccessDelay01) #if !defined( FBL_ENABLE_SEC_ADDITIONAL_LEVELS ) # define kServiceCheckListSubFctSecCheck kServiceCheckListSubFctCheck #endif #define kDiagStateFunctionalRequest kDiagStateMask(kDiagStateIdxFunctionalRequest) #define GetFunctionalRequest() GetDiagState(kDiagStateIdxFunctionalRequest) #define SetFunctionalRequest() SetDiagState(kDiagStateIdxFunctionalRequest) #define ClrFunctionalRequest() ClrDiagState(kDiagStateIdxFunctionalRequest) #define kDiagStateServiceInProgress kDiagStateMask(kDiagStateIdxServiceInProgress) #define SetServiceInProgress() SetDiagState(kDiagStateIdxServiceInProgress) #define ClrServiceInProgress() ClrDiagState(kDiagStateIdxServiceInProgress) #define kDiagStateTpConfirmationFlag kDiagStateMask(kDiagStateIdxTpConfirmationFlag) #define GetTpConfirmationFlag() GetDiagState(kDiagStateIdxTpConfirmationFlag) #define SetTpConfirmationFlag() SetDiagState(kDiagStateIdxTpConfirmationFlag) #define ClrTpConfirmationFlag() ClrDiagState(kDiagStateIdxTpConfirmationFlag) #define kDiagStateDiagIndication kDiagStateMask(kDiagStateIdxDiagIndication) #define GetDiagIndication() GetDiagState(kDiagStateIdxDiagIndication) #define SetDiagIndication() SetDiagState(kDiagStateIdxDiagIndication) #define ClrDiagIndication() ClrDiagState(kDiagStateIdxDiagIndication) #define kDiagStateSuppressPosRspMsg kDiagStateMask(kDiagStateIdxSuppressPosRspMsg) #define GetSuppressPosRspMsg() GetDiagState(kDiagStateIdxSuppressPosRspMsg) #define SetSuppressPosRspMsg() SetDiagState(kDiagStateIdxSuppressPosRspMsg) #define ClrSuppressPosRspMsg() ClrDiagState(kDiagStateIdxSuppressPosRspMsg) #define kDiagStateResponseProcessing kDiagStateMask(kDiagStateIdxResponseProcessing) #define SetResponseProcessing() SetDiagState(kDiagStateIdxResponseProcessing) #define ClrResponseProcessing() ClrDiagState(kDiagStateIdxResponseProcessing) #define kDiagStateRcrRpInProgress kDiagStateMask(kDiagStateIdxRcrRpInProgress) #define SetRcrRpInProgress() SetDiagState(kDiagStateIdxRcrRpInProgress) #define ClrRcrRpInProgress() ClrDiagState(kDiagStateIdxRcrRpInProgress) #define kDiagStateWaitForRcrRpConf kDiagStateMask(kDiagStateIdxWaitForRcrRpConf) #define GetWaitForRcrRpConf() GetDiagState(kDiagStateIdxWaitForRcrRpConf) #define SetWaitForRcrRpConf() SetDiagState(kDiagStateIdxWaitForRcrRpConf) #define ClrWaitForRcrRpConf() ClrDiagState(kDiagStateIdxWaitForRcrRpConf) #define kDiagStateMemDriverInitialized kDiagStateMask(kDiagStateIdxMemDriverInitialized) #define SetMemDriverInitialized() SetDiagState(kDiagStateIdxMemDriverInitialized) #define ClrMemDriverInitialized() ClrDiagState(kDiagStateIdxMemDriverInitialized) #define kDiagStateTransferDataAllowed kDiagStateMask(kDiagStateIdxTransferDataAllowed) #define GetTransferDataAllowed() GetDiagState(kDiagStateIdxTransferDataAllowed) #define SetTransferDataAllowed() SetDiagState(kDiagStateIdxTransferDataAllowed) #define ClrTransferDataAllowed() ClrDiagState(kDiagStateIdxTransferDataAllowed) #define kDiagStateTransferDataSucceeded kDiagStateMask(kDiagStateIdxTransferDataSucceeded) #define GetTransferDataSucceeded() GetDiagState(kDiagStateIdxTransferDataSucceeded) #define SetTransferDataSucceeded() SetDiagState(kDiagStateIdxTransferDataSucceeded) #define ClrTransferDataSucceeded() ClrDiagState(kDiagStateIdxTransferDataSucceeded) #define kDiagStateFirstDownloadReq kDiagStateMask(kDiagStateIdxFirstDownloadReq) #define GetFirstDownloadReq() GetDiagState(kDiagStateIdxFirstDownloadReq) #define SetFirstDownloadReq() SetDiagState(kDiagStateIdxFirstDownloadReq) #define ClrFirstDownloadReq() ClrDiagState(kDiagStateIdxFirstDownloadReq) #define kDiagStateEraseMemorySucceeded kDiagStateMask(kDiagStateIdxEraseMemorySucceeded) #define GetEraseMemorySucceeded() GetDiagState(kDiagStateIdxEraseMemorySucceeded) #define SetEraseMemorySucceeded() SetDiagState(kDiagStateIdxEraseMemorySucceeded) #define ClrEraseMemorySucceeded() ClrDiagState(kDiagStateIdxEraseMemorySucceeded) #if defined( FBL_DIAG_ENABLE_UPLOAD ) #define kDiagStateTransferDataUpload kDiagStateMask(kDiagStateIdxTransferDataUpload) #define GetTransferDataUpload() GetDiagState(kDiagStateIdxTransferDataUpload) #define SetTransferDataUpload() SetDiagState(kDiagStateIdxTransferDataUpload) #define ClrTransferDataUpload() ClrDiagState(kDiagStateIdxTransferDataUpload) #endif /* FBL_DIAG_ENABLE_UPLOAD */ #define kDiagStateResetMsgConfirmed kDiagStateMask(kDiagStateIdxResetMsgConfirmed) #define GetResetMsgConfirmed() GetDiagState(kDiagStateIdxResetMsgConfirmed) #define SetResetMsgConfirmed() SetDiagState(kDiagStateIdxResetMsgConfirmed) #define ClrResetMsgConfirmed() ClrDiagState(kDiagStateIdxResetMsgConfirmed) #define kDiagStateEcuResetFctFinished kDiagStateMask(kDiagStateIdxEcuResetFctFinished) #define GetEcuResetFctFinished() GetDiagState(kDiagStateIdxEcuResetFctFinished) #define SetEcuResetFctFinished() SetDiagState(kDiagStateIdxEcuResetFctFinished) #define ClrEcuResetFctFinished() ClrDiagState(kDiagStateIdxEcuResetFctFinished) #define kDiagStateWaitEcuReset kDiagStateMask(kDiagStateIdxWaitEcuReset) #define SetWaitEcuReset() { \ SetDiagState(kDiagStateIdxWaitEcuReset); \ ResetEcuResetTimeout(); \ } #define ClrWaitEcuReset() { \ ClrDiagState(kDiagStateWaitEcuReset); \ ClrDiagState(kDiagStateResetMsgConfirmed); \ ClrDiagState(kDiagStateEcuResetFctFinished); \ StopEcuResetTimeout(); \ } #define kDiagStateDiagBufferLocked kDiagStateMask(kDiagStateIdxDiagBufferLocked) #define SetDiagBufferLocked() SetDiagState(kDiagStateIdxDiagBufferLocked) #define ClrDiagBufferLocked() ClrDiagState(kDiagStateIdxDiagBufferLocked) #if ( SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC ) # define kDiagStateDiagDevelopmentKey kDiagStateMask(kDiagStateIdxDiagDevelopmentKey) # define SetDiagDevelopmentKey() SetDiagState(kDiagStateIdxDiagDevelopmentKey) # define ClrDiagDevelopmentKey() ClrDiagState(kDiagStateIdxDiagDevelopmentKey) #endif #define kDiagStateProcessingDone kDiagStateMask(kDiagStateIdxProcessingDone) #define GetProcessingDone() GetDiagState(kDiagStateIdxProcessingDone) #define SetProcessingDone() SetDiagState(kDiagStateIdxProcessingDone) #define ClrProcessingDone() ClrDiagState(kDiagStateIdxProcessingDone) #define kDiagStateLockedByInit kDiagStateMask(kDiagStateIdxLockedByInit) #define GetLockedByInit() GetDiagState(kDiagStateIdxLockedByInit) #define SetLockedByInit() SetDiagState(kDiagStateIdxLockedByInit) #define ClrLockedByInit() ClrDiagState(kDiagStateIdxLockedByInit) #if defined( FBL_DIAG_ENABLE_SESSION_PARAMETERS ) # define SetDiagSessionType(type) (currentDiagSessionIndex = FblDiagGetSessionIndex(type)) # define GetDiagSessionType() (kDiagSessionParameters[currentDiagSessionIndex].sessionType) # define GetDiagSessionTimingP2() (kDiagSessionParameters[currentDiagSessionIndex].p2Timing) # define GetDiagSessionTimingP2Star() (kDiagSessionParameters[currentDiagSessionIndex].p2StarTiming) #else # define SetDiagSessionType(type) (currentDiagSessionType = (type)) # define GetDiagSessionType() (currentDiagSessionType) # define GetDiagSessionTimingP2() (kDiagSessionTimingP2) # define GetDiagSessionTimingP2Star() (kDiagSessionTimingP2Star) #endif /* FBL_DIAG_ENABLE_SESSION_PARAMETERS */ /* Helper macro to get number of array entries */ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /*****************************************************************************/ /* Definitions for the state machine *****************************************/ /*****************************************************************************/ #define kDiagRqlUnlimited (0xFFFFu) #define kDiagNoSubServices (V_MEMROM1 tServiceList V_MEMROM2 V_MEMROM3 *)V_NULL #define kDiagNoCheckList (tServiceCheckList *)V_NULL #define kDiagNoServiceProp (ptServiceProp)V_NULL /* Typedefs and structures for internal use **********************************/ /* State machine */ #if defined( FBL_DIAG_ENABLE_RAM_STATETABLES ) typedef V_MEMRAM1 struct tagServiceProp V_MEMRAM2 V_MEMRAM3 * ptServiceProp; #else typedef V_MEMROM1 struct tagServiceProp V_MEMROM2 V_MEMROM3 * ptServiceProp; #endif typedef struct tagServiceCheck { vuint8 checkHandlerIdx; vuint8 NRC; vuint8 errorHandlerIdx; } tServiceCheck; typedef struct { V_MEMROM1 struct tagServiceCheck V_MEMROM2 V_MEMROM3 * list; vuint8 count; } tServiceCheckList; typedef struct tagServiceList { ptServiceProp list; tCwDataLengthType bufPos; vuint8 idSize; vuint8 count; } tServiceList; #if defined( FBL_DIAG_STATE_ARRAYS ) # define FBL_DIAG_STATE_SET 0 # define FBL_DIAG_STATE_UNSET 1 # define FBL_DIAG_STATE_ADD 2 # define FBL_DIAG_STATE_CLR 3 # define FBL_DIAG_STATE_CLRFAIL 4 # define stateSet states[FBL_DIAG_STATE_SET] # define stateUnset states[FBL_DIAG_STATE_UNSET] # define stateAdd states[FBL_DIAG_STATE_ADD] # define stateClr states[FBL_DIAG_STATE_CLR] # define stateClrFail states[FBL_DIAG_STATE_CLRFAIL] #endif typedef struct tagServiceProp { V_MEMROM1 struct tagServiceList V_MEMROM2 V_MEMROM3 * subServices; V_MEMROM1 vuint8 V_MEMROM2 V_MEMROM3 * serviceId; #if defined( FBL_DIAG_CHECK_LIST_HANDLES ) #else V_MEMROM1 tServiceCheckList V_MEMROM2 V_MEMROM3 * checks; #endif vuint16 minLength; vuint16 maxLength; #if defined( FBL_DIAG_STATE_ARRAYS ) && \ ( STATE_COUNT > 0 ) tStateBitmap states[STATE_COUNT][STATECHECK_ARRAYSIZE]; #else tStateBitmap stateSet[STATECHECK_ARRAYSIZE]; tStateBitmap stateUnset[STATECHECK_ARRAYSIZE]; tStateBitmap stateAdd[STATECHECK_ARRAYSIZE]; tStateBitmap stateClr[STATECHECK_ARRAYSIZE]; tStateBitmap stateClrFail[STATECHECK_ARRAYSIZE]; #endif vuint8 mainHandlerIdx; #if defined( FBL_DIAG_CHECK_LIST_HANDLES ) vuint8 checkListIdx; #endif } tServiceProp; #if defined( FBL_DIAG_ENABLE_RAM_STATETABLES ) typedef struct { # if defined( FBL_DIAG_SERVICE_LIST_HANDLES ) # else V_MEMROM1 struct tagServiceList V_MEMROM2 V_MEMROM3 * subServices; # endif V_MEMROM1 vuint8 V_MEMROM2 V_MEMROM3 * serviceId; # if defined( FBL_DIAG_CHECK_LIST_HANDLES ) # else V_MEMROM1 tServiceCheckList V_MEMROM2 V_MEMROM3 * checks; # endif vuint16 minLength; vuint16 maxLength; vuint8 stateUsage; vuint8 mainHandlerIdx; # if defined( FBL_DIAG_CHECK_LIST_HANDLES ) vuint8 checkListIdx; # endif # if defined( FBL_DIAG_SERVICE_LIST_HANDLES ) vuint8 subServicesHandler; # endif } tServicePropROM; #endif #define FBL_DIAG_CHECK_HANDLER(name) tFblResult name( const V_MEMRAM1 tServiceProp V_MEMRAM2 V_MEMRAM3 * properties, \ V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * pbDiagBuffer, \ tCwDataLengthType length, tCwDataLengthType position, \ V_MEMRAM1 ptServiceProp V_MEMRAM2 V_MEMRAM3 * result ) #define FBL_DIAG_ERROR_HANDLER(name) tFblResult name( const V_MEMRAM1 tServiceProp V_MEMRAM2 V_MEMRAM3 *properties, \ V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * pbDiagBuffer, \ tCwDataLengthType diagReqDataLen ) #define FBL_DIAG_MAIN_HANDLER(name) tFblResult name( V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * pbDiagBuffer, \ tCwDataLengthType diagReqDataLen ) typedef FBL_DIAG_CHECK_HANDLER((*tFblDiagCheckHandler)); typedef FBL_DIAG_ERROR_HANDLER((*tFblDiagErrorHandler)); typedef FBL_DIAG_MAIN_HANDLER((*tFblDiagMainHandler)); /* Check handler */ #if defined( FBL_DIAG_ENABLE_SESSION_PARAMETERS ) typedef struct { vuint8 sessionType; /* Diagnostic Session Type */ vuint16 p2Timing; /* P2 Timing Value [ms] */ vuint16 p2StarTiming; /* P2* Timing Value [ms] / 10 */ } tDiagSessionParameters; #endif /* FBL_ENABLE_SESSION_PARAMETERS */ /*********************************************************************************************************************** * GLOBAL DATA **********************************************************************************************************************/ #define FBLDIAG_START_SEC_VAR #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ /* Data buffer for diagnostic data */ V_MEMRAM0 V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * V_MEMRAM1 V_MEMRAM2 DiagBuffer; V_MEMRAM0 V_MEMRAM1 vuint8 V_MEMRAM2 diagErrorCode; /* Diagnostic error code */ V_MEMRAM0 V_MEMRAM1 tCwDataLengthType V_MEMRAM2 DiagDataLength; /* Stores number of received data */ V_MEMRAM0 V_MEMRAM1_NEAR vuint16 V_MEMRAM2_NEAR P2Timeout; /* P2 timeout value */ V_MEMRAM0 V_MEMRAM1_NEAR vuint16 V_MEMRAM2_NEAR testerPresentTimeout; /* Timer value for TesterPresent timeout */ V_MEMRAM0 V_MEMRAM1 vuint8 V_MEMRAM2 diagResponseFlag; /* Flag to enable/suppress diagnostic response */ V_MEMRAM0 V_MEMRAM1_NEAR vuint8 V_MEMRAM2_NEAR diagServiceCurrent; /* Currently processed diag service ID */ V_MEMRAM0 V_MEMRAM1_NEAR tStateBitmap V_MEMRAM2_NEAR fblStates[STATE_INDEX(kDiagNumberOfStates - 1u) + 1u]; /* State bitmap array */ V_MEMRAM0 V_MEMRAM1 vuint8 V_MEMRAM2 diagCurrentSecLvl; /* Current security level */ #if defined( FBL_ENABLE_SEC_ADDITIONAL_LEVELS ) V_MEMRAM0 V_MEMRAM1 vuint8 V_MEMRAM2 diagRequestedSecLvlIdx; /* Table index of currently requested security level */ #endif #if defined( FBL_ENABLE_SLEEPMODE ) V_MEMRAM0 V_MEMRAM1 vuint32 V_MEMRAM2 sleepCounter; /* Counter, determines when to sleep */ #endif #if defined( FBL_ENABLE_DEBUG_STATUS ) /* Variables for error status reporting */ /* PRQA S 1514 6 */ /* MD_FblDiag_1514 */ V_MEMRAM0 V_MEMRAM1 vuint16 V_MEMRAM2 errStatErrorCode; /* Error status */ V_MEMRAM0 V_MEMRAM1 vuint16 V_MEMRAM2 errStatFblStates; /* FBL state flag */ V_MEMRAM0 V_MEMRAM1 vuint8 V_MEMRAM2 errStatLastServiceId; /* Last received service identifier */ V_MEMRAM0 V_MEMRAM1 vuint8 V_MEMRAM2 errStatFlashDrvVersion[3]; /* Flash driver version information */ V_MEMRAM0 V_MEMRAM1 vuint16 V_MEMRAM2 errStatFlashDrvErrorCode; /* Flash driver error code */ V_MEMRAM0 V_MEMRAM1 tBlockDescriptor V_MEMRAM2 errStatDescriptor; /* Error status block descriptor */ #endif #define FBLDIAG_STOP_SEC_VAR #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ #if defined( FBL_ENABLE_SEC_ADDITIONAL_LEVELS ) # define FBLDIAG_START_SEC_CONST # include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ V_MEMROM0 V_MEMROM1 tDiagSecAccessParams V_MEMROM2 kDiagSecAccessParams[] = { { kDiagSecLevelFlash, kSecSeedLength, kSecKeyLength } }; # define FBLDIAG_STOP_SEC_CONST # include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ #endif /* FBL_ENABLE_SEC_ADDITIONAL_LEVELS */ /*********************************************************************************************************************** * LOCAL DATA **********************************************************************************************************************/ #define FBLDIAG_START_SEC_VAR #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ /* PRQA S 3218 TAG_FblDiag_3218_1 */ /* MD_FblDiag_3218 */ /* Temporary data used during download in TransferData */ V_MEMRAM0 static V_MEMRAM1 tDiagSegmentList V_MEMRAM2 diagSegmentList; /* Complete list of download segments */ V_MEMRAM0 static V_MEMRAM1 vuint8 V_MEMRAM2 currentSegment; /* Index of currently processed download segment */ V_MEMRAM0 static V_MEMRAM1 vuint8 V_MEMRAM2 currentBlock; /* Index of currently processed download block */ V_MEMRAM0 static V_MEMRAM1 vuint8 V_MEMRAM2 lastErasedBlock; V_MEMRAM0 static V_MEMRAM1 tBlockHeader V_MEMRAM2 blockHeader[FBL_LBT_BLOCK_COUNT]; /* Structure with runtime information about logical blocks */ V_MEMRAM0 static V_MEMRAM1 tFblDiagAddr V_MEMRAM2 transferAddress; /* Actual transfer address */ V_MEMRAM0 static V_MEMRAM1 tFblLength V_MEMRAM2 transferRemainder; /* Number of remaining transfer bytes */ V_MEMRAM0 static V_MEMRAM1 vuint8 V_MEMRAM2 transferType; /* Download into RAM/Flash or upload */ V_MEMRAM0 static V_MEMRAM1 vuint8 V_MEMRAM2 expectedSequenceCnt; /* Block sequence counter */ V_MEMRAM0 static V_MEMRAM1 vuint8 V_MEMRAM2 currentSequenceCnt; /* Current Block sequence counter */ V_MEMRAM0 static V_MEMRAM1_NEAR vuint16 V_MEMRAM2_NEAR ecuResetTimeout; /* Timeout for EcuReset request (CW) */ V_MEMRAM0 static V_MEMRAM1 vuint8 V_MEMRAM2 dataFormatId; /* Combined encryption and compression method */ V_MEMRAM0 static V_MEMRAM1 tFblLength V_MEMRAM2 totalProgramLength; /* Total number of programmed bytes */ #if defined( FBL_ENABLE_SEC_ADDITIONAL_LEVELS ) V_MEMRAM0 static V_MEMRAM1 vuint8 V_MEMRAM2 diagRequestedSecLvl; /* Currently requested security level (via seed) */ #endif #if defined( FBL_DIAG_ENABLE_SESSION_PARAMETERS ) /* Internal index of the active diagnostic session (table kDiagSessionParameters) */ V_MEMRAM0 static V_MEMRAM1 vuint8 V_MEMRAM2 currentDiagSessionIndex; #else /* Type of the active diagnostic session according to the SessionControl sub-function parameter */ V_MEMRAM0 static V_MEMRAM1 vuint8 V_MEMRAM2 currentDiagSessionType; #endif #define FBLDIAG_STOP_SEC_VAR #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ #define FBLDIAG_START_SEC_CONST #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ /* State check masks */ V_MEMROM0 static V_MEMROM1 tStateBitmap V_MEMROM2 kDiagStateMaskSessions[STATECHECK_ARRAYSIZE] = STATE_BUILDARRAY(kDiagStateSessionAll); V_MEMROM0 static V_MEMROM1 tStateBitmap V_MEMROM2 kDiagStateMaskFunctional[STATECHECK_ARRAYSIZE] = STATE_BUILDARRAY(kDiagStateFunctionalRequest); V_MEMROM0 static V_MEMROM1 tStateBitmap V_MEMROM2 kDiagStateMaskSecurityAccess[STATECHECK_ARRAYSIZE] = STATE_BUILDARRAY(kDiagStateSecurityAccess01); V_MEMROM0 static V_MEMROM1 tStateBitmap V_MEMROM2 kDiagStateMaskSequenceError[STATECHECK_ARRAYSIZE] = STATE_BUILDARRAY(kDiagStateSecurityKey01 | kDiagStateTransferDataAllowed); /* PRQA S 2790, 3494 1 */ /* MD_FblDiag_2790_kDiagStateMaskAllLong, MD_FblDiag_ConstValue */ V_MEMROM0 static V_MEMROM1 tStateBitmap V_MEMROM2 kDiagStateMaskGeneralConditions[STATECHECK_ARRAYSIZE] = STATE_BUILDARRAY(kDiagStateMaskAllLong); V_MEMROM0 static V_MEMROM1 tStateBitmap V_MEMROM2 kDiagStateMaskReset[STATECHECK_ARRAYSIZE] = STATE_BUILDARRAY(kDiagStateNone); #define FBLDIAG_STOP_SEC_CONST #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ #define FBLDIAG_START_SEC_VAR #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ /* Concatenation of service properties */ V_MEMRAM0 static V_MEMRAM1_NEAR tServiceProp V_MEMRAM2_NEAR serviceProperties; /* Result of service execution */ V_MEMRAM0 static V_MEMRAM1_NEAR tFblResult V_MEMRAM2_NEAR serviceResult; #if defined( FBL_DIAG_ENABLE_UPLOAD ) /* maxNumberOfBlockLength is a 12 bit value that determines the maximum size */ /* of a block of data that can be transferred */ V_MEMRAM0 static V_MEMRAM1 vuint16 V_MEMRAM2 maxNumberOfBlockLength; #endif /* FBL_DIAG_ENABLE_UPLOAD */ #define FBLDIAG_STOP_SEC_VAR #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ #define FBLDIAG_START_SEC_CONST #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ #if defined( FBL_DIAG_ENABLE_SESSION_PARAMETERS ) V_MEMROM0 static V_MEMROM1 tDiagSessionParameters V_MEMROM2 kDiagSessionParameters[] = { /* Default Session */ { kDiagSubDefaultSession, 50, 500 }, /* Programming Session */ { kDiagSubProgrammingSession, kDiagSessionTimingP2, kDiagSessionTimingP2Star } }; V_MEMROM0 static V_MEMROM1 vuint8 V_MEMROM2 kDiagNumberOfSessions = sizeof(kDiagSessionParameters) / sizeof(tDiagSessionParameters); #endif /* FBL_DIAG_ENABLE_SESSION_PARAMETERS */ #define FBLDIAG_STOP_SEC_CONST #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ #if ( SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC ) /* SHA256 + CRC16 */ # define FBL_DIAG_VERIFY_BUFFER_SIZE (SEC_VERIFY_CLASS_DDD_DIGEST_SIZE + SEC_SIZE_CHECKSUM_CRC) # define FBL_DIAG_CRC_OFFSET SEC_VERIFY_CLASS_DDD_CHECKSUM_OFFSET #else /* CRC16 */ # define FBL_DIAG_VERIFY_BUFFER_SIZE (SEC_VERIFY_CLASS_DDD_DIGEST_SIZE) # define FBL_DIAG_CRC_OFFSET 0u #endif #define FBLDIAG_START_SEC_VAR #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ #if defined( FBL_MEM_ENABLE_VERIFY_PIPELINED ) /* Parameters for pipelined signature calculation */ V_MEMRAM0 static V_MEMRAM1 SecM_SignatureParamType V_MEMRAM2 pipeVerifyParam; # if ( SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC ) V_MEMRAM0 static V_MEMRAM1 SecM_SignatureParamType V_MEMRAM2 pipeVerifyParamCrc; # endif /* Used to store hash value and optionally security module context */ /* PRQA S 3678 1 */ /* MD_FblDiag_3678 */ V_MEMRAM0 static V_MEMRAM1 vuint8 V_MEMRAM2 pipeVerifyBuf[FBL_DIAG_VERIFY_BUFFER_SIZE]; V_MEMRAM0 static V_MEMRAM1 vuint32 V_MEMRAM2 pipeVerifyLength; # if ( SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC ) V_MEMRAM0 static V_MEMRAM1 SecM_CRCParamType V_MEMRAM2 pipeVerifyCrc; V_MEMRAM0 static V_MEMRAM1 vuint32 V_MEMRAM2 pipeVerifyLengthCrc; # endif #endif /* FBL_MEM_ENABLE_VERIFY_PIPELINED */ #if defined( FBL_MEM_ENABLE_VERIFY_OUTPUT ) V_MEMRAM0 static V_MEMRAM1 SecM_VerifyParamType V_MEMRAM2 verifyParam; V_MEMRAM0 static V_MEMRAM1 FL_SegmentInfoType V_MEMRAM2 verifySegmentInfo[1]; #endif /* FBL_MEM_ENABLE_VERIFY_OUTPUT */ #if ( SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC ) V_MEMRAM0 static V_MEMRAM1 vuint16 V_MEMRAM2 verifyTokenSignLength; #endif /* Output buffer which keeps the verification result from FblMemBlockVerify (RequestTransferExit, CheckProgDep) */ V_MEMRAM0 static V_MEMRAM1 vuint8 V_MEMRAM2 verifyOutputBuf[FBL_DIAG_VERIFY_BUFFER_SIZE]; #define FBLDIAG_STOP_SEC_VAR #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ /*********************************************************************************************************************** * PROTOTYPES **********************************************************************************************************************/ #define FBLDIAG_START_SEC_CODE #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ static void FblDiagSegmentInit( void ); static vuint8 FblDiagSegmentNext( tFblDiagAddr segAddr, tFblLength segLength, vuint8 blockIdx ); static tCwDataLengthType FblDiagGetMaxTransferDataBlockLength(void); static void DiagDiscardReception( void ); static tFblResult FblInitMemoryDriver( void ); static void FblDeinitMemoryDriver( void ); static void FblDiagDeinit( void ); #define FBLDIAG_STOP_SEC_CODE #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ #define FBLDIAG_RAMCODE_START_SEC_CODE #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ static void DiagResetResponseHandling( void ); #define FBLDIAG_RAMCODE_STOP_SEC_CODE #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ #define FBLDIAG_START_SEC_CODE #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ static V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * FblDiagMemGetActiveBuffer(void); /*-- Service property functions ---------------------------------------------*/ static void FblDiagSetState (const V_MEMRAM1 tStateBitmap V_MEMRAM2 V_MEMRAM3 * state); static void FblDiagClrState (const V_MEMRAM1 tStateBitmap V_MEMRAM2 V_MEMRAM3 * state); static void FblDiagRetainState (V_MEMROM1 tStateBitmap V_MEMROM2 V_MEMROM3 * state); static void FblDiagInitStateTables ( void ); static void FblDiagSetProperties(ptServiceProp source, tServiceProp * destination); static void FblDiagMergeProperties(ptServiceProp source, tServiceProp * merge); static void FblDiagDispatch ( void ); static tFblResult FblDiagSecAccessSeed(V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * pbDiagBuffer, tCwDataLengthType diagReqDataLen, vuint8 secLevel); static tFblResult FblDiagSecAccessKey(V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * pbDiagBuffer, tCwDataLengthType diagReqDataLen, vuint8 secLevel); /*-- Service check functions ------------------------------------------------*/ static FBL_DIAG_CHECK_HANDLER(FblDiagSearchService); static FBL_DIAG_CHECK_HANDLER(FblDiagCheckSession); static FBL_DIAG_CHECK_HANDLER(FblDiagCheckLength); static FBL_DIAG_CHECK_HANDLER(FblDiagCheckFunctional); static FBL_DIAG_CHECK_HANDLER(FblDiagCheckSuppressPosRsp); static FBL_DIAG_CHECK_HANDLER(FblDiagCheckSecurityAccess); static FBL_DIAG_CHECK_HANDLER(FblDiagCheckSequenceError); static FBL_DIAG_CHECK_HANDLER(FblDiagCheckGeneralConditions); #if defined( FBL_DIAG_ENABLE_UPLOAD ) static FBL_DIAG_CHECK_HANDLER(FblDiagCheckTransferMode); #endif #if defined( FBL_ENABLE_SEC_ADDITIONAL_LEVELS ) static FBL_DIAG_CHECK_HANDLER(FblDiagSearchSecService); static FBL_DIAG_CHECK_HANDLER(FblDiagCheckSecLength); static FBL_DIAG_CHECK_HANDLER(FblDiagCheckSecSequenceError); #endif /*-- Diagnostic error handler service functions -----------------------------*/ #if defined( FBL_ENABLE_USERSERVICE ) static FBL_DIAG_ERROR_HANDLER(FblDiagErrorHandlerServiceNotFound); #endif #if defined( FBL_ENABLE_USERSUBFUNCTION ) static FBL_DIAG_ERROR_HANDLER(FblDiagErrorHandlerSubFunctionNotFound); #endif static FBL_DIAG_ERROR_HANDLER(FblDiagErrorHandlerExecMainHandler); /*-- Diagnostic main handler service functions ------------------------------*/ static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerDefaultSession); static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerProgrammingSession); static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerTesterPresent); static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerEcuReset); static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerRcEraseMemory); static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerRcCheckProgDep); static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerRcActivateSbl); static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerRcCheckValidApp); #if ( SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC ) # if defined( FBL_ENABLE_TOKEN_DOWNLOAD_HANDLING ) static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerRcTokenDownload); # endif #endif #if defined( FBL_DIAG_ENABLE_UPDATE_SEC_BYTES ) static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerRcUpdateSecBytes); #endif static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerSecAccessSeed); static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerSecAccessKey); static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerRequestDownload); static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerTransferDataDownload); #if defined( FBL_DIAG_ENABLE_UPLOAD ) static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerRequestUpload); static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerTransferDataUpload); #endif static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerRequestTransferExit); static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerReadDataById); #if defined( FBL_DIAG_ENABLE_WRITE_DATA_BY_IDENTIFIER ) static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerWriteDataById); #endif #if defined( FBL_ENABLE_USERROUTINE ) static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerRoutineControl); #endif /*-- Ford specific functions --------------------------------------------*/ static void FblDiagInitDownloadSequence( void ); static tFblResult FblDiagPrepareDidResponse( V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 *pbDiagBuffer, vuint16 reqDid, tDidDataPtr didData, vuint16 didLen ); static tFblResult FblDiagCheckState( const V_MEMRAM1 tServiceProp V_MEMRAM2 V_MEMRAM3 *properties, V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 *pbDiagBuffer, tCwDataLengthType length, tCwDataLengthType position, V_MEMROM1 tStateBitmap V_MEMROM2 * stateMask, ptServiceProp * result); static tFblResult FblDiagSessionTransition( V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * pbDiagBuffer, tCwDataLengthType diagReqDataLen ); static void FblDiagSessionControlParamInit( V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * pbDiagBuffer, tCwDataLengthType diagReqDataLen ); #if defined( FBL_DIAG_ENABLE_SESSION_PARAMETERS ) static vuint8 FblDiagGetSessionIndex( vuint8 diagnosticSessionType ); #endif #if defined( FBL_MEM_ENABLE_VERIFY_OUTPUT ) static SecM_StatusType FblDiagVerification( V_MEMRAM1 SecM_VerifyParamType V_MEMRAM2 V_MEMRAM3 * verifyPar ); #endif #if defined( FBL_MEM_ENABLE_VERIFY_PIPELINED ) && ( SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC ) static SecM_StatusType FblDiagVerifySignature( V_MEMRAM1 SecM_SignatureParamType V_MEMRAM2 V_MEMRAM3 * pVerifyParam ); #endif #if ( SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC ) # if defined( FBL_ENABLE_TOKEN_DOWNLOAD_HANDLING ) static tTokenHdlResult FblDiagTokenLengthCheck(vuint8 cmdType, vuint16 tokenLength); static tTokenHdlResult FblDiagTokenKeyProcessing(vuint8 cmdType, V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * tokenBufferPtr); static tTokenHdlResult FblDiagValidateToken( const V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * tokenBuf ); static tFblResult FblDiagCheckServerMessageId( const V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * tokenBuf ); static tTokenHdlResult FblDiagTokenCallout( vuint8 cmdType, const V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * tokenBuf, vuint16 tokenLength ); # endif #endif #define FBLDIAG_STOP_SEC_CODE #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ /*****************************************************************************/ /*** State machine configuration *********************************************/ /*****************************************************************************/ /* The handler tables */ enum { kServiceCheckHandlerSearchService ,kServiceCheckHandlerCheckSession ,kServiceCheckHandlerCheckLength ,kServiceCheckHandlerCheckFunctional ,kServiceCheckHandlerCheckSuppressPosRsp ,kServiceCheckHandlerCheckSecurityAccess ,kServiceCheckHandlerCheckSequenceError ,kServiceCheckHandlerCheckGeneralConditions #if defined( FBL_DIAG_ENABLE_UPLOAD ) ,kServiceCheckHandlerTransferMode #endif #if defined( FBL_ENABLE_SEC_ADDITIONAL_LEVELS ) ,kServiceCheckHandlerSearchSecService ,kServiceCheckHandlerCheckSecLength ,kServiceCheckHandlerCheckSecSequenceError #endif }; #define FBLDIAG_START_SEC_CONST #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ V_MEMROM0 static V_MEMROM1 tFblDiagCheckHandler V_MEMROM2 kServiceCheckHandlerFctTable[] = { &FblDiagSearchService ,&FblDiagCheckSession ,&FblDiagCheckLength ,&FblDiagCheckFunctional ,&FblDiagCheckSuppressPosRsp ,&FblDiagCheckSecurityAccess ,&FblDiagCheckSequenceError ,&FblDiagCheckGeneralConditions #if defined( FBL_DIAG_ENABLE_UPLOAD ) ,&FblDiagCheckTransferMode #endif #if defined( FBL_ENABLE_SEC_ADDITIONAL_LEVELS ) ,&FblDiagSearchSecService ,&FblDiagCheckSecLength ,&FblDiagCheckSecSequenceError #endif }; enum { kServiceErrorHandlerExecMainHandler #if defined( FBL_ENABLE_USERSERVICE ) ,kServiceErrorHandlerServiceNotFound #endif #if defined( FBL_ENABLE_USERSUBFUNCTION ) ,kServiceErrorHandlerSubFunctionNotFound #endif /*----------------------*/ ,kServiceErrorHandlerNone }; V_MEMROM0 static V_MEMROM1 tFblDiagErrorHandler V_MEMROM2 kServiceErrorHandlerFctTable[] = { &FblDiagErrorHandlerExecMainHandler #if defined( FBL_ENABLE_USERSERVICE ) ,&FblDiagErrorHandlerServiceNotFound #endif #if defined( FBL_ENABLE_USERSUBFUNCTION ) ,&FblDiagErrorHandlerSubFunctionNotFound #endif }; enum { kServiceMainHandlerDefaultSession ,kServiceMainHandlerProgrammingSession ,kServiceMainHandlerTesterPresent ,kServiceMainHandlerEcuReset ,kServiceMainHandlerRcEraseMemory ,kServiceMainHandlerRcCheckProgDep ,kServiceMainHandlerRcActivateSbl ,kServiceMainHandlerRcCheckValidApp #if ( SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC ) # if defined( FBL_ENABLE_TOKEN_DOWNLOAD_HANDLING ) ,kServiceMainHandlerRcTokenDownload # endif #endif #if defined( FBL_DIAG_ENABLE_UPDATE_SEC_BYTES ) ,kServiceMainHandlerRcUpdateSecBytes #endif ,kServiceMainHandlerSecAccessSeed ,kServiceMainHandlerSecAccessKey ,kServiceMainHandlerRequestDownload ,kServiceMainHandlerTransferDataDownload #if defined( FBL_DIAG_ENABLE_UPLOAD ) ,kServiceMainHandlerRequestUpload ,kServiceMainHandlerTransferDataUpload #endif ,kServiceMainHandlerRequestTransferExit ,kServiceMainHandlerReadDataById #if defined( FBL_DIAG_ENABLE_WRITE_DATA_BY_IDENTIFIER ) ,kServiceMainHandlerWriteDataById #endif #if defined( FBL_ENABLE_USERROUTINE ) ,kServiceMainHandlerRoutineControl #endif /*----------------------*/ ,kServiceMainHandlerNone }; V_MEMROM0 static V_MEMROM1 tFblDiagMainHandler V_MEMROM2 kServiceMainHandlerFctTable[] = { &FblDiagMainHandlerDefaultSession ,&FblDiagMainHandlerProgrammingSession ,&FblDiagMainHandlerTesterPresent ,&FblDiagMainHandlerEcuReset ,&FblDiagMainHandlerRcEraseMemory ,&FblDiagMainHandlerRcCheckProgDep ,&FblDiagMainHandlerRcActivateSbl ,&FblDiagMainHandlerRcCheckValidApp #if ( SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC ) # if defined( FBL_ENABLE_TOKEN_DOWNLOAD_HANDLING ) ,&FblDiagMainHandlerRcTokenDownload # endif #endif #if defined( FBL_DIAG_ENABLE_UPDATE_SEC_BYTES ) ,&FblDiagMainHandlerRcUpdateSecBytes #endif ,&FblDiagMainHandlerSecAccessSeed ,&FblDiagMainHandlerSecAccessKey ,&FblDiagMainHandlerRequestDownload ,&FblDiagMainHandlerTransferDataDownload #if defined( FBL_DIAG_ENABLE_UPLOAD ) ,&FblDiagMainHandlerRequestUpload ,&FblDiagMainHandlerTransferDataUpload #endif ,&FblDiagMainHandlerRequestTransferExit ,&FblDiagMainHandlerReadDataById #if defined( FBL_DIAG_ENABLE_WRITE_DATA_BY_IDENTIFIER ) ,&FblDiagMainHandlerWriteDataById #endif #if defined( FBL_ENABLE_USERROUTINE ) ,&FblDiagMainHandlerRoutineControl #endif }; /*****************************************************************************/ /* Service checks */ V_MEMROM0 static V_MEMROM1 tServiceCheck V_MEMROM2 kDiagServiceChecks[] = { { kServiceCheckHandlerSearchService ,kDiagNrcServiceNotSupported # if defined( FBL_ENABLE_USERSERVICE ) ,kServiceErrorHandlerServiceNotFound # else ,kServiceErrorHandlerNone # endif } ,{ kServiceCheckHandlerCheckFunctional ,kDiagNrcNoResponse ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckSession ,kDiagNrcServiceNotSupportedInActiveSession ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckLength ,kDiagNrcIncorrectMessageLengthOrInvalidFormat ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckSecurityAccess ,kDiagNrcSecurityAccessDenied ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckSequenceError ,kDiagNrcRequestSequenceError ,kServiceErrorHandlerNone } }; V_MEMROM0 static V_MEMROM1 tServiceCheckList V_MEMROM2 kDiagServiceCheckTable = { kDiagServiceChecks ,(sizeof(kDiagServiceChecks)/sizeof(kDiagServiceChecks[0])) }; /*****************************************************************************/ V_MEMROM0 static V_MEMROM1 tServiceCheck V_MEMROM2 kDiagSubFctChecks[] = { /* No real check, but only needs to be set once here */ { kServiceCheckHandlerCheckSuppressPosRsp ,kDiagNrcNoResponse ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerSearchService ,kDiagNrcSubFunctionNotSupported # if defined( FBL_ENABLE_USERSUBFUNCTION ) ,kServiceErrorHandlerSubFunctionNotFound # else ,kServiceErrorHandlerNone # endif } ,{ kServiceCheckHandlerCheckFunctional ,kDiagNrcNoResponse ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckSession ,kDiagNrcSubfunctionNotSupportedInActiveSession ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckLength ,kDiagNrcIncorrectMessageLengthOrInvalidFormat ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckSecurityAccess ,kDiagNrcSecurityAccessDenied ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckSequenceError ,kDiagNrcRequestSequenceError ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckGeneralConditions ,kDiagNrcConditionsNotCorrect ,kServiceErrorHandlerNone } }; V_MEMROM0 static V_MEMROM1 tServiceCheckList V_MEMROM2 kDiagSubFctCheckTable = { kDiagSubFctChecks ,(sizeof(kDiagSubFctChecks)/sizeof(kDiagSubFctChecks[0])) }; #if defined( FBL_ENABLE_SEC_ADDITIONAL_LEVELS ) /*****************************************************************************/ V_MEMROM0 static V_MEMROM1 tServiceCheck V_MEMROM2 kDiagSubFctSecChecks[] = { /* No real check, but only needs to be set once here */ { kServiceCheckHandlerCheckSuppressPosRsp ,kDiagNrcNoResponse ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerSearchSecService ,kDiagNrcSubFunctionNotSupported # if defined( FBL_ENABLE_USERSUBFUNCTION ) ,kServiceErrorHandlerSubFunctionNotFound # else ,kServiceErrorHandlerNone # endif } ,{ kServiceCheckHandlerCheckFunctional ,kDiagNrcNoResponse ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckSession ,kDiagNrcSubfunctionNotSupportedInActiveSession ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckSecLength ,kDiagNrcIncorrectMessageLengthOrInvalidFormat ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckSecSequenceError ,kDiagNrcRequestSequenceError ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckGeneralConditions ,kDiagNrcConditionsNotCorrect ,kServiceErrorHandlerNone } }; V_MEMROM0 static V_MEMROM1 tServiceCheckList V_MEMROM2 kDiagSubFctSecCheckTable = { kDiagSubFctSecChecks ,(sizeof(kDiagSubFctSecChecks)/sizeof(kDiagSubFctSecChecks[0])) }; #endif /* FBL_ENABLE_SEC_ADDITIONAL_LEVELS */ /*****************************************************************************/ V_MEMROM0 static V_MEMROM1 tServiceCheck V_MEMROM2 kDiagRcTypeChecks[] = { /* No real check, but only needs to be set once here */ { kServiceCheckHandlerCheckSuppressPosRsp ,kDiagNrcNoResponse ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerSearchService ,kDiagNrcSubFunctionNotSupported ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckFunctional ,kDiagNrcNoResponse ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckSession ,kDiagNrcSubfunctionNotSupportedInActiveSession ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckLength ,kDiagNrcIncorrectMessageLengthOrInvalidFormat ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckSecurityAccess ,kDiagNrcSecurityAccessDenied ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckSequenceError ,kDiagNrcRequestSequenceError ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckGeneralConditions ,kDiagNrcConditionsNotCorrect ,kServiceErrorHandlerNone } }; V_MEMROM0 static V_MEMROM1 tServiceCheckList V_MEMROM2 kDiagRcTypeCheckTable = { kDiagRcTypeChecks ,(sizeof(kDiagRcTypeChecks)/sizeof(kDiagRcTypeChecks[0])) }; /*****************************************************************************/ V_MEMROM0 static V_MEMROM1 tServiceCheck V_MEMROM2 kDiagNonSubFctChecks[] = { { kServiceCheckHandlerCheckGeneralConditions ,kDiagNrcConditionsNotCorrect ,kServiceErrorHandlerNone } }; V_MEMROM0 static V_MEMROM1 tServiceCheckList V_MEMROM2 kDiagNonSubFctCheckTable = { kDiagNonSubFctChecks ,(sizeof(kDiagNonSubFctChecks)/sizeof(kDiagNonSubFctChecks[0])) }; /*****************************************************************************/ V_MEMROM0 static V_MEMROM1 tServiceCheck V_MEMROM2 kDiagSubRoutineChecks[] = { { kServiceCheckHandlerSearchService ,kDiagNrcRequestOutOfRange ,kServiceErrorHandlerExecMainHandler } ,{ kServiceCheckHandlerCheckFunctional ,kDiagNrcNoResponse ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckSession ,kDiagNrcRequestOutOfRange ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckSecurityAccess ,kDiagNrcSecurityAccessDenied ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckGeneralConditions ,kDiagNrcConditionsNotCorrect ,kServiceErrorHandlerNone } }; V_MEMROM0 static V_MEMROM1 tServiceCheckList V_MEMROM2 kDiagSubRoutineCheckTable = { kDiagSubRoutineChecks ,(sizeof(kDiagSubRoutineChecks)/sizeof(kDiagSubRoutineChecks[0])) }; #if defined( FBL_DIAG_ENABLE_UPLOAD ) /*****************************************************************************/ /* TransferData checks */ V_MEMROM0 static V_MEMROM1 tServiceCheck V_MEMROM2 kDiagTransferDataChecks[] = { { kServiceCheckHandlerTransferMode ,kDiagErrorNone ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckLength ,kDiagNrcIncorrectMessageLengthOrInvalidFormat ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckSecurityAccess ,kDiagNrcSecurityAccessDenied ,kServiceErrorHandlerNone } ,{ kServiceCheckHandlerCheckGeneralConditions ,kDiagNrcConditionsNotCorrect ,kServiceErrorHandlerNone } }; V_MEMROM0 static V_MEMROM1 tServiceCheckList V_MEMROM2 kDiagTransferDataCheckTable = { kDiagTransferDataChecks ,(sizeof(kDiagTransferDataChecks)/sizeof(kDiagTransferDataChecks[0])) }; #endif /* FBL_DIAG_ENABLE_UPLOAD */ /*****************************************************************************/ #if defined( FBL_DIAG_CHECK_LIST_HANDLES ) /* The check list tables */ enum { kServiceCheckListServiceCheck ,kServiceCheckListSubFctCheck #if defined( FBL_ENABLE_SEC_ADDITIONAL_LEVELS ) ,kServiceCheckListSubFctSecCheck #endif ,kServiceCheckListNonSubFctCheck ,kServiceCheckListSubRoutineCheck ,kServiceCheckListRcTypeCheck #if defined( FBL_DIAG_ENABLE_UPLOAD ) ,kServiceCheckListTransferDataCheck #endif /*----------------------*/ ,kServiceCheckListNone }; V_MEMROM0 static V_MEMROM1 tServiceCheckList V_MEMROM2 V_MEMROM3 * V_MEMROM1 V_MEMROM2 kServiceCheckListTable[] = { &kDiagServiceCheckTable ,&kDiagSubFctCheckTable #if defined( FBL_ENABLE_SEC_ADDITIONAL_LEVELS ) ,&kDiagSubFctSecCheckTable #endif ,&kDiagNonSubFctCheckTable ,&kDiagSubRoutineCheckTable ,&kDiagRcTypeCheckTable #if defined( FBL_DIAG_ENABLE_UPLOAD ) ,&kDiagTransferDataCheckTable #endif }; #endif /* Service handlers **********************************************************/ /* PRQA S 0342 TAG_FblDiag_0342_1 */ /* MD_MSR_Rule20.10_0342 */ /* PRQA S 0841 TAG_FblDiag_0841_1 */ enum { #define FBL_DIAG_STATE_DEF(name, parent, firstChild, lastChild, bufPos, id, handler, checks, set, unset, add, clear, clearFail, rqlMin, rqlMax) kDiagService ## name #define FBL_DIAG_IMPL_TYPE FBL_DIAG_IMPL_TYPE_OUTPUT #define FBL_DIAG_IMPL_OUTPUT FBL_DIAG_STATE_RESULT, #include "fbl_diag.def" /* PRQA S 5087 */ /* MD_FblDiag_5087_DiagDef */ #undef FBL_DIAG_STATE_DEF #undef FBL_DIAG_IMPL_TYPE #undef FBL_DIAG_IMPL_OUTPUT kDiagNumberOfServices }; #if defined( FBL_DIAG_ENABLE_RAM_STATETABLES ) /* State Bitmaps ************************************************************/ V_MEMROM0 static V_MEMROM1 tStateBitmap V_MEMROM2 kDiagStateBitmaps[] = { #define FBL_DIAG_IMPL_TYPE FBL_DIAG_IMPL_TYPE_STATEBITMAP #include "fbl_diag.def" /* PRQA S 5087 */ /* MD_FblDiag_5087_DiagDef */ #undef FBL_DIAG_IMPL_TYPE }; #endif /* Service IDs ***************************************************************/ #if defined( FBL_DIAG_ENABLE_RAM_STATETABLES ) V_MEMRAM0 static V_MEMRAM1 tServiceProp V_MEMRAM2 kDiagServiceProperties[kDiagNumberOfServices]; #else V_MEMROM0 static V_MEMROM1 tServiceProp V_MEMROM2 kDiagServiceProperties[kDiagNumberOfServices]; #endif /* Service IDs ***************************************************************/ #define FBL_DIAG_STATE_DEF(name, parent, firstChild, lastChild, bufPos, id, handler, checks, set, unset, add, clear, clearFail, rqlMin, rqlMax) \ V_MEMROM0 static V_MEMROM1 vuint8 V_MEMROM2 kDiagSrvId_ ## name [] = { id } #define FBL_DIAG_IMPL_TYPE FBL_DIAG_IMPL_TYPE_OUTPUT #define FBL_DIAG_IMPL_OUTPUT FBL_DIAG_STATE_RESULT; #include "fbl_diag.def" /* PRQA S 5087 */ /* MD_FblDiag_5087_DiagDef */ #undef FBL_DIAG_STATE_DEF #undef FBL_DIAG_IMPL_TYPE #undef FBL_DIAG_IMPL_OUTPUT /* Service Lists *************************************************************/ #define FBL_DIAG_IMPL_TYPE FBL_DIAG_IMPL_TYPE_SERVICELIST #include "fbl_diag.def" /* PRQA S 5087 */ /* MD_FblDiag_5087_DiagDef */ #undef FBL_DIAG_IMPL_TYPE #if defined( FBL_DIAG_SERVICE_LIST_HANDLES ) enum { #define FBL_DIAG_IMPL_TYPE FBL_DIAG_IMPL_TYPE_SERVICELIST_ENUM #include "fbl_diag.def" /* PRQA S 5087 */ /* MD_FblDiag_5087_DiagDef */ #undef FBL_DIAG_IMPL_TYPE kDiagServiceListHandler_None }; V_MEMROM0 static V_MEMROM1 tServiceList V_MEMROM2 V_MEMROM3 * V_MEMROM1 V_MEMROM2 kDiagSubFctTblHandler[] = { #define FBL_DIAG_IMPL_TYPE FBL_DIAG_IMPL_TYPE_SERVICELIST_HANDLER #include "fbl_diag.def" /* PRQA S 5087 */ /* MD_FblDiag_5087_DiagDef */ #undef FBL_DIAG_IMPL_TYPE kDiagNoSubServices }; #endif /* Service Properties ********************************************************/ #if defined( FBL_DIAG_ENABLE_RAM_STATETABLES ) V_MEMROM0 static V_MEMROM1 tServicePropROM V_MEMROM2 kDiagServicePropertiesROM[] = #else V_MEMROM0 static V_MEMROM1 tServiceProp V_MEMROM2 kDiagServiceProperties[] = #endif { #define FBL_DIAG_IMPL_TYPE FBL_DIAG_IMPL_TYPE_SERVICEPROPERTY #include "fbl_diag.def" /* PRQA S 5087 */ /* MD_FblDiag_5087_DiagDef */ #undef FBL_DIAG_IMPL_TYPE }; /* PRQA L:TAG_FblDiag_0342_1 */ /* PRQA L:TAG_FblDiag_0881_1 */ /* PRQA L:TAG_FblDiag_0841_1 */ /* PRQA L:TAG_FblDiag_3410_1 */ /* PRQA L:TAG_FblDiag_3412_1 */ /* PRQA L:TAG_FblDiag_3431_1 */ /* PRQA L:TAG_FblDiag_3453_2 */ /* PRQA L:TAG_FblDiag_3218_1 */ #define FBLDIAG_STOP_SEC_CONST #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ /*********************************************************************************************************************** * GLOBAL FUNCTIONS **********************************************************************************************************************/ #define FBLDIAG_START_SEC_CODE #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ #if defined( FBL_ENABLE_USERSERVICE ) /*********************************************************************************************************************** * FblDiagErrorHandlerServiceNotFound **********************************************************************************************************************/ /*! \brief Execute callback for user specific service implementations * \param[in] properties Dispatching properties * \param[in] pbDiagBuffer Diagnostic buffer * \param[in] diagReqDataLen Request length * \return User service found **********************************************************************************************************************/ static FBL_DIAG_ERROR_HANDLER(FblDiagErrorHandlerServiceNotFound) { tFblResult result; #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameter not used: avoid compiler warning */ /* PRQA S 3112 1 */ /* MD_MSR_DummyStmt */ (void)properties; #endif ApplDiagUserService(&pbDiagBuffer[kDiagFmtRoutineIdHigh], diagReqDataLen); result = kFblFailed; if (DiagGetError() == kDiagErrorNone) { result = kFblOk; } return result; } #endif /* FBL_ENABLE_USERSERVICE */ #if defined( FBL_ENABLE_USERSUBFUNCTION ) /*********************************************************************************************************************** * FblDiagErrorHandlerSubFunctionNotFound **********************************************************************************************************************/ /*! \brief Execute callback for user specific subfunction implementations * \param[in] properties Dispatching properties * \param[in] pbDiagBuffer Diagnostic buffer * \param[in] diagReqDataLen Request length * \return User subfunction found **********************************************************************************************************************/ static FBL_DIAG_ERROR_HANDLER(FblDiagErrorHandlerSubFunctionNotFound) { tFblResult result; #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameter not used: avoid compiler warning */ /* PRQA S 3112 1 */ /* MD_MSR_DummyStmt */ (void)properties; #endif ApplDiagUserSubFunction(&pbDiagBuffer[kDiagFmtRoutineIdHigh], diagReqDataLen); result = kFblFailed; if (DiagGetError() == kDiagErrorNone) { result = kFblOk; } return result; } #endif /* FBL_ENABLE_USERSUBFUNCTION */ /*********************************************************************************************************************** * FblDiagErrorHandlerExecMainHandler **********************************************************************************************************************/ /*! \brief Execute main handler of parent service * \param[in] properties Dispatching properties * \param[in] pbDiagBuffer Diagnostic buffer * \param[in] diagReqDataLen Request length * \return Main handler execution result **********************************************************************************************************************/ static FBL_DIAG_ERROR_HANDLER(FblDiagErrorHandlerExecMainHandler) { tFblResult result; result = kFblFailed; if (properties->mainHandlerIdx != (vuint8)kServiceMainHandlerNone) { result = (kServiceMainHandlerFctTable[properties->mainHandlerIdx])(pbDiagBuffer, diagReqDataLen); } return result; } /*********************************************************************************************************************** * FblDiagSearchService **********************************************************************************************************************/ /*! \brief Search the subservice table using the id at the current request position * \param[in] properties Dispatching properties * \param[in] pbDiagBuffer Diagnostic buffer * \param[in] length Request length * \param[in] position Current request position * \param[in,out] result Resulting properties * \return Possible return values: * - kFblOk: Search successful. If applicable, changed properties are returned via parameter 'result' * - kFblFailed: Search failed **********************************************************************************************************************/ /* PRQA S 3673 1 */ /* MD_MSR_Rule8.13 */ static FBL_DIAG_CHECK_HANDLER(FblDiagSearchService) { V_MEMROM1 tServiceList V_MEMROM2 V_MEMROM3 * localSubServices; ptServiceProp subSrvLst = V_NULL; /* PRQA S 3679 */ /* MD_MSR_Rule8.13 */ ptServiceProp subService = V_NULL; /* PRQA S 3679 */ /* MD_MSR_Rule8.13 */ vuint8 curPos; vuint8 subSrvIdx; tFblResult valid; tFblResult found; #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameter not used: avoid compiler warning */ /* PRQA S 3112 1 */ /* MD_MSR_DummyStmt */ (void)length; #endif localSubServices = properties->subServices; subSrvLst = localSubServices->list; found = kFblFailed; for (subSrvIdx = 0; subSrvIdx < localSubServices->count; subSrvIdx++) { subService = &subSrvLst[subSrvIdx]; valid = kFblOk; for (curPos = 0; curPos < localSubServices->idSize; curPos++) { if (subService->serviceId[curPos] != pbDiagBuffer[position + curPos]) { valid = kFblFailed; /* Code size optimization, single break in loop allowed by MISRA */ break; } } if (valid == kFblOk) { found = kFblOk; *result = subService; /* Code size optimization, single break in loop allowed by MISRA */ break; } } return found; } /*********************************************************************************************************************** * FblDiagCheckState **********************************************************************************************************************/ /*! \brief Check if the masked state matches the service requirements * \param[in] properties Dispatching properties * \param[in] pbDiagBuffer Diagnostic buffer * \param[in] length Request length * \param[in] position Current request position * \param[in] stateMask State mask * \param[in,out] result Resulting properties * \return Possible return values: * - kFblOk: Check successful. If applicable, changed properties are returned via parameter 'result' * - kFblFailed: Check failed **********************************************************************************************************************/ /* PRQA S 3673, 6060 1 */ /* MD_MSR_Rule8.13, MD_MSR_STPAR */ static tFblResult FblDiagCheckState( const V_MEMRAM1 tServiceProp V_MEMRAM2 V_MEMRAM3 *properties, V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 *pbDiagBuffer, tCwDataLengthType length, tCwDataLengthType position, V_MEMROM1 tStateBitmap V_MEMROM2 * stateMask, ptServiceProp * result) { vuint8 idx, valid; tStateBitmap maskedState; #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameters not used: avoid compiler warning */ /* PRQA S 3112 4 */ /* MD_MSR_DummyStmt */ (void)pbDiagBuffer; (void)length; (void)position; (void)result; #endif valid = kFblOk; #if ( STATECHECK_ARRAYSIZE == 1u ) idx = 0u; #else for (idx = 0u; (idx < STATECHECK_ARRAYSIZE) && (valid == kFblOk); idx++) #endif { /* Separate the state bits which have to be set */ maskedState = properties->stateSet[idx] & stateMask[idx]; /* Check if all of the required "Set" states are set */ if ((maskedState != kDiagStateMaskNone) && ((maskedState & fblStates[idx]) != maskedState)) { /* At least one of the required states is not set */ valid = kFblFailed; } else { /* Separate the state bits which must not be set */ maskedState = properties->stateUnset[idx] & stateMask[idx]; /* Check if all of the required "Unset" states are cleared */ if ((maskedState != kDiagStateMaskNone) && ((maskedState & fblStates[idx]) != kDiagStateMaskNone)) { /* At least one of the required states is set */ valid = kFblFailed; } } } /* Positive check result: - All of the required "Set" states are set - All of the required "Unset" states are cleared */ return valid; } /*********************************************************************************************************************** * FblDiagCheckSession **********************************************************************************************************************/ /*! \brief Check if the session states match the service requirements * \param[in] properties Dispatching properties * \param[in] pbDiagBuffer Diagnostic buffer * \param[in] length Request length * \param[in] position Current request position * \param[in,out] result Resulting properties * \return Possible return values: * - kFblOk: Check successful. If applicable, changed properties are returned via parameter 'result' * - kFblFailed: Check failed **********************************************************************************************************************/ static FBL_DIAG_CHECK_HANDLER(FblDiagCheckSession) { return FblDiagCheckState(properties, pbDiagBuffer, length, position, kDiagStateMaskSessions, result); } /*********************************************************************************************************************** * FblDiagCheckFunctional **********************************************************************************************************************/ /*! \brief Check if the functional request state matches the service requirements * \param[in] properties Dispatching properties * \param[in] pbDiagBuffer Diagnostic buffer * \param[in] length Request length * \param[in] position Current request position * \param[in,out] result Resulting properties * \return Possible return values: * - kFblOk: Check successful. If applicable, changed properties are returned via parameter 'result' * - kFblFailed: Check failed **********************************************************************************************************************/ static FBL_DIAG_CHECK_HANDLER(FblDiagCheckFunctional) { return FblDiagCheckState(properties, pbDiagBuffer, length, position, kDiagStateMaskFunctional, result); } /*********************************************************************************************************************** * FblDiagCheckSecurityAccess **********************************************************************************************************************/ /*! \brief Check if the security access states match the service requirements * \param[in] properties Dispatching properties * \param[in] pbDiagBuffer Diagnostic buffer * \param[in] length Request length * \param[in] position Current request position * \param[in,out] result Resulting properties * \return Possible return values: * - kFblOk: Check successful. If applicable, changed properties are returned via parameter 'result' * - kFblFailed: Check failed **********************************************************************************************************************/ static FBL_DIAG_CHECK_HANDLER(FblDiagCheckSecurityAccess) { return FblDiagCheckState(properties, pbDiagBuffer, length, position, kDiagStateMaskSecurityAccess, result); } /*********************************************************************************************************************** * FblDiagCheckSequenceError **********************************************************************************************************************/ /*! \brief Check if the states leading to request sequence errors match the service requirements * \param[in] properties Dispatching properties * \param[in] pbDiagBuffer Diagnostic buffer * \param[in] length Request length * \param[in] position Current request position * \param[in,out] result Resulting properties * \return Possible return values: * - kFblOk: Check successful. If applicable, changed properties are returned via parameter 'result' * - kFblFailed: Check failed **********************************************************************************************************************/ static FBL_DIAG_CHECK_HANDLER(FblDiagCheckSequenceError) { return FblDiagCheckState(properties, pbDiagBuffer, length, position, kDiagStateMaskSequenceError, result); } /*********************************************************************************************************************** * FblDiagCheckGeneralConditions **********************************************************************************************************************/ /*! \brief Check if all possible session states match the service requirements * \param[in] properties Dispatching properties * \param[in] pbDiagBuffer Diagnostic buffer * \param[in] length Request length * \param[in] position Current request position * \param[in,out] result Resulting properties * \return Possible return values: * - kFblOk: Check successful. If applicable, changed properties are returned via parameter 'result' * - kFblFailed: Check failed **********************************************************************************************************************/ static FBL_DIAG_CHECK_HANDLER(FblDiagCheckGeneralConditions) { return FblDiagCheckState(properties, pbDiagBuffer, length, position, kDiagStateMaskGeneralConditions, result); } /*********************************************************************************************************************** * FblDiagCheckLength **********************************************************************************************************************/ /*! \brief Check if the request length matches the service requirements * \param[in] properties Dispatching properties * \param[in] pbDiagBuffer Diagnostic buffer * \param[in] length Request length * \param[in] position Current request position * \param[in,out] result Resulting properties * \return Possible return values: * - kFblOk: Check successful. If applicable, changed properties are returned via parameter 'result' * - kFblFailed: Check failed **********************************************************************************************************************/ /* PRQA S 3673 1 */ /* MD_MSR_Rule8.13 */ static FBL_DIAG_CHECK_HANDLER(FblDiagCheckLength) { vuint8 valid; #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameters not used: avoid compiler warning */ /* PRQA S 3112 3 */ /* MD_MSR_DummyStmt */ (void)pbDiagBuffer; (void)position; (void)result; #endif valid = kFblOk; if ((properties->minLength > 0u) && (length < properties->minLength)) { valid = kFblFailed; } if (length > properties->maxLength) { valid = kFblFailed; } return valid; } /*********************************************************************************************************************** * FblDiagCheckSuppressPosRsp **********************************************************************************************************************/ /*! \brief Evaluate the suppress positive response message bit for subfunction requests * \details No real check, but should only be executed for services with subfunctions * \param[in] properties Dispatching properties * \param[in] pbDiagBuffer Diagnostic buffer * \param[in] length Request length * \param[in] position Current request position * \param[in,out] result Resulting properties * \return Possible return values: * - kFblOk: Check successful. If applicable, changed properties are returned via parameter 'result' * - kFblFailed: Check failed **********************************************************************************************************************/ /* PRQA S 3673 1 */ /* MD_MSR_Rule8.13 */ static FBL_DIAG_CHECK_HANDLER(FblDiagCheckSuppressPosRsp) { #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameter not used: avoid compiler warning */ /* PRQA S 3112 3 */ /* MD_MSR_DummyStmt */ (void)properties; (void)length; (void)result; #endif CheckSuppressPosRspMsgIndication(&pbDiagBuffer[position]); return kFblOk; } #if defined( FBL_DIAG_ENABLE_UPLOAD ) /*********************************************************************************************************************** * FblDiagCheckTransferMode **********************************************************************************************************************/ /*! \brief Evaluate the requested transfer mode. This check is used to switch between download and upload transfers. * \param[in] properties Dispatching properties * \param[in] pbDiagBuffer Diagnostic buffer * \param[in] length Request length * \param[in] position Current request position * \param[in,out] result Resulting properties * \return Possible return values: * - kFblOk: Check successful. If applicable, changed properties are returned via parameter 'result' * - kFblFailed: Check failed **********************************************************************************************************************/ /* PRQA S 3673 1 */ /* MD_MSR_Rule8.13 */ static FBL_DIAG_CHECK_HANDLER(FblDiagCheckTransferMode) { V_MEMROM1 tServiceList V_MEMROM2 * localSubServices; ptServiceProp subSrvLst = V_NULL; /* PRQA S 3679 */ /* MD_MSR_Rule8.13 */ ptServiceProp subService = V_NULL; /* PRQA S 3679 */ /* MD_MSR_Rule8.13 */ vuint8 subSrvIdx; vuint8 found; #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameter not used: avoid compiler warning */ /* PRQA S 3112 3 */ /* MD_MSR_DummyStmt */ (void)pbDiagBuffer; (void)length; (void)position; #endif localSubServices = properties->subServices; subSrvLst = localSubServices->list; found = kFblFailed; for (subSrvIdx = 0; (subSrvIdx < localSubServices->count) && (found != kFblOk); subSrvIdx++) { subService = &subSrvLst[subSrvIdx]; if (STATE_TEST(subService->stateSet, kDiagStateIdxTransferDataUpload) == GetTransferDataUpload()) { found = kFblOk; } } if (found == kFblOk) { *result = subService; } return found; } #endif /* FBL_DIAG_ENABLE_UPLOAD */ #if defined( FBL_ENABLE_SEC_ADDITIONAL_LEVELS ) /*********************************************************************************************************************** * FblDiagSearchSecService **********************************************************************************************************************/ /*! \brief Search the sub service table using the id at the current request position. Special use case for security access * \param[in] properties Dispatching properties * \param[in] pbDiagBuffer Diagnostic buffer * \param[in] length Request length * \param[in] position Current request position * \param[in,out] result Resulting properties * \return Possible return values: * - kFblOk: Search successful. If applicable, changed properties are returned via parameter 'result' * - kFblFailed: Search failed **********************************************************************************************************************/ static FBL_DIAG_CHECK_HANDLER(FblDiagSearchSecService) { V_MEMROM1 tServiceList V_MEMROM2 * localSubServices; ptServiceProp subSrvLst; /* PRQA S 3679 */ /* MD_MSR_Rule8.13 */ ptServiceProp subService; /* PRQA S 3679 */ /* MD_MSR_Rule8.13 */ vuint8 subSrvIdx; vuint8 found; #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameter not used: avoid compiler warning */ /* PRQA S 3112 1 */ /* MD_MSR_DummyStmt */ (void)length; #endif localSubServices = properties->subServices; subSrvLst = localSubServices->list; subService = kDiagNoServiceProp; diagRequestedSecLvlIdx = kDiagInvalidSecLvlIdx; found = kFblFailed; /* Check if level is supported */ for (subSrvIdx = 0; subSrvIdx < (sizeof(kDiagSecAccessParams)/sizeof(kDiagSecAccessParams[0])); subSrvIdx++) { if (kDiagSecAccessParams[subSrvIdx].secLevel == pbDiagBuffer[position] ) { /* Level supported - Seed request */ subService = &subSrvLst[0]; found = kFblOk; break; } if (kDiagSecAccessParams[subSrvIdx].secLevel == (pbDiagBuffer[position] - 1u)) { /* Level supported - Key request */ subService = &subSrvLst[1]; found = kFblOk; break; } } if (found == kFblOk) { /* Cache index of identified table entry for later usage */ diagRequestedSecLvlIdx = subSrvIdx; *result = subService; } return found; } /*********************************************************************************************************************** * FblDiagCheckSecLength **********************************************************************************************************************/ /*! \brief Check if the request length matches the service requirements * \details Special version for security access. * \param[in] properties Dispatching properties * \param[in] pbDiagBuffer Diagnostic buffer * \param[in] length Request length * \param[in] position Current request position * \param[in,out] result Resulting properties * \return Possible return values: * - kFblOk: Check successful. If applicable, changed properties are returned via parameter 'result' * - kFblFailed: Check failed **********************************************************************************************************************/ static FBL_DIAG_CHECK_HANDLER(FblDiagCheckSecLength) { vuint8 valid; assertFblInternal(diagRequestedSecLvlIdx != kDiagInvalidSecLvlIdx, kFblOemAssertInvalidSecLvlIdx); valid = kFblFailed; if (kDiagSecAccessParams[diagRequestedSecLvlIdx].secLevel == pbDiagBuffer[position]) { /* Seed request -> use standard check * This works because pbDiagBuffer is not evaluated any more */ valid = FblDiagCheckLength(properties, pbDiagBuffer, length, position, result); } if (kDiagSecAccessParams[diagRequestedSecLvlIdx].secLevel == (pbDiagBuffer[position] - 1u)) { /* Key request */ if ((kDiagSecAccessParams[diagRequestedSecLvlIdx].keyLength + 1u) == length) { valid = kFblOk; } } return valid; } /*********************************************************************************************************************** * FblDiagCheckSecSequenceError **********************************************************************************************************************/ /*! \brief Check if the states leading to request sequence errors match the service requirements for security access * \param[in] properties Dispatching properties * \param[in] pbDiagBuffer Diagnostic buffer * \param[in] length Request length * \param[in] position Current request position * \param[in,out] result Resulting properties * \return Possible return values: * - kFblOk: Check successful. If applicable, changed properties are returned via parameter 'result' * - kFblFailed: Check failed **********************************************************************************************************************/ static FBL_DIAG_CHECK_HANDLER(FblDiagCheckSecSequenceError) { vuint8 tmpSecLvl; tFblResult valid; assertFblInternal(diagRequestedSecLvlIdx != kDiagInvalidSecLvlIdx, kFblOemAssertInvalidSecLvlIdx); valid = kFblOk; if ((pbDiagBuffer[position] & 0x01u) == 0x01u) { /* Seed request: sub service equals security level */ tmpSecLvl = pbDiagBuffer[position]; if ((kDiagSecLevelNone != GetCurrentSecLvl()) && (tmpSecLvl != GetCurrentSecLvl())) { valid = kFblFailed; } } else { /* Key request: (sub service - 1) equals security level */ tmpSecLvl = pbDiagBuffer[position] - 1; if (diagRequestedSecLvl != tmpSecLvl) { valid = kFblFailed; } } if ((kFblOk == valid ) && (kFblOk == ApplFblGetSecLvlSupport(tmpSecLvl))) { valid = FblDiagCheckState(properties, pbDiagBuffer, length, position, kDiagStateMaskSequenceError, result); } else { valid = kFblFailed; } return valid; } #endif /* FBL_ENABLE_SEC_ADDITIONAL_LEVELS */ /*********************************************************************************************************************** * FblDiagSetState **********************************************************************************************************************/ /*! \brief Set states according to mask * \param[in] state State mask **********************************************************************************************************************/ static void FblDiagSetState (const V_MEMRAM1 tStateBitmap V_MEMRAM2 V_MEMRAM3 * state) { vuint8 idx; #if ( STATECHECK_ARRAYSIZE == 1u) idx = 0u; #else for (idx = 0u; idx < STATECHECK_ARRAYSIZE; idx++) #endif { fblStates[idx] |= state[idx]; } } /*********************************************************************************************************************** * FblDiagClrState **********************************************************************************************************************/ /*! \brief Clear states according to mask * \param[in] state State mask **********************************************************************************************************************/ static void FblDiagClrState (const V_MEMRAM1 tStateBitmap V_MEMRAM2 V_MEMRAM3 * state) { vuint8 idx; #if ( STATECHECK_ARRAYSIZE == 1u) idx = 0u; #else for (idx = 0u; idx < STATECHECK_ARRAYSIZE; idx++) #endif { fblStates[idx] &= FblInvertBits(state[idx], tStateBitmap); } } /*********************************************************************************************************************** * FblDiagRetainState **********************************************************************************************************************/ /*! \brief Retain the value of all masked states, clear all others including the internal states * \param[in] state State mask **********************************************************************************************************************/ static void FblDiagRetainState (V_MEMROM1 tStateBitmap V_MEMROM2 V_MEMROM3 * state) { vuint8 idx; /* Retain values of masked dispatcher states */ #if ( STATECHECK_ARRAYSIZE == 1u) idx = 0u; #else for (idx = 0u; idx < STATECHECK_ARRAYSIZE; idx++) #endif { fblStates[idx] &= state[idx]; } /* Clear all additional internal flags */ for ( ; idx < ARRAY_SIZE(fblStates); idx++) { fblStates[idx] = 0; } } #if defined( FBL_DIAG_ENABLE_SESSION_PARAMETERS ) /*********************************************************************************************************************** * FblDiagGetSessionIndex **********************************************************************************************************************/ /*! \brief Search the diagnostic session table for the requested session type and return the internal session index * \param[in] diagnosticSessionType SessionControl parameter * \return Session index **********************************************************************************************************************/ static vuint8 FblDiagGetSessionIndex(vuint8 diagnosticSessionType) { vuint8 sessionIdx; for (sessionIdx = 0u; sessionIdx < kDiagNumberOfSessions; sessionIdx++) { if (kDiagSessionParameters[sessionIdx].sessionType == diagnosticSessionType) { /* Found valid session */ break; } } if (sessionIdx == kDiagNumberOfSessions) { /* * Config error: this error can only appear if the dispatcher knows more * diagnostic session types than the session parameter table. */ assertFblInternal(0u, kFblOemAssertSessionIndexNotFound); /* PRQA S 2214 */ /* MD_FblDiag_2214 */ sessionIdx = kDiagSessionNotFound; } return sessionIdx; } #endif /* FBL_DIAG_ENABLE_SESSION_PARAMETERS */ #define FBLDIAG_STOP_SEC_CODE #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ /* Diagnostic standard functions ********************************************/ #define FBLDIAG_RAMCODE_START_SEC_CODE #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ /*********************************************************************************************************************** * DiagResetResponseHandling **********************************************************************************************************************/ /*! \brief Reset the status for service handling * \pre Service response shall be finished **********************************************************************************************************************/ static void DiagResetResponseHandling( void ) { DiagClrError(); /* Restart the tester present timer if not in default session */ if (!GetDiagDefaultDiagSession()) { ResetTesterTimeout(); } /* Buffer is now available */ ClrDiagBufferLocked(); /* Reset flag for functional request after processing */ ClrFunctionalRequest(); } /*********************************************************************************************************************** * DiagExRCRResponsePending **********************************************************************************************************************/ /*! \brief Transmit a busy message if timer expires * (forceSend == kNotForceSendResponsePending) or if kForceSendResponsePending is passed. * \param[in] forceSend Determines if a message is sent independently from timer state. **********************************************************************************************************************/ void DiagExRCRResponsePending( vuint8 forceSend ) { static vuint8 rcrrpDiagBuffer[3]; if (GetServiceInProgress()) { if (((GetP2Timeout() > 0x00u) && (GetP2Timer() < (GetP2Timeout()))) || (forceSend == kForceSendResponsePending)) { /* Prepare and transmit RCRRP buffer */ rcrrpDiagBuffer[0] = kDiagRidNegativeResponse; rcrrpDiagBuffer[1] = diagServiceCurrent; rcrrpDiagBuffer[2] = kDiagNrcRcrResponsePending; FblCwTransmitRP(rcrrpDiagBuffer); /* Restart P2-Timer to P2* */ SetP2Timer(kFblDiagTimeP2Star); SetP2Timeout(kFblDiagTimeP2Star); /* PRQA S 3493 */ /* MD_FblDiag_3493 */ /* If response pending is transmitted and no response * is set, a positive response has to be transmitted anyway. */ ClrSuppressPosRspMsg(); /* Prepare parameter for the confirmation function */ SetRcrRpInProgress(); } } } #define FBLDIAG_RAMCODE_STOP_SEC_CODE #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ #define FBLDIAG_START_SEC_CODE #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ /*********************************************************************************************************************** * FblDiagMemGetActiveBuffer **********************************************************************************************************************/ /*! \brief Function updates Diagnostic buffer (DiagBuffer) and returns updated pbDiagData to handler * \return updated pbDiagData buffer used by diagnostic handler functions * **********************************************************************************************************************/ static V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * FblDiagMemGetActiveBuffer(void) { DiagBuffer = FblMemGetActiveBuffer(); return DiagBuffer; } /*********************************************************************************************************************** * DiagDiscardReception **********************************************************************************************************************/ /*! \brief Received diagnostic messages are discarded **********************************************************************************************************************/ static void DiagDiscardReception( void ) { SetResponseProcessing(); /* Set flag for running response procedure */ FblCwDiscardReception(); ClrResponseProcessing(); } /*********************************************************************************************************************** * DiagResponseProcessor **********************************************************************************************************************/ /*! \brief Send diagnostic response message * \pre List of preconditions: * - Current SID must be in DiagBuffer[0] * - diagErrorCode must be initialized * \param[in] dataLength Data length to be transmitted. **********************************************************************************************************************/ void DiagResponseProcessor( tCwDataLengthType dataLength ) { ClrServiceInProgress(); ClrRcrRpInProgress(); ClrP2Timer(); ClrP2Timeout(); DiagDiscardReception(); FblErrStatSetSId(diagServiceCurrent); if (DiagGetError() != kDiagErrorNone) { if (GetFunctionalRequest() && ((DiagGetError() == kDiagNrcServiceNotSupported) || (DiagGetError() == kDiagNrcServiceNotSupportedInActiveSession) || (DiagGetError() == kDiagNrcSubFunctionNotSupported) || (DiagGetError() == kDiagNrcSubfunctionNotSupportedInActiveSession) || (DiagGetError() == kDiagNrcRequestOutOfRange) )) { /* No response for functionally addressed requests if service or subfunction not supported. */ DiagResetResponseHandling(); FblCwResetRxBlock(); } else { /* Prepare response message */ DiagBuffer[kDiagFmtSubparam] = diagServiceCurrent; DiagBuffer[kDiagFmtServiceId] = kDiagRidNegativeResponse; DiagBuffer[kDiagFmtNegResponse] = DiagGetError(); /* Send response in communication wrapper */ FblCwTransmit(DiagBuffer, 3, kFblCwTxCallNegResponse ); } /* Clear 'pending' error */ DiagClrError(); } else if (diagResponseFlag == kDiagPutResponse) { if (!GetSuppressPosRspMsg()) { /* Transmit positive response if not suppressed */ DiagBuffer[kDiagFmtServiceId] = (vuint8)(diagServiceCurrent + 0x40u); /* Send response in communication wrapper */ FblCwTransmit(DiagBuffer, (tCwDataLengthType)(dataLength + 1u), kFblCwTxCallPosResponse); } else { DiagResetResponseHandling(); FblCwResetRxBlock(); ClrSuppressPosRspMsg(); /* Check if a reset shall be generated without message transmission */ if (GetWaitEcuReset()) { /* If so, generate the reset immediately */ SetResetMsgConfirmed(); } } } else { /* Do not send a response, just reset internal state */ DiagResetResponseHandling(); FblCwResetRxBlock(); ClrSuppressPosRspMsg(); /* Check if a reset shall be generated without message transmission */ if (GetWaitEcuReset()) { /* If so, generate the reset immediately */ SetResetMsgConfirmed(); } } /* Response processing executed */ SetProcessingDone(); } /*********************************************************************************************************************** * FblRealTimeSupport **********************************************************************************************************************/ /*! \brief Transmit busy messages and triggers the watchdog according to system timer * \pre P2Timer must be initialized * \return Return code of FblLookForWatchdog **********************************************************************************************************************/ vuint8 FblRealTimeSupport( void ) { vuint8 returnCode; returnCode = FblLookForWatchdog(); DiagExRCRResponsePending(kNotForceSendResponsePending); return returnCode; } /*********************************************************************************************************************** * FblRealTimeSupportVoid **********************************************************************************************************************/ /*! \brief Transmit busy messages and triggers the watchdog according to system timer. * \pre Diagnosis and communication stack must be initialized, diagnostic request has to be received. * \return None **********************************************************************************************************************/ void FblRealTimeSupportVoid( void ) { FblLookForWatchdogVoid(); DiagExRCRResponsePending(kNotForceSendResponsePending); } #if defined( FBL_DIAG_ENABLE_RAM_STATETABLES ) /*********************************************************************************************************************** * FblDiagInitStateTables **********************************************************************************************************************/ /*! \brief Expand condensed service property tables from ROM to RAM **********************************************************************************************************************/ static void FblDiagInitStateTables ( void ) { vuint8 idx; vuint16 bitmapIdx; vuint8 stateIdx; vuint8 stateArrIdx; vuint8 stateMask; static V_MEMROM1 tStateBitmap V_MEMROM2 V_MEMROM3 * sourceState; static V_MEMRAM1 tStateBitmap V_MEMRAM2 V_MEMRAM3 * targetState; bitmapIdx = 0; for (idx = 0; idx < (sizeof(kDiagServicePropertiesROM)/sizeof(kDiagServicePropertiesROM[0])); idx++) { # if defined( FBL_DIAG_SERVICE_LIST_HANDLES ) kDiagServiceProperties[idx].subServices = kDiagSubFctTblHandler[kDiagServicePropertiesROM[idx].subServicesHandler]; # else kDiagServiceProperties[idx].subServices = kDiagServicePropertiesROM[idx].subServices; # endif kDiagServiceProperties[idx].serviceId = kDiagServicePropertiesROM[idx].serviceId; #if defined( FBL_DIAG_CHECK_LIST_HANDLES ) #else kDiagServiceProperties[idx].checks = kDiagServicePropertiesROM[idx].checks; #endif kDiagServiceProperties[idx].minLength = kDiagServicePropertiesROM[idx].minLength; kDiagServiceProperties[idx].maxLength = kDiagServicePropertiesROM[idx].maxLength; kDiagServiceProperties[idx].mainHandlerIdx = kDiagServicePropertiesROM[idx].mainHandlerIdx; #if defined( FBL_DIAG_CHECK_LIST_HANDLES ) kDiagServiceProperties[idx].checkListIdx = kDiagServicePropertiesROM[idx].checkListIdx; #endif #if defined( FBL_DIAG_STATE_ARRAYS ) stateMask = 0x01; #endif for (stateArrIdx = 0; stateArrIdx < STATE_COUNT; stateArrIdx++) { #if defined( FBL_DIAG_STATE_ARRAYS ) targetState = kDiagServiceProperties[idx].states[stateArrIdx]; #else switch (stateArrIdx) { case 0: targetState = kDiagServiceProperties[idx].stateSet; stateMask = 0x01; break; case 1: targetState = kDiagServiceProperties[idx].stateUnset; stateMask = 0x02; break; case 2: targetState = kDiagServiceProperties[idx].stateAdd; stateMask = 0x04; break; case 3: targetState = kDiagServiceProperties[idx].stateClr; stateMask = 0x08; break; case 4: targetState = kDiagServiceProperties[idx].stateClrFail; stateMask = 0x10; break; } #endif if ((kDiagServicePropertiesROM[idx].stateUsage & stateMask) == stateMask) { sourceState = &kDiagStateBitmaps[bitmapIdx]; bitmapIdx += STATECHECK_ARRAYSIZE; } else { sourceState = kDiagStateMaskReset; } # if ( STATECHECK_ARRAYSIZE == 1u) stateIdx = 0; # else for (stateIdx = 0; stateIdx < STATECHECK_ARRAYSIZE; stateIdx++) # endif { targetState[stateIdx] = sourceState[stateIdx]; } stateMask <<= 1; } } } #endif /*********************************************************************************************************************** * FblDiagInitDownloadSequence **********************************************************************************************************************/ /*! \brief (Re-)initialize download sequence (initialization and session transition) **********************************************************************************************************************/ static void FblDiagInitDownloadSequence( void ) { vuint8 blockIdx; /* (Re-)initialize download sequence */ transferRemainder = 0u; transferType = DOWNLOAD_RAM; expectedSequenceCnt = 0u; lastErasedBlock = kBlockNrInvalid; /* Initialize download information structure */ FblDiagSegmentInit(); /* Initialize block information */ currentBlock = kBlockNrInvalid; for (blockIdx = 0u; blockIdx < FBL_LBT_BLOCK_COUNT; blockIdx++) { blockHeader[blockIdx].state = kBlockState_Init; blockHeader[blockIdx].nrOfSegments = 0u; } /* Initialize security module */ (void)ApplFblSecurityInit(); SetCurrentSecLvl(kDiagSecLevelNone); #if defined( FBL_ENABLE_SEC_ADDITIONAL_LEVELS ) /* Initialize security access variables */ diagRequestedSecLvl = kDiagSecLevelNone; diagRequestedSecLvlIdx = kDiagInvalidSecLvlIdx; #endif } /*********************************************************************************************************************** * FblDiagInitPowerOn **********************************************************************************************************************/ /*! \brief Initialize module variables **********************************************************************************************************************/ void FblDiagInitPowerOn( void ) { vuint8 idx; for (idx = 0u; idx < (sizeof(fblStates)/sizeof(fblStates[0])); idx++) { fblStates[idx] = (tStateBitmap)0x00u; } transferRemainder = 0u; transferType = DOWNLOAD_RAM; expectedSequenceCnt = 0u; memSegment = -1; diagResponseFlag = kDiagPutResponse; /* Initialize variables of lib Lbt */ FblLbtInitPowerOn(); DiagClrError(); /* Set diagnostic session (default session) */ SetDiagDefaultDiagSession(); /* Stop tester present timer */ StopTesterTimeout(); /* Clear timer for response pending transmission */ ClrP2Timer(); /* Clear P2 timeout to prevent erroneous sending of RCR-RP */ ClrP2Timeout(); ApplFblResetVfp(); /* Initialize security module */ (void)SecM_InitPowerOn(V_NULL); #if defined( FBL_ENABLE_DEBUG_STATUS ) /* Initialize error status */ ApplFblInitErrStatus(); #endif } /*********************************************************************************************************************** * FblDiagInit **********************************************************************************************************************/ /*! \brief Initialize module variables **********************************************************************************************************************/ /* PRQA S 6050 1 */ /* MD_MSR_STCAL */ void FblDiagInit( void ) { tCwDataLengthType requestLength = 0u; /* Get aligned diag buffer pointer from memory library */ DiagBuffer = FblMemInitPowerOn(); #if defined( FBL_DIAG_ENABLE_RAM_STATETABLES ) FblDiagInitStateTables(); #endif /* Reset service properties */ FblDiagSetProperties(&kDiagServiceProperties[0], &serviceProperties); StopEcuResetTimeout(); /* If FBL was started from application, already lock diagnostic buffer here */ if (FblMainGetStartFromAppl()) { requestLength = kDiagRqlDiagnosticSessionControl + 1u; } /* Release the buffer to be able to respond to request receiv ed by application */ ClrDiagBufferLocked(); if (FblDiagRxGetPhysBuffer(requestLength) == DiagBuffer) { SetLockedByInit(); /* Lock the TP buffer, because service buffer is allocated for pos. response */ FblCwSetRxBlock(); } /* Initialize communication wrapper */ FblCwSetTxInit(); #if defined( FBL_CW_ENABLE_MULTIPLE_CONNECTIONS ) FblCwResetResponseAddress(); #endif /* FBL_CW_ENABLE_MULTIPLE_CONNECTIONS */ #if ( SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC ) # if defined( FBL_ENABLE_TOKEN_DOWNLOAD_HANDLING ) # if defined( FBL_DIAG_MULTIPLE_KEY ) /* Initialized the correct software signing key */ (void)FblDiagCopyUsedPersKeyToUsedNotPersKey(); # endif /* FBL_DIAG_MULTIPLE_KEY */ # endif /* FBL_ENABLE_TOKEN_DOWNLOAD_HANDLING */ #endif /* SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC */ /* Initialize verification component */ (void)SecM_InitVerification(V_NULL); #if defined( FBL_MEM_ENABLE_VERIFY_OUTPUT ) /* Assign segment list array */ verifyParam.segmentList.segmentInfo = verifySegmentInfo; #endif /* FBL_MEM_ENABLE_VERIFY_OUTPUT */ (void)RamDriver_InitSync(V_NULL); FblDiagInitDownloadSequence(); } /*********************************************************************************************************************** * FblDiagGetLastErasedBlock **********************************************************************************************************************/ /*! \brief Returns last erased logical block or kBlockNrInvalid if no block has been erased yet. **********************************************************************************************************************/ vuint8 FblDiagGetLastErasedBlock( void ) { return lastErasedBlock; } /*********************************************************************************************************************** * FblDiagSetLastErasedBlock **********************************************************************************************************************/ /*! \brief Sets last erased logical block. * \param[in] blockNr Block number of last erased logical block **********************************************************************************************************************/ void FblDiagSetLastErasedBlock( vuint8 blockNr ) { lastErasedBlock = blockNr; } /*********************************************************************************************************************** * CheckSuppressPosRspMsgIndication **********************************************************************************************************************/ /*! \brief This functions checks if a diagnostic response has to be sent and resets the positive response * message indication bit if necessary * \param[in,out] subparam Diagnostic subparameter **********************************************************************************************************************/ void CheckSuppressPosRspMsgIndication( V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 *subparam ) { if (((*(subparam)) & (kDiagSuppressPosRspMsgIndicationBit)) != 0u) { SetSuppressPosRspMsg(); /* Set internal flag for response processor */ (*(subparam)) &= FblInvertBits(kDiagSuppressPosRspMsgIndicationBit, vuint8); /* Clear indication bit */ } } /*********************************************************************************************************************** * FblDiagSegmentInit **********************************************************************************************************************/ /*! \brief Initialize the download segment table **********************************************************************************************************************/ static void FblDiagSegmentInit( void ) { currentSegment = kDiagSegmentOutOfRange; diagSegmentList.nrOfSegments = 0u; } /*********************************************************************************************************************** * FblDiagSegmentNext **********************************************************************************************************************/ /*! \brief The parameters of a download section (received by the RequestDownload handler) will be copied into * the segment table. * \param[in] segAddr Start address of download segment * \param[in] segLength Length of download segment * \param[in] blockIdx Index of the logical block which is the target of the download segment * \return Index of current list entry **********************************************************************************************************************/ static vuint8 FblDiagSegmentNext( tFblDiagAddr segAddr, tFblLength segLength, vuint8 blockIdx ) { vuint8 result; /* Compare currently used number of address regions against configured max. value */ if (diagSegmentList.nrOfSegments < SWM_DATA_MAX_NOAR) { currentSegment = diagSegmentList.nrOfSegments; /* Store segment address, length and logical block index for later use */ diagSegmentList.segmentInfo[currentSegment].targetAddress = FblDiagGetMemAddr(segAddr); diagSegmentList.segmentInfo[currentSegment].length = segLength; /* Store reference to this segment in blockHeader */ blockHeader[blockIdx].segmentIdx[blockHeader[blockIdx].nrOfSegments] = currentSegment; /* Increment segment counters */ diagSegmentList.nrOfSegments++; blockHeader[blockIdx].nrOfSegments++; /* Return index of current list entry */ result = currentSegment; } else { /* Segment list full, reject creation of new entry */ result = kDiagSegmentOutOfRange; } return result; } /*********************************************************************************************************************** * FblDiagGetMaxTransferDataBlockLength **********************************************************************************************************************/ /*! \brief Evaluate maximum TransferData block length for active connection * \details Length is the minimum of link payload length and configured diagnostic buffer size * \return TransferData block length applicable for active connection **********************************************************************************************************************/ static tCwDataLengthType FblDiagGetMaxTransferDataBlockLength(void) { tCwDataLengthType maxBlockLength; /* Get payload limit of active communication link */ maxBlockLength = FblCwGetPayloadLimit(); /* Limit block length to available diagnostic buffer size */ if (FBL_DIAG_BUFFER_LENGTH < maxBlockLength) { maxBlockLength = FBL_DIAG_BUFFER_LENGTH; } #if defined( FBL_ENABLE_UNALIGNED_DATA_TRANSFER ) #else /* Align length to maximum memory segment size */ maxBlockLength = (tCwDataLengthType)(((maxBlockLength - 2u) & FblInvert32Bit(FBL_MAX_SEGMENT_SIZE - 1u)) + 2u); #endif /* FBL_ENABLE_UNALIGNED_DATA_TRANSFER */ return maxBlockLength; } /*********************************************************************************************************************** * FblDiagPostInit **********************************************************************************************************************/ /*! \brief This function is called from FblInit() * \details The diagnostic buffer is prepared to be able to handle the diagnostic request. **********************************************************************************************************************/ void FblDiagPostInit( void ) { if (GetLockedByInit()) { if (kFblOk == FblCwPrepareResponseAddress()) { /* Clear state if programming session request "simulation" could be done */ ClrLockedByInit(); /* Prepare diag buffer */ diagServiceCurrent = kDiagSidDiagnosticSessionControl; DiagBuffer[kDiagFmtServiceId] = kDiagSidDiagnosticSessionControl; DiagBuffer[kDiagFmtSubparam] = kDiagSubProgrammingSession; /* Omit response for programming request */ DiagBuffer[kDiagFmtSubparam] |= 0x80u; DiagDataLength = kDiagRqlDiagnosticSessionControl; /* Simulate data indication */ FblDiagRxStartIndication(); FblDiagRxIndication(DiagBuffer, DiagDataLength + 1u); } else { /* Do the same as if a functional tester present with SPRMB was received in order to unlock/free * the diagnostic buffer for new requests */ DiagResetResponseHandling(); FblCwResetRxBlock(); } } } /*********************************************************************************************************************** * FblDiagSessionTransition **********************************************************************************************************************/ /*! \brief Common tasks which shall be executed during session transition * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \return kFblOk: Session transition completed successfully * kFblFailed: Session transition failed **********************************************************************************************************************/ /* PRQA S 3673 1 */ /* MD_MSR_Rule8.13 */ static tFblResult FblDiagSessionTransition(V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 *pbDiagBuffer, tCwDataLengthType diagReqDataLen) { tFblResult result = kFblOk; #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameter not used: avoid compiler warning */ /* PRQA S 3112 2 */ /* MD_MSR_DummyStmt */ (void)pbDiagBuffer; (void)diagReqDataLen; #endif /* Reset internal states */ ClrSecurityKeyAllowed(); ClrTransferDataAllowed(); ClrTransferDataSucceeded(); FblDiagInitDownloadSequence(); return result; } /*********************************************************************************************************************** * FblDiagSessionControlParamInit **********************************************************************************************************************/ /*! \brief General initialization of response parameter and download preparation. * \pre All other conditions for a successful session transition have been fulfilled. * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) **********************************************************************************************************************/ static void FblDiagSessionControlParamInit(V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 *pbDiagBuffer, tCwDataLengthType diagReqDataLen) { #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameter not used: avoid compiler warning */ /* PRQA S 3112 1 */ /* MD_MSR_DummyStmt */ (void)diagReqDataLen; #endif /* * Save the requested session type and adapt the P2 timing (if required). * Note: the SPRMIB has been cleared by CheckSuppressPosRspMsgIndication() * before and doesn't have to be considered here. */ SetDiagSessionType(pbDiagBuffer[kDiagFmtSubparam]); /* Diagnostic session timing */ pbDiagBuffer[kDiagFmtSubparam + 1u] = (vuint8)(GetDiagSessionTimingP2() >> 8u); pbDiagBuffer[kDiagFmtSubparam + 2u] = (vuint8) GetDiagSessionTimingP2(); pbDiagBuffer[kDiagFmtSubparam + 3u] = (vuint8)(GetDiagSessionTimingP2Star() >> 8u); pbDiagBuffer[kDiagFmtSubparam + 4u] = (vuint8) GetDiagSessionTimingP2Star(); } /* Diagnostic service handlers *********************************************/ /*********************************************************************************************************************** * FblDiagMainHandlerDefaultSession **********************************************************************************************************************/ /*! \brief Switch to default session, issue reset if necessary * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerDefaultSession) { /* Switch to default session by issuing a reset */ /* Initialize parameters for SessionControl response */ FblDiagSessionControlParamInit(pbDiagBuffer, diagReqDataLen); /* The response will be sent by FblDiagEcuReset */ FblDiagEcuReset(kDiagResetPutResponse, RESET_RESPONSE_SDS_REQUIRED); /* Shutdown is performed in main loop */ return kFblOk; } /*********************************************************************************************************************** * FblDiagMainHandlerProgrammingSession **********************************************************************************************************************/ /*! \brief Switch to programming session * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ /* PRQA S 3673 1 */ /* MD_MSR_Rule8.13 */ static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerProgrammingSession) { tFblResult result; V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * localPbDiagBuffer; #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameters not used: avoid compiler warning */ /* PRQA S 3112 1 */ /* MD_MSR_DummyStmt */ (void)pbDiagBuffer; #endif /* ESCAN00067433: Stop background operations of FblLib_Mem */ DiagBuffer = FblMemInit(); localPbDiagBuffer = DiagBuffer; /* Deinitialize loaded memory driver(s) */ FblDeinitMemoryDriver(); /* Initialize parameters for SessionControl response */ FblDiagSessionControlParamInit(localPbDiagBuffer, diagReqDataLen); /* * ESCAN00042572: switch session immediately to ensure correct S3 timer * handling in DiagResponseProcessor()/FblDiagTpConfirmation(). */ SetDiagProgrammingSession(); /* Send response */ DiagProcessingDone(kDiagRslDiagnosticSessionControl); /* Execute common (post) session transition tasks */ result = FblDiagSessionTransition(localPbDiagBuffer, diagReqDataLen); return result; } /*********************************************************************************************************************** * FblDiagMainHandlerTesterPresent **********************************************************************************************************************/ /*! \brief TesterPresent service handling * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ /* PRQA S 3673 1 */ /* MD_MSR_Rule8.13 */ static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerTesterPresent) { #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameters not used: avoid compiler warning */ /* PRQA S 3112 2 */ /* MD_MSR_DummyStmt */ (void)pbDiagBuffer; (void)diagReqDataLen; #endif /* Simply transmit a positive response message */ DiagProcessingDone(kDiagRslTesterPresent); return kFblOk; } /*********************************************************************************************************************** * FblDiagMainHandlerEcuReset **********************************************************************************************************************/ /*! \brief Issue reset * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ /* PRQA S 3673 1 */ /* MD_MSR_Rule8.13 */ static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerEcuReset) { #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameters not used: avoid compiler warning */ /* PRQA S 3112 2 */ /* MD_MSR_DummyStmt */ (void)pbDiagBuffer; (void)diagReqDataLen; #endif FblDiagEcuReset(kDiagResetPutResponse, RESET_RESPONSE_ECURESET_REQUIRED); /* Shutdown is performed in main loop */ return kFblOk; } #if defined( FBL_ENABLE_USERROUTINE ) /*********************************************************************************************************************** * FblDiagMainHandlerRoutineControl **********************************************************************************************************************/ /*! \brief RoutineControl - No (predefined) routine found * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerRoutineControl) { tFblResult result; result = kFblOk; /* * Call user function to process user specific routine(s). Pass pointer to * diag buffer which points after the SID. */ ApplDiagRoutineControl(&(pbDiagBuffer[kDiagFmtSubparam]), diagReqDataLen); if (DiagGetError() == kDiagErrorNone) { /* No NRC returned, send the response */ DiagProcessingDone(DiagDataLength); } else { result = kFblFailed; } return result; } #endif /* FBL_ENABLE_USERROUTINE */ /*********************************************************************************************************************** * FblDiagMainHandlerRcActivateSbl **********************************************************************************************************************/ /*! \brief RoutineControl - Activate Secondary Bootloader subroutine * \pre SBL has been downloaded * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ /* PRQA S 6050 1 */ /* MD_MSR_STCAL */ static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerRcActivateSbl) { tFblResult result; tBlockDescriptor blockDescriptor; #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameters not used: avoid compiler warning */ /* PRQA S 3112 1 */ /* MD_MSR_DummyStmt */ (void)diagReqDataLen; #endif /* Send a RCRRP to avoid a timeout during SBL verification and activation */ DiagExRCRResponsePending(kForceSendResponsePending); result = FblLbtGetBlockDescriptorByNr(FBL_LBT_SBL_BLOCK_NUMBER, &blockDescriptor); if (kFblOk == result) { /* Perform SBL block verification */ result = ApplFblValidateBlock(blockDescriptor); } if (kFblOk == result) { /* Set SBL block state to 'verified' */ blockHeader[FBL_MTAB_SBL_BLOCK_NUMBER].state = kBlockState_Verified; result = FblInitMemoryDriver(); } if (result == kFblOk) { /* All following download requests are directed to non-volatile memory */ transferType = DOWNLOAD_FLASH; /* Activation of SBL (and other memory drivers) succeeded, prepare positive response */ pbDiagBuffer[kDiagFmtSubRoutineInfo] = (vuint8)((kDiagSubRoutineType1_Sync << 4u) | kDiagSubRoutineStatusCompleted); } else { /* ESCAN00066098: Activation of SBL failed, send negative response */ DiagNRCConditionsNotCorrect(); } /* Send response */ DiagProcessingDone(kDiagRslRcActivateSbl); return result; } /*********************************************************************************************************************** * FblDiagMainHandlerRcCheckValidApp **********************************************************************************************************************/ /*! \brief RoutineControl - Check Valid Application subroutine * \pre Application software has been downloaded * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ /* PRQA S 6010, 6030, 6050, 6080 1 */ /* MD_MSR_STPTH, MD_MSR_STCYC, MD_MSR_STCAL, MD_MSR_STMIF */ static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerRcCheckValidApp) { tFblResult result; tFblLbtBlockFilter blockFilter; tBlockDescriptor iterBlock; tDiagSegmentList localSegmentList; FL_SegmentListType localSegmentListSB; FL_SegmentInfoType segListPerBlock[SWM_DATA_MAX_NOAR]; vuint8 idxSeg; #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameters not used: avoid compiler warning */ /* PRQA S 3112 1 */ /* MD_MSR_DummyStmt */ (void)diagReqDataLen; #endif /* Initialize return value */ result = kFblOk; /* Initialize localSegmentList */ localSegmentList.nrOfSegments = 0u; for(idxSeg = 0u; idxSeg < SWM_DATA_MAX_NOAR; idxSeg++) { localSegmentList.segmentInfo[idxSeg].targetAddress = 0u; localSegmentList.segmentInfo[idxSeg].length = 0u; } /* Check if any data was downloaded besides the SBL */ if ((kBlockNrInvalid != currentBlock) && (FBL_MTAB_SBL_BLOCK_NUMBER != currentBlock)) { /* Send RCRRP message to avoid a P2 timeout during validation */ DiagExRCRResponsePending(kForceSendResponsePending); /* Iterate over logical blocks to determine the validity of the downloaded software/data */ FblLbtBlockFilterInit(&blockFilter); FblLbtBlockFilterSetBlockType(&blockFilter, kBlockTypeApplication); iterBlock = FblLbtBlockFirst(&blockFilter); while (FblLbtBlockDone() == FALSE) { { /* Check validity of logical block by calling ApplFblValidateBlock() */ if (ApplFblValidateBlock(iterBlock) == kFblOk) { { if (blockHeader[iterBlock.blockNr].state == kBlockState_Erased) { /* Get the segment list */ (void)FblDiagGetSegmentList(iterBlock.blockNr, &localSegmentList); for(idxSeg = 0u; idxSeg < localSegmentList.nrOfSegments; idxSeg++) { segListPerBlock[idxSeg].transferredAddress = localSegmentList.segmentInfo[idxSeg].targetAddress; segListPerBlock[idxSeg].targetAddress = localSegmentList.segmentInfo[idxSeg].targetAddress; segListPerBlock[idxSeg].length = localSegmentList.segmentInfo[idxSeg].length; } localSegmentListSB.nrOfSegments = localSegmentList.nrOfSegments; /* PRQA S 2983 */ /* MD_FblDiag_2983_2985_RedundantAssignment */ localSegmentListSB.segmentInfo = segListPerBlock; /* PRQA S 2983 */ /* MD_FblDiag_2983_2985_RedundantAssignment */ /* Update MAC for Secure Boot */ if (ApplFblUpdateBlockMac(&iterBlock, &localSegmentListSB) == kFblOk) /* PRQA S 2741 */ /* MD_FblDiag_2741 */ { /* Set block state to 'verified' */ blockHeader[iterBlock.blockNr].state = kBlockState_Verified; } else { /* Check logical block assignment */ if (iterBlock.mandatoryType == TRUE) /* PRQA S 2880 */ /* MD_FblDiag_2880_UnreachableCode */ { /* MAC calculation on mandatory Block failed, set overall verification result to 'failed' */ result = kFblFailed; } } } else { /* Set block state to 'verified' */ blockHeader[iterBlock.blockNr].state = kBlockState_Verified; } } } else { /* Check logical block assignment */ if (iterBlock.mandatoryType == TRUE) { /* Mandatory Block not valid, set overall verification result to 'failed' */ result = kFblFailed; } } } /* Prepare next cycle */ iterBlock = FblLbtBlockNext(); } if (kFblOk == result) { /* * All mandatory logical blocks are valid. Let the user do the overall validity check (e.g. compatibility check, * multi-processor configurations). The result has to be persisted inside the user function and can be * evaluated during startup in ApplFblIsValidApp(). */ result = ApplFblValidateApp(); } /* * There are three valid return states of the validation function: * * result | DiagGetError() | state * ------------|-----------------|--------------------------------------- * kFblOk | kDiagErrorNone | download valid, pattern written * kFblFailed | kDiagErrorNone | download invalid, pattern not written * kFblFailed | !kDiagErrorNone | download valid, pattern write error */ /* Catch invalid combinations of return value and NRC state */ assertFblUser(((result == kFblOk) && (DiagGetError() == kDiagErrorNone)) || ((result != kFblOk) && (DiagGetError() == kDiagErrorNone)) || ((result != kFblOk) && (DiagGetError() != kDiagErrorNone)), kFblOemAssertIllegalReturnValue); } /* Proceed only if no NRC has been set in the user functions */ if (DiagGetError() == kDiagErrorNone) { /* Check if all necessary files are present/compatible for the application to be considered valid */ if (ApplFblIsValidApp() != kApplValid) { pbDiagBuffer[kDiagFmtSubRoutineCheckValidAppStatus] = kDiagSubRoutineApplInvalid; /* Send positive response */ DiagProcessingDone(kDiagRslRcCheckValidApp); } else { { pbDiagBuffer[kDiagFmtSubRoutineCheckValidAppStatus] = kDiagSubRoutineApplValid; /* Routine is complete */ pbDiagBuffer[kDiagFmtSubRoutineInfo] = (vuint8)((kDiagSubRoutineType1_Sync << 4u) | kDiagSubRoutineStatusCompleted); /* Send positive response */ DiagProcessingDone(kDiagRslRcCheckValidApp); } } } else { /* Assure correct return value */ result = kFblFailed; } return result; } #if ( SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC ) # if defined( FBL_ENABLE_TOKEN_DOWNLOAD_HANDLING ) /*********************************************************************************************************************** * FblDiagTokenLengthCheck **********************************************************************************************************************/ /*! \brief Check whether that the token length is consistent with the received command * \param[in] cmdType The Token mode from TokenCommandType * \param[in] tokenLength The token length * \return Possible return values: * - tTokenHdlResult: result of the validation operation **********************************************************************************************************************/ /* PRQA S 6010, 6030 1 */ /* MD_MSR_STPTH, MD_MSR_STCYC */ static tTokenHdlResult FblDiagTokenLengthCheck(vuint8 cmdType, vuint16 tokenLength) { tTokenHdlResult resultTkn = kTokenHdlrOk; /* Check that the token length is consistent with the received command */ if (cmdType == FBL_DIAG_TOKEN_CMD_REVERTPROD) { /* Mode 0 tokens are supported with and without signature */ if ((tokenLength != FBL_DIAG_TOKEN_MIN_SIZE) && (tokenLength != (FBL_DIAG_TOKEN_MIN_SIZE + SEC_SIZE_SIG_RSA2048))) { DiagNRCIncorrectMessageLengthOrInvalidFormat(); resultTkn = kTokenHdlrInternalFailed; } } else if (cmdType == FBL_DIAG_TOKEN_CMD_PROGKEY) { /* Mode 5 tokens */ if (tokenLength != FBL_DIAG_TOKEN_MAX_SIZE) { DiagNRCIncorrectMessageLengthOrInvalidFormat(); resultTkn = kTokenHdlrInternalFailed; } } else { /* Mode 1-4 tokens always require a signature */ if (tokenLength != (FBL_DIAG_TOKEN_MIN_SIZE + SEC_SIZE_SIG_RSA2048)) { DiagNRCIncorrectMessageLengthOrInvalidFormat(); resultTkn = kTokenHdlrInternalFailed; } } return resultTkn; } /*********************************************************************************************************************** * FblDiagTokenKeyProcessing **********************************************************************************************************************/ /*! \brief Function is used to perform key switching or key programming based on the received cmdType * \param[in] cmdType The Token mode from TokenCommandType * \param[in] tokenBufferPtr Pointer to the token * \return Possible return values: * - tTokenHdlResult: result of the validation operation **********************************************************************************************************************/ /* PRQA S 3673, 6010, 6030, 6080 1 */ /* MD_MSR_Rule8.13, MD_MSR_STPTH, MD_MSR_STCYC, MD_MSR_STMIF */ static tTokenHdlResult FblDiagTokenKeyProcessing(vuint8 cmdType, V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * tokenBufferPtr) { tTokenHdlResult resultTkn = kTokenHdlrOk; switch (cmdType) { #if defined( FBL_DIAG_MULTIPLE_KEY ) /* Multiple Key Use Case */ case FBL_DIAG_TOKEN_CMD_REVERTPROD: { /* Revert back to production key */ if (FblDiagCopyProductionKeyToUsedPersKey() != SECM_OK) { resultTkn = kTokenHdlrInternalFailed; } else if (FblDiagCopyUsedPersKeyToUsedNotPersKey() != SECM_OK) { resultTkn = kTokenHdlrInternalFailed; } else { /* MISRA */ } break; } case FBL_DIAG_TOKEN_CMD_USEDEVPERM: { /* Use development key until further request */ if (FblDiagCopyDevelopmentKeyToUsedNotPersKey() != SECM_OK) { resultTkn = kTokenHdlrInternalFailed; } else if (FblDiagCopyDevelopmentKeyToUsedPersKey() != SECM_OK) { resultTkn = kTokenHdlrInternalFailed; } else { /* MISRA */ } break; } case FBL_DIAG_TOKEN_CMD_USEDEVTEMP: { /* Use development key until next reset or Cmd 0 */ if (FblDiagCopyDevelopmentKeyToUsedNotPersKey() != SECM_OK) { resultTkn = kTokenHdlrInternalFailed; } break; } case FBL_DIAG_TOKEN_CMD_PROGKEY: { vuint8 pubKeyBuffer[FBL_DIAG_KEY_MOD_LENGTH + FBL_DIAG_KEY_EXP_LENGTH]; /* Program the new keys contained in the token. */ if (ApplFblTokenParseKey(FblDiagGetTokenDevKeyIndex(tokenBufferPtr), pubKeyBuffer) != kTokenHdlrOk) { resultTkn = kTokenHdlrInternalFailed; } else if (FblDiagSetDevelopmentModKey(pubKeyBuffer, FBL_DIAG_KEY_MOD_LENGTH) != SECM_OK) { resultTkn = kTokenHdlrInternalFailed; } else if (FblDiagSetDevelopmentExpKey(&pubKeyBuffer[FBL_DIAG_KEY_MOD_LENGTH], FBL_DIAG_KEY_EXP_LENGTH) != SECM_OK) { resultTkn = kTokenHdlrInternalFailed; } else if (ApplFblTokenParseKey(FblDiagGetTokenTokenKeyIndex(tokenBufferPtr), pubKeyBuffer) != kTokenHdlrOk) { resultTkn = kTokenHdlrInternalFailed; } else if (FblDiagSetTokenModKey(pubKeyBuffer, FBL_DIAG_KEY_MOD_LENGTH) != SECM_OK) { resultTkn = kTokenHdlrInternalFailed; } else if (FblDiagSetTokenExpKey(&pubKeyBuffer[FBL_DIAG_KEY_MOD_LENGTH], FBL_DIAG_KEY_EXP_LENGTH) != SECM_OK) { resultTkn = kTokenHdlrInternalFailed; } else if (ApplFblTokenParseKey(FblDiagGetTokenProdKeyIndex(tokenBufferPtr), pubKeyBuffer) != kTokenHdlrOk) { resultTkn = kTokenHdlrInternalFailed; } else if (FblDiagSetProductionModKey(pubKeyBuffer, FBL_DIAG_KEY_MOD_LENGTH) != SECM_OK) { resultTkn = kTokenHdlrInternalFailed; } else if (FblDiagSetProductionExpKey(&pubKeyBuffer[FBL_DIAG_KEY_MOD_LENGTH], FBL_DIAG_KEY_EXP_LENGTH) != SECM_OK) { resultTkn = kTokenHdlrInternalFailed; } else if (FblDiagSetUsedPersModKey(pubKeyBuffer, FBL_DIAG_KEY_MOD_LENGTH) != SECM_OK) { resultTkn = kTokenHdlrInternalFailed; } else if (FblDiagSetUsedPersExpKey(&pubKeyBuffer[FBL_DIAG_KEY_MOD_LENGTH], FBL_DIAG_KEY_EXP_LENGTH) != SECM_OK) { resultTkn = kTokenHdlrInternalFailed; } else if (FblDiagSetUsedNotPersModKey(pubKeyBuffer, FBL_DIAG_KEY_MOD_LENGTH) != SECM_OK) { resultTkn = kTokenHdlrInternalFailed; } else if (FblDiagSetUsedNotPersExpKey(&pubKeyBuffer[FBL_DIAG_KEY_MOD_LENGTH], FBL_DIAG_KEY_EXP_LENGTH) != SECM_OK) { resultTkn = kTokenHdlrInternalFailed; } else { /* MISRA */ } break; } default: { resultTkn = kTokenHdlrInternalFailed; break; } #else /* FBL_DIAG_MULTIPLE_KEY */ /* Single Key Use Case */ case FBL_DIAG_TOKEN_CMD_REVERTPROD: { /* Revert back to production key */ ClrDiagDevelopmentKey(); break; } case FBL_DIAG_TOKEN_CMD_USEDEVPERM: { /* Use development key permanently (Not possible to revert to production key) */ SetDiagDevelopmentKey(); if (ApplFblWriteVerificationKey(V_NULL) != kFblOk) { resultTkn = kTokenHdlrKeyChangeFailed; /* Revert back to production key, in case of failure */ ClrDiagDevelopmentKey(); } break; } case FBL_DIAG_TOKEN_CMD_USEDEVTEMP: { /* Use development key until next reset or Cmd 0 */ SetDiagDevelopmentKey(); break; } case FBL_DIAG_TOKEN_CMD_PROGKEY: { vuint8 isDevKeyActive = 0u; vuint8 pubKeyBuffer[FBL_DIAG_KEY_MOD_LENGTH + FBL_DIAG_KEY_EXP_LENGTH]; /* Program the production key contained in the token (Not possible to revert to development key) */ if (GetDiagDevelopmentKey()) { isDevKeyActive = 1u; } ClrDiagDevelopmentKey(); if (ApplFblTokenParseKey(FblDiagGetTokenProdKeyIndex(tokenBufferPtr), pubKeyBuffer) == kTokenHdlrOk) { /* The Production Key modulo contains sequentially also the exponent */ if (ApplFblWriteVerificationKey(pubKeyBuffer) != kFblOk) { resultTkn = kTokenHdlrKeyChangeFailed; if (isDevKeyActive == 1u) { SetDiagDevelopmentKey(); } } } else { resultTkn = kTokenHdlrInternalFailed; } break; } default: { resultTkn = kTokenHdlrInternalFailed; break; } #endif /* FBL_DIAG_MULTIPLE_KEY */ } return resultTkn; } /*********************************************************************************************************************** * FblDiagMainHandlerRcTokenDownload **********************************************************************************************************************/ /*! \brief RoutineControl - Download a Token from the tester into internal RAM * \pre Diagnostic module shall be initialized * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ /* PRQA S 6010, 6030, 6080 1 */ /* MD_MSR_STPTH, MD_MSR_STCYC, MD_MSR_STMIF */ static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerRcTokenDownload) { SecM_SignatureParamType verifyToken; SecM_AsymKeyType keyChangeKey; vuint8 *tokenBufferPtr; tTokenHdlResult resultTkn = kTokenHdlrOk;; tFblResult result; vuint8 cmdType; vuint16 tokenLength; /* Check programming mode - if the SBL is not present and activated, send NRC and do not process token further */ if (!GetMemDriverInitialized()) { DiagNRCRequestSequenceError(); } else { tokenLength = diagReqDataLen - 3u; tokenBufferPtr = &pbDiagBuffer[kDiagFmtRoutineIdDataRecord]; /* Token shall be verified with respective key */ verifyTokenSignLength = tokenLength - SEC_SIZE_SIG_RSA2048; /* Extract command */ cmdType = FblDiagGetTokenCommandType(tokenBufferPtr); /* Check that the token length is consistent with the received command */ resultTkn = FblDiagTokenLengthCheck(cmdType, tokenLength); /* Signature verification shall not be done for revert to production command */ if ((cmdType != FBL_DIAG_TOKEN_CMD_REVERTPROD) && (resultTkn == kTokenHdlrOk)) { /* Here the Token signature will be verified */ /* This verification shall be in common between MKU and SKU */ /* Forcing the usage of an internal workspace */ verifyToken.currentHash.sigResultBuffer = (SecM_ResultBufferType)SEC_DEFAULT_WORKSPACE; /* PRQA S 0306 */ /* MD_FblDiag_0306 */ verifyToken.currentHash.length = SEC_DEFAULT_WORKSPACE_SIZE; verifyToken.currentDataLength = V_NULL; verifyToken.sigSourceBuffer = tokenBufferPtr; verifyToken.sigByteCount = verifyTokenSignLength; verifyToken.wdTriggerFct = &FblRealTimeSupportVoid; if (FblDiagGetTokenKeyIndex(tokenBufferPtr) == FBL_DIAG_TOKEN_KEY_INDEX_0) { resultTkn = ApplFblGetTokenVerificationKey(&keyChangeKey); verifyToken.key = (SecM_VerifyKeyType)&keyChangeKey; /* PRQA S 0314 */ /* MD_FblDiag_0314_KeyPtr */ } else { /* For mode 1-4 use default internally configured key */ verifyToken.key = V_NULL; } } if ((cmdType != FBL_DIAG_TOKEN_CMD_REVERTPROD) && (resultTkn == kTokenHdlrOk)) { verifyToken.sigState = SEC_HASH_INIT; resultTkn = kTokenHdlrSignatureFailed; if (FblDiagVerifyTokenSignature(&verifyToken) == SECM_VER_OK) { verifyToken.sigState = SEC_HASH_COMPUTE; if (FblDiagVerifyTokenSignature(&verifyToken) == SECM_VER_OK) { verifyToken.sigState = SEC_HASH_FINALIZE; if (FblDiagVerifyTokenSignature(&verifyToken) == SECM_VER_OK) { verifyToken.sigState = SEC_SIG_VERIFY; verifyToken.sigSourceBuffer = &tokenBufferPtr[verifyTokenSignLength]; verifyToken.sigByteCount = SEC_SIZE_SIG_RSA2048; if (FblDiagVerifyTokenSignature(&verifyToken) == SECM_VER_OK) { resultTkn = kTokenHdlrOk; } } } } } /* Do token validation */ if (resultTkn == kTokenHdlrOk) { resultTkn = ApplFblPreValidateToken(tokenBufferPtr); if(resultTkn == kTokenHdlrOk) { resultTkn = FblDiagValidateToken(tokenBufferPtr); } } /* Do token copy into NVM after validation successfull */ if (resultTkn == kTokenHdlrOk) { /* Token shall be stored into the NVM */ if (ApplFblWriteToken(tokenBufferPtr, tokenLength) != kFblOk) { resultTkn = kTokenHdlrInternalFailed; } } /* For mode 3 and 4 perform only Token validation, other modes perform key switch or key reprogramming */ if ((cmdType != FBL_DIAG_TOKEN_CMD_USEDEVDATE) && (cmdType != FBL_DIAG_TOKEN_CMD_USEDEVIGNI) && (resultTkn == kTokenHdlrOk)) { resultTkn = FblDiagTokenKeyProcessing(cmdType, tokenBufferPtr); } /* Call callouts for every mode */ if (resultTkn == kTokenHdlrOk) { resultTkn = FblDiagTokenCallout(cmdType, tokenBufferPtr, tokenLength); } } if (DiagGetError() == kDiagErrorNone) { /* Send positive response */ pbDiagBuffer[kDiagFmtSubRoutineInfo] = (vuint8)resultTkn; DiagProcessingDone(kDiagRslRcTokenDownload); result = kFblOk; } else { result = kFblFailed; } return result; } # endif /* FBL_ENABLE_TOKEN_DOWNLOAD_HANDLING */ #endif /* SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC */ #if defined( FBL_DIAG_ENABLE_UPDATE_SEC_BYTES ) /*********************************************************************************************************************** * FblDiagMainHandlerRcUpdateSecBytes **********************************************************************************************************************/ /*! \brief RoutineControl - Update Security Bytes subroutine (0x0305) * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerRcUpdateSecBytes) { tFblResult result = kFblOk; #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameter not used: avoid compiler warning */ /* PRQA S 3112 1 */ /* MD_MSR_DummyStmt */ (void)diagReqDataLen; #endif /* Check programming mode - is the SBL present and activated? */ if (!GetMemDriverInitialized()) { DiagNRCConditionsNotCorrect(); } else { /* Check if write request is targeted at the correct security level */ if (pbDiagBuffer[kDiagFmtSubRoutineUpdateSecBytesLevel] != kDiagSecLevelFlash) { /* Invalid security level */ DiagNRCRequestOutOfRange(); } else { /* Write security bytes to non-volatile memory */ result = ApplFblWriteSecurityBytes(&pbDiagBuffer[kDiagFmtSubRoutineUpdateSecBytesValue], kSecSecretKeyLength); } } /* Send response immediately if no NRC has been set */ if (DiagGetError() == kDiagErrorNone) { /* No NRC has been set, prepare positive response */ pbDiagBuffer[kDiagFmtSubRoutineIdPar] = (vuint8)((kDiagSubRoutineType1_Sync << 4) | kDiagSubRoutineStatusCompleted ); /* Send positive response */ DiagProcessingDone(kDiagRslRcUpdateSecBytes); } else { /* NRC has been set, set correct return value */ result = kFblFailed; } return result; } #endif /* FBL_DIAG_ENABLE_UPDATE_SEC_BYTES */ /*********************************************************************************************************************** * FblDiagMainHandlerRcEraseMemory **********************************************************************************************************************/ /*! \brief RoutineControl - EraseMemory subroutine * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ /* PRQA S 6010, 6030, 6050 1 */ /* MD_MSR_STPTH, MD_MSR_STCYC, MD_MSR_STCAL */ static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerRcEraseMemory) { tFblResult result = kFblOk; tBlockDescriptor eraseBlockDescriptor = {0}; tFblMemBlockInfo blockInfo = {0}; tFblAddress eraseAddress = 0u; tFblLength eraseLength = 0u; #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameter not used: avoid compiler warning */ /* PRQA S 3112 1 */ /* MD_MSR_DummyStmt */ (void)diagReqDataLen; #endif /* Initialize return value */ { ClrEraseMemorySucceeded(); /* Extract erase region information from the diag buffer */ eraseAddress = (tFblAddress)FblMemGetInteger(kDiagRqlRcEraseMemoryAddress, &pbDiagBuffer[kDiagFmtSubRoutineEraseMemoryAddress]); eraseLength = (tFblLength)FblMemGetInteger(kDiagRqlRcEraseMemoryLength, &pbDiagBuffer[kDiagFmtSubRoutineEraseMemorySize]); /* Check if the memory driver has been downloaded and initialized */ if (!GetMemDriverInitialized()) { /* Routine not supported in PBL */ DiagNRCConditionsNotCorrect(); result = kFblFailed; } } if (result == kFblOk) { /* Retrieve index of logical block (blockNr is kBlockNrInvalid in case of failure) */ result = FblLbtGetBlockDescriptorByAddressLength(eraseAddress, eraseLength, &eraseBlockDescriptor); if ((result != kFblOk) /* Check exact match of requested erase area with logical block */ || (eraseBlockDescriptor.blockStartAddress != eraseAddress) || (eraseBlockDescriptor.blockLength != eraseLength) ) { DiagNRCRequestOutOfRange(); result = kFblFailed; } } if (result == kFblOk) { /* Check type of requested block */ if (eraseBlockDescriptor.blockNr == FBL_MTAB_SBL_BLOCK_NUMBER) { /* Reject all erase requests which are directed to the SBL block */ DiagNRCRequestOutOfRange(); result = kFblFailed; } } if (result == kFblOk) { #if defined( FBL_ENABLE_FLASH_ERASED_DETECTION ) if (ApplFblGetBlockErased(eraseBlockDescriptor) == kFlashErased) { result = kFblOk; } else #endif /* FBL_ENABLE_FLASH_ERASED_DETECTION */ { /* Avoid P2 timeout during invalidation */ DiagExRCRResponsePending(kForceSendResponsePending); /* Invalidate application before erase procedure */ result = ApplFblInvalidateBlock(eraseBlockDescriptor); /* Catch invalid combinations of return value and NRC state */ assertFblUser(((result == kFblOk) && (DiagGetError() == kDiagErrorNone)) || ((result != kFblOk) && (DiagGetError() != kDiagErrorNone)), kFblOemAssertIllegalReturnValue); /* Proceed only if all entry conditions and block invalidation succeeded */ if (result == kFblOk) { /* Start erase procedure */ blockInfo.targetAddress = eraseBlockDescriptor.blockStartAddress; blockInfo.targetLength = eraseBlockDescriptor.blockLength; blockInfo.logicalAddress = eraseBlockDescriptor.blockStartAddress; blockInfo.logicalLength = eraseBlockDescriptor.blockLength; /* Additional members are not used for erase indication */ result = FblMemRemapStatus(FblMemBlockEraseIndication(&blockInfo)); } if (result == kFblOk) { #if defined( FBL_ENABLE_FLASH_ERASED_DETECTION ) (void)ApplFblSetBlockErased(eraseBlockDescriptor); #endif } } } if (result == kFblOk) { /* Remember erased state */ SetEraseMemorySucceeded(); lastErasedBlock = eraseBlockDescriptor.blockNr; blockHeader[eraseBlockDescriptor.blockNr].state = kBlockState_Erased; } /* Send response immediately if no NRC has been set */ if (DiagGetError() == kDiagErrorNone) { /* No NRC has been set, prepare positive response */ if (result == kFblOk) { pbDiagBuffer[kDiagFmtSubRoutineIdPar] = (vuint8)((kDiagSubRoutineType1_Sync << 4) | kDiagSubRoutineStatusCompleted ); /* Send positive response */ DiagProcessingDone(kDiagRslRcEraseMemory); } else { /* ESCAN00066098: Erase procedure failed, send negative response */ DiagNRCGeneralProgrammingFailure(); } } else { /* NRC has been set, set correct return value */ result = kFblFailed; } return result; } /*********************************************************************************************************************** * FblDiagMainHandlerRcCheckProgDep **********************************************************************************************************************/ /*! \brief RoutineControl - CheckProgrammingDependencies subroutine * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerRcCheckProgDep) { tFblAddress checkStartAddress; tFblLength checkLength; tFblResult result; #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameter not used: avoid compiler warning */ /* PRQA S 3112 1 */ /* MD_MSR_DummyStmt */ (void)diagReqDataLen; #endif /* Extract check address range */ checkStartAddress = FblMemGetInteger(kDiagRqlRcCheckProgDepMemoryAddress, &pbDiagBuffer[kDiagFmtSubRoutineCheckMemoryAddress]); checkLength = FblMemGetInteger(kDiagRqlRcCheckProgDepMemorySize, &pbDiagBuffer[kDiagFmtSubRoutineCheckMemorySize]); if (checkLength < kDiagCheckProgDepAdressMinLength) { /* Address length is under the minimal length */ result = kFblFailed; } else if (FblMemSegmentNrGet(checkStartAddress) < 0) { /* Address start is not located in the Flash Block Table */ result = kFblFailed; } else if (FblMemSegmentNrGet(checkStartAddress + checkLength - 1u) < 0) { /* Address end is not located in the Flash Block Table */ result = kFblFailed; } else { result = kFblOk; } /* Ensure that a valid address */ if (result != kFblOk) { /* Requested download region does not meet requirements; abort service handling */ DiagNRCRequestOutOfRange(); } else { /* Setup segment information */ verifySegmentInfo[0].targetAddress = checkStartAddress; verifySegmentInfo[0].transferredAddress = checkStartAddress; verifySegmentInfo[0].length = checkLength; verifyParam.segmentList.nrOfSegments = 1; /* Trigger checksum calculation */ verifyParam.blockStartAddress = checkStartAddress; verifyParam.blockLength = checkLength; /* No actual verification data included in request */ verifyParam.verificationData = verifyOutputBuf; verifyParam.wdTriggerFct = &FblRealTimeSupportVoid; /* Routine is restricted to ROM access */ verifyParam.readMemory = (FL_ReadMemoryFctType)&FblReadProm; /* Call HIS verification interface to calculate CRC */ if (SECM_VER_OK == FblDiagVerification(&verifyParam)) { /* RoutineInfo */ pbDiagBuffer[kDiagFmtSubRoutineInfo] = (vuint8)((kDiagSubRoutineType1_Sync << 4) | kDiagSubRoutineStatusCompleted); /* CRC value is stored in last two byte of buffer */ /* PRQA S 0314 1 */ /* MD_FblDiag_0314_MemCpy */ (void)MEMCPY(&pbDiagBuffer[kDiagFmtSubRoutineCrcHigh], &verifyOutputBuf[FBL_DIAG_CRC_OFFSET], SEC_SIZE_CHECKSUM_CRC); /* Send positive response */ DiagProcessingDone(kDiagRslRcCheckProgDep); } else { /* ESCAN00066098: Verification failed (most likely memory read error), send negative response */ DiagNRCGeneralReject(); result = kFblFailed; } } return result; } /*********************************************************************************************************************** * FblDiagSecAccessSeed **********************************************************************************************************************/ /*! \brief Process security seed request * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \param[in] secLevel Requested security level * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ static tFblResult FblDiagSecAccessSeed(V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * pbDiagBuffer, tCwDataLengthType diagReqDataLen, vuint8 secLevel ) { vuint8 returnCode; vuint8 i; #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameter not used: avoid compiler warning */ /* PRQA S 3112 2 */ /* MD_MSR_DummyStmt */ (void)diagReqDataLen; (void)secLevel; # if defined( FBL_ENABLE_SEC_ADDITIONAL_LEVELS ) # else (void)pbDiagBuffer; /* PRQA S 3112 */ /* MD_MSR_DummyStmt */ # endif #endif #if ( SYSSERVICE_SECMODHIS_VERSION >= 0x0300u ) /* Cancel all SecM jobs if security access is performed anew, for example if the download is restarted */ SecM_CancelAllJobs(); #endif /* Get currently unlocked level */ if (GetCurrentSecLvl() != kDiagSecLevelNone) { /* ECU is already unlocked, send zero seed */ for (i = 0; i < GetRequestedSeedLength(); i++) { pbDiagBuffer[kDiagFmtSeedKeyStart + i] = 0x00u; } /* Security access already granted. Don't allow a key to be submitted. */ ClrSecurityKeyAllowed(); returnCode = kFblFailed; } else { /* Generate seed by application function */ if (ApplFblSecuritySeed() == kFblOk) { /* Accept security key next */ returnCode = kFblOk; #if defined( FBL_ENABLE_SEC_ADDITIONAL_LEVELS ) /* Remember security level */ diagRequestedSecLvl = pbDiagBuffer[kDiagFmtSubparam]; #endif } else { /* Error occurred during seed computation */ FblErrStatSetError(FBL_ERR_SEED_GENERATION_FAILED); DiagNRCConditionsNotCorrect(); returnCode = kFblFailed; } } #if defined( FBL_ENABLE_SEC_ADDITIONAL_LEVELS ) if (returnCode != kFblOk) { /* Invalidate requested security level */ diagRequestedSecLvlIdx = kDiagInvalidSecLvlIdx; } #endif /* Set response length used by fbl_diag: (SID +) sub parameter + seed length */ DiagProcessingDone(1u + GetRequestedSeedLength()); return returnCode; } /*********************************************************************************************************************** * FblDiagSecAccessKey **********************************************************************************************************************/ /*! \brief Process security key request * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \param[in] secLevel Requested security level * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ /* PRQA S 3673 1 */ /* MD_MSR_Rule8.13 */ static tFblResult FblDiagSecAccessKey(V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * pbDiagBuffer, tCwDataLengthType diagReqDataLen, vuint8 secLevel) { vuint8 returnCode; #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameters not used: avoid compiler warning */ /* PRQA S 3112 2 */ /* MD_MSR_DummyStmt */ (void)diagReqDataLen; (void)secLevel; #endif /* * Clearing the SecurityKeyAllowed state cannot be done automatically * (by the dispatcher) because errors other than key comparison (e.g. * length check) should not reset the state. */ ClrSecurityKeyAllowed(); /* Check security access key in application function */ returnCode = ApplFblSecurityKey(); if (returnCode != kFblOk) { /* Set NRC */ DiagNRCInvalidKey(); } else { SetCurrentSecLvl((vuint8)(pbDiagBuffer[kDiagFmtSubparam] - 1u)); DiagProcessingDone(kDiagRslSecurityAccessKey); } return returnCode; } /*********************************************************************************************************************** * FblDiagMainHandlerSecAccessSeed **********************************************************************************************************************/ /*! \brief SecurityAccess - Seed handling for security level "Flash" * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerSecAccessSeed) { return FblDiagSecAccessSeed(pbDiagBuffer, diagReqDataLen, kDiagSecLevelFlash); } /*********************************************************************************************************************** * FblDiagMainHandlerSecAccessKey **********************************************************************************************************************/ /*! \brief SecurityAccess - Key handling for security level "Flash Programming" * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerSecAccessKey) { return FblDiagSecAccessKey(pbDiagBuffer, diagReqDataLen, kDiagSecLevelFlash); } /*********************************************************************************************************************** * FblDiagMainHandlerRequestDownload **********************************************************************************************************************/ /*! \brief RequestDownload service handling * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ /* PRQA S 2889, 6010, 6030, 6050, 6080 1 */ /* MD_FblDiag_2889, MD_MSR_STPTH, MD_MSR_STCYC, MD_MSR_STCAL, MD_MSR_STMIF */ static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerRequestDownload) { vuint8 lengthFormat = 0u; vuint8 addrFormat = 0u; tFblLbtBlockNr requestedDownloadBlock = 0u; tBlockDescriptor logicalBlockDescriptor = {0}; tFblLength transferLength = 0u; tFblMemSegmentInfo segInfo; tFblMemBlockInfo blockInfo; tFblResult result = kFblOk; tCwDataLengthType maxBlockLength; V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * localPbDiagBuffer = V_NULL; #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) # if defined( FBL_DIAG_ENABLE_FIXED_TRANSFER_ALFI ) /* Parameter not used: avoid compiler warning */ /* PRQA S 3112 1 */ /* MD_MSR_DummyStmt */ (void)diagReqDataLen; # endif #endif /* Initialize return value */ { localPbDiagBuffer = pbDiagBuffer; /* Get encryption and compression method */ dataFormatId = localPbDiagBuffer[kDiagFmtSubparam]; #if defined( FBL_DIAG_ENABLE_FIXED_TRANSFER_ALFI ) if (localPbDiagBuffer[kDiagFmtFormatOffset] != ((vuint8)(kDiagSubMaxLengthFormat << 4u) | kDiagSubMaxAddrFormat)) { DiagNRCRequestOutOfRange(); result = kFblFailed; } lengthFormat = kDiagSubMaxLengthFormat; addrFormat = kDiagSubMaxAddrFormat; #else /* Get address- and length format */ lengthFormat = (vuint8)((localPbDiagBuffer[kDiagFmtFormatOffset] & kDiagFmtLengthMask) >> 4u); addrFormat = (vuint8)(localPbDiagBuffer[kDiagFmtFormatOffset] & kDiagFmtAddrMask); if ((lengthFormat < kDiagSubMinLengthFormat) || (lengthFormat > kDiagSubMaxLengthFormat) || (addrFormat < kDiagSubMinAddrFormat) || (addrFormat > kDiagSubMaxAddrFormat)) { DiagNRCRequestOutOfRange(); result = kFblFailed; } if (result == kFblOk) { if (diagReqDataLen != (kDiagRqlRequestDownload + lengthFormat + addrFormat)) { DiagNRCIncorrectMessageLengthOrInvalidFormat(); result = kFblFailed; } } #endif /* FBL_DIAG_ENABLE_FIXED_TRANSFER_ALFI */ } if (result == kFblOk) { #if defined( FBL_ENABLE_DATA_PROCESSING ) # if defined( FBL_ENABLE_ENCRYPTION_MODE ) # else /* No encrypted data supported */ if (FblDiagGetEncryptionMode(dataFormatId) != kDiagSubNoEncryption) { DiagNRCRequestOutOfRange(); result = kFblFailed; } # endif /* FBL_ENABLE_ENCRYPTION_MODE */ # if defined( FBL_ENABLE_COMPRESSION_MODE ) # else /* No compressed data supported */ if (FblDiagGetCompressionMode(dataFormatId) != kDiagSubNoCompression) { DiagNRCRequestOutOfRange(); result = kFblFailed; } # endif /* FBL_ENABLE_COMPRESSION_MODE */ #else if (dataFormatId != kDiagSubNoDataProcessing) { DiagNRCRequestOutOfRange(); result = kFblFailed; } #endif /* FBL_ENABLE_DATA_PROCESSING */ } if (result == kFblOk) { /* Init expected sequence counter for TransferData */ expectedSequenceCnt = kDiagInitSequenceNum; /* Init current sequence counter for TransferData */ currentSequenceCnt = kDiagInitSequenceNum; /* Extract address and length from request */ transferAddress = (tFblAddress)FblMemGetInteger(addrFormat, &localPbDiagBuffer[kDiagFmtAddrOffset]); transferRemainder = (tFblLength)FblMemGetInteger(lengthFormat, &localPbDiagBuffer[kDiagFmtAddrOffset + addrFormat]); /* Check if length is equal to zero */ if (transferRemainder == 0u) { /* Length zero is unaccepted */ DiagNRCRequestOutOfRange(); result = kFblFailed; } } if (result == kFblOk) { #if defined( FBL_ENABLE_PROCESSED_DATA_LENGTH ) /* * If the requested download contains compressed or encrypted data, the requested download length refers to the * size of the transfer data (i.e. the length of the processed (decrypted/decompressed) data may differ from the * requested download length). */ if (dataFormatId != kDiagSubNoDataProcessing) { /* * Check the start address only. Flash boundary check not possible here because the resulting length of the * processed data is not known. Additional check performed in programming routine. */ transferLength = 1u; } else #endif /* FBL_ENABLE_PROCESSED_DATA_LENGTH */ { transferLength = transferRemainder; } /* Retrieve block descriptor of requested logical block */ result = FblLbtGetBlockDescriptorByAddressLength(transferAddress, transferLength, &logicalBlockDescriptor); /* Ensure that a valid block is set */ if (result != kFblOk) { /* Requested download region is outside of the configured logical blocks; abort service handling */ DiagNRCRequestOutOfRange(); } } if (result == kFblOk) { requestedDownloadBlock = logicalBlockDescriptor.blockNr; if (transferType == DOWNLOAD_FLASH) { /* Check state flags */ if (!GetMemDriverInitialized()) { DiagNRCConditionsNotCorrect(); result = kFblFailed; } } else /* transferType == DOWNLOAD_RAM */ { assertFbl(!GetMemDriverInitialized(), kFblOemAssertIllegalExecutionPath); /* Check type of requested block */ if (requestedDownloadBlock != FBL_MTAB_SBL_BLOCK_NUMBER) { /* Still in PBL: reject all downloads which are not directed to the SBL block */ DiagNRCRequestOutOfRange(); result = kFblFailed; } if (result == kFblOk) { /* Restrict execution sequence and perform auto-erase */ if (blockHeader[requestedDownloadBlock].state == kBlockState_Init) { /* "Erase" flash code array (remove spurious code in buffer, support writing of presence pattern) */ /* Note: since the block state is reset in SessionControl, this will also clean up the flashcode buffer */ assertFbl(FLASH_SIZE == logicalBlockDescriptor.blockLength, kFblSysAssertParameterOutOfRange); if (kFblMemStatus_Ok == FblMemEraseRegion(logicalBlockDescriptor.blockStartAddress, logicalBlockDescriptor.blockLength)) { blockHeader[requestedDownloadBlock].state = kBlockState_Erased; } } } } } if (result == kFblOk) { /* Check if the respective logical block has been erased */ if (blockHeader[requestedDownloadBlock].state != kBlockState_Erased) { /* Requested download region has not been erased; abort service handling */ DiagNRCRequestOutOfRange(); result = kFblFailed; } } if (result == kFblOk) { (void)ApplFblAdjustLbtBlockData(&logicalBlockDescriptor); /* Check if requested download block overwrites presence pattern (or exceeds logical block) */ if ((transferAddress + transferLength) > (logicalBlockDescriptor.blockStartAddress + logicalBlockDescriptor.blockLength)) { DiagNRCRequestOutOfRange(); result = kFblFailed; } } if (result == kFblOk) { /* Copy data and address of segment to initialize diagSegmentList */ if (FblDiagSegmentNext(transferAddress, transferRemainder, requestedDownloadBlock) == kDiagSegmentOutOfRange) { FblErrStatSetError(FBL_ERR_TOO_MANY_SEGMENTS_IN_MODULE); DiagNRCRequestOutOfRange(); result = kFblFailed; } } if (result == kFblOk) { /*** Download request has been accepted ***/ /* Initialize block data used by FblLib_Mem */ blockInfo.targetAddress = logicalBlockDescriptor.blockStartAddress; blockInfo.targetLength = logicalBlockDescriptor.blockLength; blockInfo.logicalAddress = blockInfo.targetAddress; blockInfo.logicalLength = blockInfo.targetLength; blockInfo.verifyRoutineInput.function = V_NULL; blockInfo.verifyRoutineInput.param = V_NULL; blockInfo.segmentList = &verifyParam.segmentList; blockInfo.maxSegments = 1u; /* Only a single segment per block */ #if defined( FBL_MEM_ENABLE_VERIFY_PIPELINED ) /* Check if a customer function is configured for this logical block */ if (SecM_Default != logicalBlockDescriptor.verifyOutput) { /* Switch to output verification (customer function will be set in FblDiagVerification() */ blockInfo.verifyRoutineOutput.function = &FblDiagVerification; blockInfo.verifyRoutineOutput.param = &verifyParam; blockInfo.verifyRoutinePipe.function = V_NULL; blockInfo.verifyRoutinePipe.param = V_NULL; } else { /* Initialize the calculation (CCC: SHA256, DDD: CRC16) */ pipeVerifyParam.currentHash.sigResultBuffer = (vuint32)pipeVerifyBuf; /* PRQA S 0306 */ /* MD_FblDiag_0306 */ pipeVerifyParam.currentHash.length = sizeof(pipeVerifyBuf); pipeVerifyParam.currentDataLength = &pipeVerifyLength; # if ( SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC ) /* Initialize the calculation (CCC: CRC16) */ pipeVerifyParamCrc.currentHash.sigResultBuffer = (vuint32)&pipeVerifyCrc; /* PRQA S 0306 */ /* MD_FblDiag_0306 */ pipeVerifyParamCrc.currentHash.length = sizeof(pipeVerifyCrc); pipeVerifyParamCrc.currentDataLength = &pipeVerifyLengthCrc; blockInfo.verifyRoutinePipe.function = &FblDiagVerifySignature; # else blockInfo.verifyRoutinePipe.function = &SecM_VerifyClassDDD; # endif /* SEC_ENABLE_SECURITY_CLASS_CCC */ blockInfo.verifyRoutinePipe.param = &pipeVerifyParam; blockInfo.verifyRoutineOutput.function = V_NULL; blockInfo.verifyRoutineOutput.param = V_NULL; } #else blockInfo.verifyRoutineOutput.function = &FblDiagVerification; blockInfo.verifyRoutineOutput.param = &verifyParam; blockInfo.verifyRoutinePipe.function = V_NULL; blockInfo.verifyRoutinePipe.param = V_NULL; #endif /* FBL_MEM_ENABLE_VERIFY_PIPELINED */ blockInfo.readFct = &FblReadProm; /* FblWrapperRam required! */ /* Indicate the start of a new download block */ result = FblMemRemapStatus(FblMemBlockStartIndication(&blockInfo)); (void)FblDiagMemGetActiveBuffer(); if (result != kDiagErrorNone) { DiagSetError(result); result = kFblFailed; } } if (result == kFblOk) { /* Initialize segment data */ segInfo.targetAddress = transferAddress; segInfo.targetLength = transferRemainder; segInfo.logicalAddress = segInfo.targetAddress; segInfo.logicalLength = segInfo.targetLength; segInfo.type = kFblMemType_ROM; /* FblWrapperRam required! */ segInfo.dataFormat = dataFormatId; /* Indicate start of new segment */ result = FblMemRemapStatus(FblMemSegmentStartIndication(&segInfo)); localPbDiagBuffer = FblDiagMemGetActiveBuffer(); if (result != kDiagErrorNone) { DiagSetError(result); result = kFblFailed; } } if (result == kFblOk) { /* Download of segment accepted: set logical block as "active" */ currentBlock = requestedDownloadBlock; #if defined( FBL_ENABLE_FLASH_ERASED_DETECTION ) (void)ApplFblClrBlockErased(logicalBlockDescriptor); #endif /* Evaluate maximum block length for TransferData requests */ maxBlockLength = FblDiagGetMaxTransferDataBlockLength(); /* Length format dependent on maximum block length */ /* PRQA S 2880, 2992, 2996 TAG_FblDiag_ConstValue_1 */ /* MD_FblDiag_ConstValue */ if (maxBlockLength > 0xFFFFFFuL) { lengthFormat = 4u; } else if (maxBlockLength > 0xFFFFu) { lengthFormat = 3u; } else { /* Use at least two length bytes */ lengthFormat = 2u; } /* PRQA L:TAG_FblDiag_ConstValue_1 */ /* Set length format and maximum block length */ localPbDiagBuffer[kDiagFmtSubparam] = lengthFormat << 4u; FblMemSetInteger(lengthFormat, maxBlockLength, &localPbDiagBuffer[kDiagFmtMaxBlockLengthHigh]); DiagProcessingDone(kDiagRslRequestDownload + lengthFormat); } else { /* In case this was the RD for the SBL, and OTA is enable, revert the current partition in case of failure */ } return result; } /*********************************************************************************************************************** * FblDiagMainHandlerTransferDataDownload **********************************************************************************************************************/ /*! \brief TransferData service handling * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ /* PRQA S 2889, 3673 1 */ /* MD_FblDiag_2889, MD_MSR_Rule8.13 */ static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerTransferDataDownload) { tFblResult result; /* Check if the requested sequence number is expected */ if (pbDiagBuffer[kDiagFmtSubparam] != expectedSequenceCnt ) { /* Check if sequence number corresponds to a retry */ if (pbDiagBuffer[kDiagFmtSubparam] == currentSequenceCnt) { /* Handle the retries here */ /* Repetition of last transferData request */ /* Simply send a positive response without loading data to memory */ DiagProcessingDone(kDiagRslTransferData); return kFblOk; } else /* Sequence number is not for a retry */ { /* Send a WrongSequenceError */ DiagNRCWrongBlockSequenceCounter(); return kFblFailed; } } result = FblMemRemapStatus(FblMemDataIndication(DiagBuffer, kDiagFmtDataOffset, (tFblLength)diagReqDataLen - 1u)); (void)FblDiagMemGetActiveBuffer(); if (result != kDiagErrorNone) { DiagSetError(result); ClrTransferDataAllowed(); return kFblFailed; } transferRemainder -= ((tFblLength)diagReqDataLen - 1u); if (transferRemainder == 0u) { /* Finalize writing the data */ result = FblMemRemapStatus(FblMemSegmentEndIndication(&totalProgramLength)); (void)FblDiagMemGetActiveBuffer(); if (result != kDiagErrorNone) { DiagSetError(result); return kFblFailed; } result = FblMemRemapStatus(FblMemBlockEndIndication()); if (result != kDiagErrorNone) { DiagSetError(result); return kFblFailed; } } /* Memorize current counter */ currentSequenceCnt = expectedSequenceCnt; /* Sequence counter value of next transferData request */ expectedSequenceCnt++; DiagProcessingDone(kDiagRslTransferData); return kFblOk; } #if defined( FBL_DIAG_ENABLE_UPLOAD ) /*********************************************************************************************************************** * FblDiagMainHandlerRequestUpload **********************************************************************************************************************/ /*! \brief RequestUpload service handling * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ /* PRQA S 2889 1 */ /* MD_FblDiag_2889 */ static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerRequestUpload) { vuint8 lengthFormat, addrFormat; vuint8 requestedUploadBlock; tFblResult result; #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) # if defined( FBL_DIAG_ENABLE_FIXED_TRANSFER_ALFI ) /* Parameter not used: avoid compiler warning */ /* PRQA S 3112 1 */ /* MD_MSR_DummyStmt */ (void)diagReqDataLen; # endif #endif #if defined( FBL_DIAG_ENABLE_FIXED_TRANSFER_ALFI ) if (pbDiagBuffer[kDiagFmtFormatOffset] != ((vuint8)(kDiagSubMaxLengthFormat << 4) | kDiagSubMaxAddrFormat)) { DiagNRCRequestOutOfRange(); return kFblFailed; } lengthFormat = kDiagSubMaxLengthFormat; addrFormat = kDiagSubMaxAddrFormat; #else /* Get address- and length format */ lengthFormat = (vuint8)((pbDiagBuffer[kDiagFmtFormatOffset] & kDiagFmtLengthMask) >> 4); addrFormat = pbDiagBuffer[kDiagFmtFormatOffset] & kDiagFmtAddrMask; if ((lengthFormat < kDiagSubMinLengthFormat) || (lengthFormat > kDiagSubMaxLengthFormat) || (addrFormat < kDiagSubMinAddrFormat) || (addrFormat > kDiagSubMaxAddrFormat)) { DiagNRCRequestOutOfRange(); return kFblFailed; } if (diagReqDataLen != (kDiagRqlRequestDownload + lengthFormat + addrFormat)) { DiagNRCIncorrectMessageLengthOrInvalidFormat(); return kFblFailed; } #endif /* FBL_DIAG_ENABLE_FIXED_TRANSFER_ALFI */ /* Get encryption and compression method */ dataFormatId = pbDiagBuffer[kDiagFmtSubparam]; /* No encrypted or compressed data supported */ if (dataFormatId != kDiagSubNoDataProcessing) { DiagNRCRequestOutOfRange(); return kFblFailed; } /* Extract address and length from request */ transferAddress = (tFblAddress)FblMemGetInteger(addrFormat, &pbDiagBuffer[kDiagFmtAddrOffset]); transferRemainder = (tFblLength)FblMemGetInteger(lengthFormat, &pbDiagBuffer[kDiagFmtAddrOffset + addrFormat]); /* Check if length is equal to zero */ if (transferRemainder == 0u) { /* Length zero is unaccepted */ DiagNRCRequestOutOfRange(); return kFblFailed; } /* Retrieve index of logical block (result is kBlockNrInvalid in case of failure) */ result = FblLbtGetBlockNrByAddressLength(transferAddress, transferRemainder, &requestedUploadBlock); /* Ensure that a valid block number is set */ if (result != kFblOk) { /* Requested download region is outside of the configured logical blocks; abort service handling */ DiagNRCRequestOutOfRange(); return kFblFailed; } /* Save data and address of segment for CRC calculation in TransferExit */ if (FblDiagSegmentNext(transferAddress, transferRemainder, requestedUploadBlock) == kDiagSegmentOutOfRange) { FblErrStatSetError(FBL_ERR_TOO_MANY_SEGMENTS_IN_MODULE); DiagNRCRequestOutOfRange(); return kFblFailed; } /* Check programming mode - is the SBL present and activated? */ if (!GetMemDriverInitialized()) { DiagNRCConditionsNotCorrect(); return kFblFailed; } /* Init expected sequence counter for TransferData */ expectedSequenceCnt = kDiagInitSequenceNum; /* Init current sequence counter for TransferData */ currentSequenceCnt = kDiagInitSequenceNum; /* Use whole diag buffer size as block length for TransferDataUpload */ maxNumberOfBlockLength = (vuint16)FBL_DIAG_BUFFER_LENGTH; /* Number of bytes reserved for maximum block length */ pbDiagBuffer[kDiagFmtSubparam] = kDiagMaxNumberOfBlockLengthLength << 4u; /* Report block length which will be used in TransferDataUpload */ pbDiagBuffer[kDiagFmtMaxBlockLengthHigh] = (vuint8)((maxNumberOfBlockLength >> 8) & 0xFFu); pbDiagBuffer[kDiagFmtMaxBlockLengthLow] = (vuint8)(maxNumberOfBlockLength & 0xFFu); DiagProcessingDone(kDiagRslRequestUpload + kDiagMaxNumberOfBlockLengthLength); return kFblOk; } /*********************************************************************************************************************** * FblDiagMainHandlerTransferDataUpload **********************************************************************************************************************/ /*! \brief TransferData service handling * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ /* PRQA S 2889 1 */ /* MD_FblDiag_2889 */ static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerTransferDataUpload) { /* The transfer data length is static to account for potential retries */ static tCwDataLengthType transferDataUpLength; /* Temporary buffer used to backup data from the diag buffer that is */ /* overwritten by a retry upload request */ static vuint8 tmpUploadBuffer[kDiagFmtTransferDataUploadRetryBackupSize]; #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameter not used: avoid compiler warning */ /* PRQA S 3112 1 */ /* MD_MSR_DummyStmt */ (void)diagReqDataLen; #endif /* Check if the requested sequence number is expected */ if (DiagBuffer[kDiagFmtSequenceCnt] != expectedSequenceCnt ) { /* Check if sequence number corresponds to a retry */ if (DiagBuffer[kDiagFmtSequenceCnt] == currentSequenceCnt) { vuintx i; /* * Repetition of last TransferData request: retrieve the saved data * from temporary buffer. */ for (i = 0u; i < kDiagFmtTransferDataUploadRetryBackupSize; i++) { pbDiagBuffer[kDiagFmtDataOffset + i] = tmpUploadBuffer[i]; } /* Re-upload the data that is still in the buffer */ DiagProcessingDone(transferDataUpLength + 1u); return kFblOk; } else /* Sequence number is not for a retry */ { /* Send a WrongSequenceError */ DiagNRCWrongBlockSequenceCounter(); return kFblFailed; } } else /* Sequence number is equal to the one expected */ { /* Check if anymore data is expected */ if (transferRemainder == 0u) { /* Send NRC TransferDataSuspended and abort, no more data expected! */ DiagNRCTransferDataSuspended(); ClrTransferDataAllowed(); return kFblFailed; } } /* Memorize current counter */ currentSequenceCnt = expectedSequenceCnt; /* Sequence counter value of next TransferData request */ expectedSequenceCnt++; /* * Check if the requested length exceeds the diag buffer size. * kDiagFmtDataOffset accounts for service ID and block sequence counter. */ if (transferRemainder > ((tFblLength)maxNumberOfBlockLength - kDiagFmtDataOffset)) { transferDataUpLength = ((tCwDataLengthType)maxNumberOfBlockLength - kDiagFmtDataOffset); } else { transferDataUpLength = (tCwDataLengthType)transferRemainder; } transferRemainder -= transferDataUpLength; /* * Address being passed is either within flash boundaries or within some * other type of memory supported by the application. */ if (FblReadProm(transferAddress, &pbDiagBuffer[kDiagFmtDataOffset], transferDataUpLength) != transferDataUpLength) { /* Tried accessing non supported memory location */ DiagNRCConditionsNotCorrect(); return kFblFailed; } else /* Success */ { vuintx i; transferAddress += transferDataUpLength; /* * Backup the DATA bytes in the diag buffer which might be overwritten * by the single frame reception with a retry upload request. */ for (i = 0u; i < kDiagFmtTransferDataUploadRetryBackupSize; i++) { tmpUploadBuffer[i] = pbDiagBuffer[kDiagFmtDataOffset + i]; } } DiagProcessingDone(transferDataUpLength + 1u); return kFblOk; } #endif /* FBL_DIAG_ENABLE_UPLOAD */ /*********************************************************************************************************************** * FblDiagMainHandlerRequestTransferExit **********************************************************************************************************************/ /*! \brief RequestTransferExit service handling * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ /* PRQA S 3673, 2889, 6010, 6030, 6050 1 */ /* MD_MSR_Rule8.13, MD_FblDiag_2889, MD_MSR_STPTH, MD_MSR_STCYC, MD_MSR_STCAL */ static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerRequestTransferExit) { tFblResult result; tFblMemVerifyStatus verifyResult; tFblMemBlockVerifyData verifyData = {0}; #if defined( FBL_MEM_ENABLE_VERIFY_PIPELINED ) tExportFct exportFct; #endif #if defined( V_ENABLE_USE_DUMMY_STATEMENT ) /* Parameters not used: avoid compiler warning */ /* PRQA S 3112 1 */ /* MD_MSR_DummyStmt */ (void)diagReqDataLen; # if defined( FBL_DIAG_ENABLE_UPLOAD ) # else (void)pbDiagBuffer; /* PRQA S 3112 */ /* MD_MSR_DummyStmt */ # endif /* FBL_DIAG_ENABLE_UPLOAD */ #endif assertFblInternal(currentSegment != kDiagSegmentOutOfRange, kFblOemAssertIllegalParameter); assertFblInternal(currentBlock != kBlockNrInvalid, kFblOemAssertIllegalParameter); #if defined( FBL_DIAG_ENABLE_UPLOAD ) if (GetTransferDataUpload()) { /* This service is allowed after all bytes of the segment are transferred */ if (transferRemainder != 0u) { DiagNRCRequestSequenceError(); return kFblFailed; } } #endif /* Send an initial response pending message */ DiagExRCRResponsePending(kForceSendResponsePending); /* Calculate CRC16-CITT value of the given memory area */ #if defined( FBL_DIAG_ENABLE_UPLOAD ) if (GetTransferDataUpload()) { result = kFblOk; /* Setup segment information */ verifySegmentInfo[0].targetAddress = diagSegmentList.segmentInfo[currentSegment].targetAddress; verifySegmentInfo[0].transferredAddress = diagSegmentList.segmentInfo[currentSegment].targetAddress; verifySegmentInfo[0].length = diagSegmentList.segmentInfo[currentSegment].length; verifyParam.segmentList.nrOfSegments = 1u; /* Trigger checksum calculation */ verifyParam.blockStartAddress = diagSegmentList.segmentInfo[currentSegment].targetAddress; verifyParam.blockLength = diagSegmentList.segmentInfo[currentSegment].length; /* No actual verification data included in request; result of CRC calculation will be stored here */ verifyParam.verificationData = verifyOutputBuf; verifyParam.wdTriggerFct = &FblRealTimeSupportVoid; /* Upload is restricted to ROM content */ verifyParam.readMemory = (FL_ReadMemoryFctType)&FblReadProm; if (SECM_VER_OK != FblDiagVerification(&verifyParam)) { /* An error occurred during checksum calculation */ return kFblFailed; } /* Restore the segmentInfo entry for download purposes */ diagSegmentList.nrOfSegments--; } else #endif /* FBL_DIAG_ENABLE_UPLOAD */ { #if defined( FBL_ENABLE_PROCESSED_DATA_LENGTH ) /* Update segment information with actually programmed length */ diagSegmentList.segmentInfo[currentSegment].length = totalProgramLength; #endif /* FBL_ENABLE_PROCESSED_DATA_LENGTH */ verifyData.verifyDataInput.length = 0u; verifyData.verifyDataInput.data = V_NULL; #if defined( FBL_MEM_ENABLE_VERIFY_OUTPUT ) && !defined( FBL_MEM_ENABLE_VERIFY_PIPELINED ) /* Output and pipelined verification use the same data as they are used exclusively */ /* No actual verification data included in request */ verifyData.verifyDataOutput.length = FBL_DIAG_VERIFY_BUFFER_SIZE; verifyData.verifyDataOutput.data = verifyOutputBuf; verifyData.verifyDataPipe.length = 0u; verifyData.verifyDataPipe.data = V_NULL; #else /* FBL_MEM_ENABLE_VERIFY_PIPELINED */ /* Check if customer verification function is configured for this block */ result = FblLbtGetBlockVerifyOutputFuncByNr(currentBlock, &exportFct); if (result == kFblOk) { if (SecM_Default == exportFct) { verifyData.verifyDataOutput.length = 0u; verifyData.verifyDataOutput.data = V_NULL; verifyData.verifyDataPipe.length = FBL_DIAG_VERIFY_BUFFER_SIZE; verifyData.verifyDataPipe.data = verifyOutputBuf; } else { /* Customer verification function: switch to output verification */ verifyData.verifyDataOutput.length = FBL_DIAG_VERIFY_BUFFER_SIZE; verifyData.verifyDataOutput.data = verifyOutputBuf; verifyData.verifyDataPipe.length = 0u; verifyData.verifyDataPipe.data = V_NULL; } } else { /* Should never happen */ DiagNRCRequestOutOfRange(); return kFblFailed; } #endif /* FBL_MEM_ENABLE_VERIFY_PIPELINED */ /* Handle LibMem state flags and perform state checks */ result = FblMemRemapStatus(FblMemBlockVerify(&verifyData, &verifyResult)); if (result == kDiagErrorNone) { /* Store segment checksum for later verification in routine CheckValidApp */ /* PRQA S 0314 1 */ /* MD_FblDiag_0314_MemCpy */ (void)MEMCPY(diagSegmentList.segmentInfo[currentSegment].checksum, verifyOutputBuf, SEC_VERIFY_CLASS_DDD_DIGEST_SIZE); } else { DiagSetError(result); return kFblFailed; } } if (DiagGetError() == kDiagErrorNone) { /* No NRC returned, send the response */ /* CRC value is stored in last two byte of buffer */ /* PRQA S 0314 1 */ /* MD_FblDiag_0314_MemCpy */ (void)MEMCPY(&pbDiagBuffer[kDiagFmtRoutineIdHigh], &verifyOutputBuf[FBL_DIAG_CRC_OFFSET], SEC_SIZE_CHECKSUM_CRC); { DiagProcessingDone(kDiagRslRequestTransferExit); } } else { result = kFblFailed; } return result; } /*********************************************************************************************************************** * FblDiagPrepareDidResponse **********************************************************************************************************************/ /*! \brief ReadDataByIdentifier service handling * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] reqDid Requested DID * \param[in] didData Pointer to DID data * \param[in] didLength Data length of the DID * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ static tFblResult FblDiagPrepareDidResponse ( vuint8 *pbDiagBuffer, vuint16 reqDid, tDidDataPtr didData, vuint16 didLen ) { vuint16 dataIdx; tFblResult result = kFblOk; /* Check if data fits into diag buffer */ if ((DiagDataLength + didLen) < FBL_DIAG_BUFFER_LENGTH) { /* Write DID to the diag buffer */ pbDiagBuffer[0] = (vuint8)(reqDid >> 8u); pbDiagBuffer[1] = (vuint8)(reqDid & 0xFFu); if (didData != kDiagComplexDidData) { /* Extract the requested information from DID table */ for (dataIdx = 0u; dataIdx < (didLen - kDiagFmtDataIdSize); dataIdx++) { pbDiagBuffer[kDiagFmtDataIdSize + dataIdx] = didData[dataIdx]; } } else { /* User callback provides the requested information */ result = ApplFblReadDataByIdentifier(pbDiagBuffer, didLen - kDiagFmtDataIdSize); } } else { /* Requested data doesn't fit into diag buffer */ DiagNRCResponseTooLong(); result = kFblFailed; } return result; } /*********************************************************************************************************************** * FblDiagMainHandlerReadDataById **********************************************************************************************************************/ /*! \brief ReadDataByIdentifier service handling * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ /* PRQA S 2889, 6010, 6030, 6080 1 */ /* MD_FblDiag_2889, MD_MSR_STPTH, MD_MSR_STCYC, MD_MSR_STMIF */ static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerReadDataById) { tFblResult result = kFblFailed; /* Check if the length is an odd value. */ if ((diagReqDataLen % 2u) == 1u) { DiagNRCIncorrectMessageLengthOrInvalidFormat(); } else { vuint16 reqDid[FBL_MAX_DID_COUNT]; vuint16 didLen = 0u; vuint8 numberOfDids, didIdx, tableIdx; /* Get pointer to upper byte of first DID */ V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * localPbDiagBuffer = &pbDiagBuffer[1u]; /* Reset response length */ DiagDataLength = 0u; /* Extract DIDs from diag buffer, do while in order to always initialize reqDid */ numberOfDids = 0u; do { reqDid[numberOfDids] = (vuint16)FblMemGetInteger(2u, &localPbDiagBuffer[numberOfDids * 2u]); numberOfDids++; } while (numberOfDids < (diagReqDataLen / 2u)); /* Process requested DIDs */ for (didIdx = 0u; (didIdx < numberOfDids) && (DiagGetError() == kDiagErrorNone); didIdx++) { /* Handle watchdog but omit transmission of RCRRP (REQPROD 74147) */ (void)FblLookForWatchdog(); result = kFblFailed; switch (reqDid[didIdx]) { /* Active Diagnostic Session */ case kDiagDataIdActiveDiagnosticSession: { /* Bootloader supports programming session only */ vuint8 diagSessionType = GetDiagSessionType(); didLen = kDiagFmtDataIdSize + kDiagFmtDataIdActiveDiagnosticSessionSize; result = FblDiagPrepareDidResponse(localPbDiagBuffer, reqDid[didIdx], (tDidDataPtr)&diagSessionType, didLen); break; } /* Software Download Specification Version */ case kDiagDataIdSwdlVersion: { /* SWDL issue kDiagSwdlVersion */ vuint8 swdlVersion = kDiagSwdlVersion; didLen = kDiagFmtDataIdSize + kDiagFmtDataIdSwdlVersionSize; result = FblDiagPrepareDidResponse(localPbDiagBuffer, reqDid[didIdx], (tDidDataPtr)&swdlVersion, didLen); break; } #if defined( FBL_DIAG_ENABLE_DID_CURRENT_DIAG_APP ) /* DID 0xD021: Current Diagnostic Application */ case kDiagDataIdBootloaderCurrentDiagnosticApp: { vuint8 currentDiagnosticApp = kFblDiagAppUnknown; didLen = kDiagFmtDataIdSize + kDiagFmtDataIdBootloaderCurrentDiagAppSize; if (GetMemDriverInitialized()) { currentDiagnosticApp = kFblDiagAppSbl; } else { currentDiagnosticApp = kFblDiagAppPbl; } result = FblDiagPrepareDidResponse(localPbDiagBuffer, reqDid[didIdx], (tDidDataPtr)¤tDiagnosticApp, didLen); break; } #endif /* User handles the other DIDs */ default: { /* Search table of supported DIDs */ for (tableIdx = 0; tableIdx < kNrOfDids; tableIdx++) { if (fblDidTable[tableIdx].did == reqDid[didIdx]) { /* Calculate overall data length for range check and pointer handling */ didLen = kDiagFmtDataIdSize + fblDidTable[tableIdx].size; result = FblDiagPrepareDidResponse(localPbDiagBuffer, reqDid[didIdx], fblDidTable[tableIdx].ptr, didLen); break; } } break; } } if (result == kFblOk) { /* Adjust response length and pointer to diag buffer */ DiagDataLength += didLen; localPbDiagBuffer = &localPbDiagBuffer[didLen]; } } if (DiagGetError() == kDiagErrorNone) { /* Check if at least one DID has been found */ if (DiagDataLength == 0u) { DiagNRCRequestOutOfRange(); result = kFblFailed; } else { /* No NRC returned, send the response */ DiagProcessingDone(DiagDataLength); } } else { result = kFblFailed; } } return result; } #if defined( FBL_DIAG_ENABLE_WRITE_DATA_BY_IDENTIFIER ) /*********************************************************************************************************************** * FblDiagMainHandlerWriteDataById **********************************************************************************************************************/ /*! \brief WriteDataByIdentifier service handling * \param[in] pbDiagBuffer Pointer to the data in the pbDiagBuffer (without SID) * \param[in] diagReqDataLen Length of data (without SID) * \return Possible return values: * - kFblOk: Service processed successfully (goto next state) * - kFblFailed: Service processing failed. **********************************************************************************************************************/ static FBL_DIAG_MAIN_HANDLER(FblDiagMainHandlerWriteDataById) { tFblResult result; /* Pass pointer to diag buffer which points after the SID. */ result = ApplFblWriteDataByIdentifier(&(pbDiagBuffer[kDiagFmtDataIdHigh]), diagReqDataLen); /* Catch invalid combinations of return value and NRC state */ assertFblUser(((result == kFblOk) && (DiagGetError() == kDiagErrorNone)) || ((result != kFblOk) && (DiagGetError() != kDiagErrorNone)), kFblOemAssertIllegalReturnValue); if (DiagGetError() == kDiagErrorNone) { /* No NRC returned, send the response */ DiagProcessingDone(kDiagRslWriteDataByIdentifier); } else { result = kFblFailed; } return result; } #endif /* Diagnostic service functions *********************************************/ /*********************************************************************************************************************** * FblDiagEcuReset **********************************************************************************************************************/ /*! \brief Initiate ECU reset * \param[in] resetOptions OR combination of: * - kDiagResetNoResponse (timeout of TesterPresent) * - kDiagResetPutResponse (service EcuReset received) * - kDiagResetStayInBoot (do not reset active boot mode) * \param[in] responseFlag Value written to reset response flag **********************************************************************************************************************/ void FblDiagEcuReset(vuint8 resetOptions, vuint8 responseFlag) { #if defined( FBL_ENABLE_ECURESET_DELAY ) vuint8 tmpFuncReq = GetFunctionalRequest(); #endif /* Disable tester present timeout monitoring */ StopTesterTimeout(); /* ESCAN00067433: Stop background operations of FblLib_Mem */ FblMemDeinit(); /* Check if a response is required */ if (GetResetOptionPutResponse(resetOptions) && (!GetSuppressPosRspMsg())) { /* Request for reset/FBL-shutdown */ SetWaitEcuReset(); /* Check if response address has been stored successfully */ if (kFblOk == FblCwSaveResponseAddress()) /* PRQA S 2741 */ /* MD_FblDiag_ConstValue */ { /* Transmit response if required */ switch (responseFlag) { case RESET_RESPONSE_SDS_REQUIRED: { DiagProcessingDone(kDiagRslDiagnosticSessionControl); break; } case RESET_RESPONSE_ECURESET_REQUIRED: { DiagProcessingDone(kDiagRslEcuReset); break; } default: { /* Invalid combination of reset option and response flag */ assertFblInternal(0u, kFblOemAssertParameterOutOfRange); break; } } } else { /* PRQA S 2880 1 */ /* MD_FblDiag_ConstValue */ DiagNRCGeneralReject(); } SetEcuResetFctFinished(); } else { /* Do not transmit response message */ DiagSetNoResponse(); DiagProcessingDone(0u); FblDiagDeinit(); } #if defined( FBL_ENABLE_ECURESET_DELAY ) /* Functionally addressed request: wait for a pre-defined time for * responses from the sub nodes */ if (tmpFuncReq != 0) { vuint16 i = FBL_ECURESET_DELAY_TIME; while (i != 0) { /* Watchdog function calls FblCw polling tasks */ if ((FblLookForWatchdog() & FBL_TM_TRIGGERED) == FBL_TM_TRIGGERED) { i--; } } } #endif /* FBL_ENABLE_ECURESET_DELAY */ } /*********************************************************************************************************************** * FblDiagSetProperties **********************************************************************************************************************/ /*! \brief Copy service properties from source to target * \param[in] source Source service properties * \param[out] target Target service properties **********************************************************************************************************************/ /* PRQA S 3673 1 */ /* MD_MSR_Rule8.13 */ static void FblDiagSetProperties(ptServiceProp source, tServiceProp * destination) { vuint8 idx; vuint8 stateIdx; destination->serviceId = source->serviceId; destination->minLength = source->minLength; destination->maxLength = source->maxLength; destination->mainHandlerIdx = source->mainHandlerIdx; destination->subServices = source->subServices; #if defined( FBL_DIAG_STATE_ARRAYS ) for (stateIdx = 0u; stateIdx < STATE_COUNT; stateIdx++) { #if ( STATECHECK_ARRAYSIZE == 1u) idx = 0; #else for (idx = 0u; idx < STATECHECK_ARRAYSIZE; idx++) #endif { destination->states[stateIdx][idx] = source->states[stateIdx][idx]; } } #else #if ( STATECHECK_ARRAYSIZE == 1u) idx = 0u; #else for (idx = 0u; idx < STATECHECK_ARRAYSIZE; idx++) #endif { destination->stateSet[idx] = source->stateSet[idx]; destination->stateUnset[idx] = source->stateUnset[idx]; destination->stateAdd[idx] = source->stateAdd[idx]; destination->stateClr[idx] = source->stateClr[idx]; destination->stateClrFail[idx] = source->stateClrFail[idx]; } #endif } /*********************************************************************************************************************** * FblDiagMergeProperties **********************************************************************************************************************/ /*! \brief Merge existing contents of target service properties with the one from source. * \details Service ID, subservices and handlers will be overwritten if present. Length will be updated if values * are more restrictive. Resulting states are the OR concatenation of the inputs. * \param[in] source Source service properties * \param[out] merge Input service properties, merged with source **********************************************************************************************************************/ /* PRQA S 3673 1 */ /* MD_MSR_Rule8.13 */ static void FblDiagMergeProperties(ptServiceProp source, tServiceProp * merge) { vuint8 idx; #if defined( FBL_DIAG_STATE_ARRAYS ) vuint8 stateIdx; #endif /* PRQA S 2916 TAG_FblDiag_2916_1 */ /* MD_FblDiag_2916 */ merge->serviceId = source->serviceId; if (source->minLength > merge->minLength) { merge->minLength = source->minLength; } if (source->maxLength < merge->maxLength) { merge->maxLength = source->maxLength; } if (source->mainHandlerIdx != (vuint8)kServiceMainHandlerNone) { merge->mainHandlerIdx = source->mainHandlerIdx; } merge->subServices = source->subServices; /* PRQA L: TAG_FblDiag_2916_1 */ #if defined( FBL_DIAG_STATE_ARRAYS ) for (stateIdx = 0u; stateIdx < STATE_COUNT; stateIdx++) { # if ( STATECHECK_ARRAYSIZE == 1u) idx = 0u; # else for (idx = 0u; idx < STATECHECK_ARRAYSIZE; idx++) # endif { merge->states[stateIdx][idx] |= source->states[stateIdx][idx]; } } #else # if ( STATECHECK_ARRAYSIZE == 1u) idx = 0u; # else for (idx = 0u; idx < STATECHECK_ARRAYSIZE; idx++) # endif { merge->stateSet[idx] |= source->stateSet[idx]; merge->stateUnset[idx] |= source->stateUnset[idx]; merge->stateAdd[idx] |= source->stateAdd[idx]; merge->stateClr[idx] |= source->stateClr[idx]; merge->stateClrFail[idx] |= source->stateClrFail[idx]; } #endif } /*********************************************************************************************************************** * FblDiagDispatch **********************************************************************************************************************/ /*! \brief Dispatch the current request in the diagnostic buffer **********************************************************************************************************************/ /* PRQA S 6010, 6030 1 */ /* MD_MSR_STPTH, MD_MSR_STCYC */ static void FblDiagDispatch ( void ) { /* Variables to traverse the service tables */ ptServiceProp prevProp; /* PRQA S 3679 */ /* MD_MSR_Rule8.13 */ ptServiceProp currProp; V_MEMROM1 tServiceList V_MEMROM2 V_MEMROM3 * localSubServices; V_MEMROM1 tServiceCheckList V_MEMROM2 V_MEMROM3 * checkList; V_MEMROM1 tServiceCheck V_MEMROM2 V_MEMROM3 * checkFct; vuint8 chkFctIdx; tCwDataLengthType bufferPos; tFblResult done; /* Set service table entry point */ FblDiagSetProperties(&kDiagServiceProperties[0], &serviceProperties); /* Init traversal variables */ currProp = (ptServiceProp)&kDiagServiceProperties[0]; prevProp = currProp; localSubServices = currProp->subServices; #if defined( FBL_DIAG_CHECK_LIST_HANDLES ) checkList = kServiceCheckListTable[currProp->checkListIdx]; #else checkList = currProp->checks; #endif bufferPos = localSubServices->bufPos; checkFct = (V_MEMROM1 tServiceCheck V_MEMROM2 V_MEMROM3 *)0; done = kFblFailed; /* Run until service was found or error occurred */ while (done != kFblOk) { /* Assume operation finished */ done = kFblOk; /* Run over all check functions of current service */ for (chkFctIdx = 0; chkFctIdx < checkList->count; chkFctIdx++) { /* Execute check function */ checkFct = &(checkList->list)[chkFctIdx]; if ((kServiceCheckHandlerFctTable[checkFct->checkHandlerIdx])(&serviceProperties, DiagBuffer, DiagDataLength, bufferPos, &currProp) == kFblOk) { /* Current service has potentially changed */ if (currProp != prevProp) { /* Merge new properties with existing one */ FblDiagMergeProperties(currProp, &serviceProperties); prevProp = currProp; /* Not finished yet */ done = kFblFailed; } } else { /* Invalidate service */ currProp = kDiagNoServiceProp; break; } } /* Service property has changed */ if (done != kFblOk) { /* Assume operation finished */ done = kFblOk; /* Valid service found */ if (currProp != kDiagNoServiceProp) { /* Get new check functions */ #if defined( FBL_DIAG_CHECK_LIST_HANDLES ) if (currProp->checkListIdx != (vuint8)kServiceCheckListNone) { checkList = kServiceCheckListTable[currProp->checkListIdx]; #else checkList = currProp->checks; if (checkList != (void *)0) { #endif /* Initialize check function */ checkFct = (V_MEMROM1 tServiceCheck V_MEMROM2 V_MEMROM3 *)0; /* Not finished yet, new check functions present */ done = kFblFailed; } /* Get subservices of current service */ localSubServices = currProp->subServices; if (localSubServices != (void *)0) { /* Move to next buffer position */ bufferPos = localSubServices->bufPos; } } } } /* Assume dispatching failed */ serviceResult = kFblFailed; /* No valid subservice found */ if (currProp == kDiagNoServiceProp) { /* Failed check function is known */ if (checkFct != (void *)0) { /* Execute error handler */ if (checkFct->errorHandlerIdx != (vuint8)kServiceErrorHandlerNone) { /* Result of error handler changes execution state */ serviceResult = (kServiceErrorHandlerFctTable[checkFct->errorHandlerIdx])(&serviceProperties, DiagBuffer, DiagDataLength); } /* Error handler wasn't successful and NRC was not set directly */ if ((serviceResult != kFblOk) && (DiagGetError() == kDiagErrorNone)) { /* Set NRC according to check function configuration */ if (checkFct->NRC == kDiagNrcNoResponse) { /* Quiet failure */ DiagSetNoResponse(); DiagProcessingDone(0); } else { /* Set NRC */ DiagSetError(checkFct->NRC); } } } else { /* Operation failed but check function is unknown Set generic NRC */ DiagNRCGeneralReject(); } } else { /* Execute main handler */ if (serviceProperties.mainHandlerIdx != (vuint8)kServiceMainHandlerNone) { serviceResult = (kServiceMainHandlerFctTable[serviceProperties.mainHandlerIdx])(DiagBuffer, DiagDataLength); } } /* Set and clear state flags according to execution result */ if (serviceResult == kFblOk) { FblDiagClrState(serviceProperties.stateClr); FblDiagSetState(serviceProperties.stateAdd); } else { FblDiagClrState(serviceProperties.stateClrFail); } } /*********************************************************************************************************************** * FblDiagTimerTask **********************************************************************************************************************/ /*! \brief This function handles the surveillance of the tester present timer. When a timeout occurs, a reset * is executed. * \pre FblDiagInit has to be executed **********************************************************************************************************************/ void FblDiagTimerTask( void ) { /* Tester present timing */ if (TimeoutTesterValue() != 0u) { DecTimeoutTesterValue(); if (TimeoutTesterValue() == 0u) { /* * Tester present timer expired: * Exit bootloader via reset, but force no response!! */ FblDiagEcuReset(kDiagResetNoResponse, RESET_RESPONSE_NOT_REQUIRED); } } /* ECU reset is pending */ if (TimeoutEcuResetValue() != 0u) { DecTimeoutEcuResetValue(); if (TimeoutEcuResetValue() == 0u) { /* ECU reset timer expired */ /* Exit bootloader via Reset, but force no response!! */ FblDiagEcuReset(kDiagResetNoResponse, RESET_RESPONSE_NOT_REQUIRED); } } } /*********************************************************************************************************************** * FblDiagStateTask **********************************************************************************************************************/ /*! \brief Handle diagnostic indications. * \pre FblDiagInit has to be executed **********************************************************************************************************************/ void FblDiagStateTask( void ) { /* Diagnostic request pending */ if (GetDiagIndication()) { /* Setup state flags */ ClrDiagIndication(); ClrSuppressPosRspMsg(); ClrProcessingDone(); DiagClrError(); /* Indicate an ongoing service processing */ SetServiceInProgress(); /* Dispatch request */ FblDiagDispatch(); /* Call response processor in case of NRC */ if (DiagGetError() != kDiagErrorNone) { DiagResponseProcessor(0); } /* Reset internal state in case no response was sent */ if ((!GetProcessingDone()) && (!GetWaitForRcrRpConf())) { DiagSetNoResponse(); DiagResponseProcessor(0); } } /* Check for reset request */ /* The following preconditions have to be fulfilled: * Reset message confirmed * Pre-reset function (e.g. flag written to NV-memory) has finished */ if (GetWaitEcuReset() && GetResetMsgConfirmed() && GetEcuResetFctFinished()) { { FblDiagDeinit(); } } /* ESCAN00061727: Resume suspended LibMem operation */ FblMemResumeIndication(); } /*********************************************************************************************************************** * FblDiagDeinit **********************************************************************************************************************/ /*! \brief Function prepares for FBL shutdown on diagnostic service request. **********************************************************************************************************************/ static void FblDiagDeinit(void) { /* Deinitialize verification component */ (void)SecM_DeinitVerification(V_NULL); /* Deinitialize loaded memory driver(s) */ FblDeinitMemoryDriver(); /* Reset internal FBL states */ FblDiagRetainState(kDiagStateMaskReset); /* Clear negative response indicator */ DiagClrError(); /* Request shutdown from communication wrapper */ FblCwShutdownRequest(kFblCwResetEcuRegularCase); } /*********************************************************************************************************************** * FblInitMemoryDriver **********************************************************************************************************************/ /*! \brief Initializes the flash driver for usage * \pre Flash driver must be verified * \return kFblOk = initialization successful, kFblFailed = otherwise **********************************************************************************************************************/ static tFblResult FblInitMemoryDriver( void ) { tFblResult result = kFblFailed; IO_ErrorType memErrorCode; if (!GetMemDriverInitialized()) { /* Initialize flash driver version */ FblErrStatSetFlashDrvVersion(); /* Turn on programming voltage (if necessary) */ ApplFblSetVfp(); /* ApplFbl[Set|Reset]Vfp() are not allowed to set a NRC */ assertFblUser((DiagGetError() == kDiagErrorNone), kFblOemAssertIllegalReturnValue); /* Check version and initialize flash driver */ FblCwSetOfflineMode(); memErrorCode = MemDriver_InitSync(V_NULL); FblCwSetOnlineMode(); /* * ESCAN00041016: Require all memory drivers to be correctly initialized * at this point (i.e. non-downloadable drivers, too). */ if (memErrorCode == IO_E_OK) { /* Set Flash driver initialization flag */ SetMemDriverInitialized(); result = kFblOk; } else { /* Flash driver initialization failure */ FblErrStatSetError(FBL_ERR_FLASHCODE_INIT_FAILED); FblErrStatSetFlashDrvError(memErrorCode); /* Reset programming voltage */ ApplFblResetVfp(); /* ApplFbl[Set|Reset]Vfp() are not allowed to set a NRC */ assertFblUser((DiagGetError() == kDiagErrorNone), kFblOemAssertIllegalReturnValue); } } else { /* Flash driver already initialized */ result = kFblOk; } return result; } /*********************************************************************************************************************** * FblDeinitMemoryDriver **********************************************************************************************************************/ /*! \brief Deinitialize memory driver if present **********************************************************************************************************************/ static void FblDeinitMemoryDriver( void ) { if (GetDiagProgrammingSession()) { if (GetMemDriverInitialized()) { /* Deinitialize memory driver flash */ ClrMemDriverInitialized(); /* Remove memory driver from RAM-buffer */ FblCwSetOfflineMode(); { (void)MemDriver_DeinitSync(V_NULL); } FblCwSetOnlineMode(); } /* Turn off programming voltage */ ApplFblResetVfp(); } } /* Ford specific functions **********************************************/ #if defined( FBL_MEM_ENABLE_VERIFY_OUTPUT ) /*********************************************************************************************************************** * FblDiagVerification - Ford specific **********************************************************************************************************************/ /*! \brief This function calls the HIS verification interface to calculate the CRC16 value over the requested * address region in non-volatile memory. * \pre Address region check has been performed (FblDiagAddressRegionCheck) * \param[in] verifyParam Parameter structure for verification * \return Result of operation **********************************************************************************************************************/ static SecM_StatusType FblDiagVerification(V_MEMRAM1 SecM_VerifyParamType V_MEMRAM2 V_MEMRAM3 * verifyPar) { tBlockDescriptor blockDescriptor; tFblMemVerifyFctOutput verifyFct; /* Set default verification function */ verifyFct = &SecM_VerificationClassDDD; /* * Note: general address region check is expected to be performed before this * function is called (e.g. in FblDiagMainHandlerRequestDownload/Upload, FblDiagMainHandlerRcCheckProgDep). */ if (FblLbtGetBlockDescriptorByAddressLength(verifyPar->blockStartAddress, verifyPar->blockLength, &blockDescriptor) == kFblOk) { if (SecM_Default != blockDescriptor.verifyOutput) { /* Logical block no. has been determined successfully: assign block specific verification function */ verifyFct = (tFblMemVerifyFctOutput)blockDescriptor.verifyOutput; /* PRQA S 0313 */ /* MD_FblDiag_0313_VerifyFctOutput */ } } /* Perform verification */ return verifyFct(verifyPar); } #endif #if defined( FBL_MEM_ENABLE_VERIFY_PIPELINED ) && ( SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC ) /*********************************************************************************************************************** * FblDiagVerifySignature **********************************************************************************************************************/ /*! \brief This function calls the HIS verification interface to calculate the CRC16 value over the requested * address region in non-volatile memory (pipelined mode). * \pre Address region check has been performed (FblDiagAddressRegionCheck) * \param[in] pVerifyParam Parameter structure for verification * \return Result of operation **********************************************************************************************************************/ static SecM_StatusType FblDiagVerifySignature( V_MEMRAM1 SecM_SignatureParamType V_MEMRAM2 V_MEMRAM3 * pVerifyParam ) { SecM_StatusType result; SecM_LengthType byteCount; result = SECM_VER_ERROR; pipeVerifyParamCrc.sigState = pVerifyParam->sigState; pipeVerifyParamCrc.sigSourceBuffer = pVerifyParam->sigSourceBuffer; pipeVerifyParamCrc.sigByteCount = pVerifyParam->sigByteCount; pipeVerifyParamCrc.wdTriggerFct = pVerifyParam->wdTriggerFct; switch (pVerifyParam->sigState) { case SEC_HASH_INIT: case SEC_HASH_COMPUTE: case SEC_HASH_FINALIZE: { result = SecM_VerifyClassDDD(pVerifyParam); (void)SecM_VerifyChecksumCrc(&pipeVerifyParamCrc); break; } case SEC_SIG_VERIFY: { result = SecM_VerifyClassDDD(pVerifyParam); byteCount = pVerifyParam->sigByteCount; pipeVerifyParamCrc.sigSourceBuffer = &pVerifyParam->sigSourceBuffer[byteCount]; pipeVerifyParamCrc.sigByteCount -= byteCount; (void)SecM_VerifyChecksumCrc(&pipeVerifyParamCrc); pVerifyParam->sigByteCount += pipeVerifyParamCrc.sigByteCount; break; } default: { /* Nothing to do */ break; } } return result; } #endif /* FBL_MEM_ENABLE_VERIFY_PIPELINED && ( SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC ) */ #if defined( FBL_ENABLE_STAY_IN_BOOT ) /*********************************************************************************************************************** * FblDiagCheckStartMsg - Ford Specific **********************************************************************************************************************/ /*! \brief Check if the OEM specific start message has been received * \pre Start message reception has to be verified by ComWrapper * \param[in] pData Pointer to received data * \param[in] length Length of received data * \return Possible return values: * - kFblOk: OEM specific start message has been identified * - kFblFailed: Received message doesn't equal the OEM specific start message **********************************************************************************************************************/ vuint8 FblDiagCheckStartMsg(const V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 *pData, vuintx length) { vuint8 result; /* Initialize variables */ result = kFblFailed; /* Check if received data is long enough */ if (length >= (kDiagRqlDiagnosticSessionControl + 2u)) { /* Check complete message contents for Stay-In-Boot */ /* For Ford, this is: 0x02 0x10 0x02 (DiagnosticSessionControl/ProgrammingSession) */ if ( ( pData[0] == (kDiagRqlDiagnosticSessionControl + 1u)) /* Add the service ID */ && ( pData[kDiagFmtServiceId + 1u] == kDiagSidDiagnosticSessionControl) && ((pData[kDiagFmtSubparam + 1u] & 0x7Fu) == kDiagSubProgrammingSession)) /* Suppressed bit may be true or false */ { /* Start message received */ result = kFblOk; } } return result; } #endif /* FBL_ENABLE_STAY_IN_BOOT */ /*********************************************************************************************************************** * FblDiagGetSegmentList **********************************************************************************************************************/ /*! \brief Returns a list of download segments which have been programmed into a certain logical block * \param[in] blockIdx Index of the logical block for which the associated download segments shall be returned * \param[out] blockSegList Pointer to local segment list which shall keep the respective download segments * \return Number of download segment which are associated with the requested logical block **********************************************************************************************************************/ vuint8 FblDiagGetSegmentList(vuint8 blockIdx, V_MEMRAM1 tDiagSegmentList V_MEMRAM2 V_MEMRAM3 * blockSegList) { vuint8 listIdx; blockSegList->nrOfSegments = 0u; for (listIdx = 0u; listIdx < blockHeader[blockIdx].nrOfSegments; listIdx++) { blockSegList->segmentInfo[blockSegList->nrOfSegments] = diagSegmentList.segmentInfo[blockHeader[blockIdx].segmentIdx[listIdx]]; blockSegList->nrOfSegments++; } return blockSegList->nrOfSegments; } #define FBLDIAG_STOP_SEC_CODE #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ /* Communication wrapper callback functions **********************************/ #define FBLDIAG_RAMCODE_START_SEC_CODE #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ /*********************************************************************************************************************** * FblDiagTxErrorIndication **********************************************************************************************************************/ /*! \brief Indicates that an error has occurred during transmission. * \details According to ISO-14229, now the S3 timer must be restarted. * \pre TP must been initialized * \param[in] cwMsgType Message type of indication (defined in CW layer): * - kFblCwMsgTypeRcrRp: Request correctly received/response pending message * - kFblCwMsgTypeNormal: Normal request message **********************************************************************************************************************/ void FblDiagTxErrorIndication( vuint8 cwMsgType ) { /* Do not reset states for RCR-RP confirmation */ if (cwMsgType != kFblCwMsgTypeRcrRp) { DiagResetResponseHandling(); } } /*********************************************************************************************************************** * FblDiagRxStartIndication **********************************************************************************************************************/ /*! \brief Data reception call-back function to start diagnostic service processing. * \details Valid TesterPresent requests will simply start the S3 timer and will not be processed. * \pre TP reception successful **********************************************************************************************************************/ void FblDiagRxStartIndication( void ) { /* Halts the S3 timer while receiving a diagnostic message */ StopTesterTimeout(); } /*********************************************************************************************************************** * FblDiagRxErrorIndication **********************************************************************************************************************/ /*! \brief Indicates that an error has occurred during reception. * \details According to ISO-14229, now the S3 timer must be restarted. * \pre TP must been initialized **********************************************************************************************************************/ void FblDiagRxErrorIndication( void ) { DiagResetResponseHandling(); } /*********************************************************************************************************************** * FblDiagRxIndication **********************************************************************************************************************/ /*! \brief Data reception call-back function to start diagnostic service processing. * \details Valid TesterPresent requests will simply start the S3 timer and will not be processed. * \pre TP reception successful * \param[in] pbDiagBuffer Pointer to diagnostic buffer * \param[in] rxDataLength Number of bytes to be received **********************************************************************************************************************/ /* PRQA S 3673 1 */ /* MD_MSR_Rule8.13 */ void FblDiagRxIndication( V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * pbDiagBuffer, tCwDataLengthType rxDataLength ) { /* Check for functionally addressed valid TesterPresent message with SuppressPosRsp */ if ((kDiagSidTesterPresent == pbDiagBuffer[kDiagFmtServiceId]) && (kDiagSuppressPosRspMsgIndicationBit == pbDiagBuffer[kDiagFmtSubparam]) && (kDiagRqlTesterPresent == (rxDataLength - 1u)) && GetFunctionalRequest() ) { /* Bypass logic for this TesterPresent message */ DiagResetResponseHandling(); /* Reset tester timeout */ FblCwResetRxBlock(); } else { /* Start regular service processing */ DiagClrError(); diagResponseFlag = kDiagPutResponse; diagServiceCurrent = pbDiagBuffer[kDiagFmtServiceId]; SetP2Timer(kFblDiagTimeP2); /* Reset P2 timer (initial timing) */ SetP2Timeout(kFblDiagTimeP2); /* PRQA S 3493 */ /* MD_FblDiag_3493 */ DiagDataLength = rxDataLength - 1u; SetDiagIndication(); #if defined( FBL_MEM_ENABLE_PIPELINING ) if (FblMemTaskIsPending()) { FblMemRxNotification(); } #endif } /* Initialize security seed */ (void)ApplFblSecuritySeedInit(); #if defined( FBL_ENABLE_SLEEPMODE ) /* Request received - reload sleep counter */ FblSleepCounterReload(); #endif } /*********************************************************************************************************************** * FblDiagTxConfirmation **********************************************************************************************************************/ /*! \brief TP transmission call-back function. * \pre TP transmission successful * \param[in] cwMsgType Message type of indication (defined in CW layer): * - kFblCwMsgTypeRcrRp: Request correctly received/response pending message * - kFblCwMsgTypeNormal: Normal request message **********************************************************************************************************************/ void FblDiagTxConfirmation( vuint8 cwMsgType ) { /* Do not reset states for RCR-RP confirmation */ if (cwMsgType != kFblCwMsgTypeRcrRp) { DiagResetResponseHandling(); } /* Diag wants to reset FBL after sending an RCR-RP */ if (GetWaitEcuReset()) { SetResetMsgConfirmed(); } } /*********************************************************************************************************************** * FblDiagRxGetPhysBuffer **********************************************************************************************************************/ /*! \brief Diagnostic buffer management function for physical requests. * \param[in] rxDataLength Number of bytes to be received * \return Possible return values: * - Pointer to diagnostic buffer * - V_NULL in case no buffer is available **********************************************************************************************************************/ vuint8* FblDiagRxGetPhysBuffer( tCwDataLengthType rxDataLength ) { vuint8* result; /* Check request length and if buffer is free */ if ((rxDataLength > 0u ) && (FBL_DIAG_BUFFER_LENGTH >= rxDataLength) && (!GetDiagBufferLocked())) { /* Initialize state variables */ ClrFunctionalRequest(); /* Lock buffer */ SetDiagBufferLocked(); /* Return diagnostic buffer */ result = DiagBuffer; } else { /* Illegal buffer request, return null pointer */ result = V_NULL; } return result; } /*********************************************************************************************************************** * FblDiagRxGetFuncBuffer **********************************************************************************************************************/ /*! \brief Diagnostic buffer management function for functional requests. * \param[in] rxDataLength Number of bytes to be received * \return Possible return values: * - Pointer to diagnostic buffer * - V_NULL in case no buffer is available **********************************************************************************************************************/ vuint8* FblDiagRxGetFuncBuffer( tCwDataLengthType rxDataLength ) { /* Process functional request like physical request */ vuint8* diagnosticBuffer = FblDiagRxGetPhysBuffer(rxDataLength); /* Set functional request indication */ if (V_NULL != diagnosticBuffer) { SetFunctionalRequest(); } return diagnosticBuffer; } #define FBLDIAG_RAMCODE_STOP_SEC_CODE #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ #define FBLDIAG_START_SEC_CODE #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ /*********************************************************************************************************************** * FblDiagMemPreWrite **********************************************************************************************************************/ /*! \brief Function performs actions before FblLib_Mem calls the memory driver write function. * \return Possible return values: * - kFblOk: Pre-write operations are successful * - kFblFailed: Pre-write operations failed **********************************************************************************************************************/ tFblResult FblDiagMemPreWrite( void ) { FblCwSetOfflineMode(); return kFblOk; } /*********************************************************************************************************************** * FblDiagMemPostWrite **********************************************************************************************************************/ /*! \brief Checks if message is the platform message or not * \return Possible return values: * - kFblOk: Post-write operations are successful * - kFblFailed: Post-write operations failed **********************************************************************************************************************/ tFblResult FblDiagMemPostWrite( void ) { FblCwSetOnlineMode(); return kFblOk; } #if ( SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC ) # if defined( FBL_ENABLE_TOKEN_DOWNLOAD_HANDLING ) /*********************************************************************************************************************** * FblDiagValidateToken **********************************************************************************************************************/ /*! \brief Validate the token against main validity rules * \return Possible return values: * - tTokenHdlResult: result of the validation operation **********************************************************************************************************************/ /* PRQA S 6010, 6030 1 */ /* MD_MSR_STPTH, MD_MSR_STCYC */ static tTokenHdlResult FblDiagValidateToken( const V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * tokenBuf ) { tTokenHdlResult result; vuintx idx; vuint8 const *fesnPtr = FblDiagGetFesn(); result = kTokenHdlrInternalFailed; /* Check if Server Message ID is required and valid */ if (FblDiagIsTokenMsgIDRequired(tokenBuf)) { if (FblDiagCheckServerMessageId(tokenBuf) == kFblOk) { result = kTokenHdlrOk; } } /* Is KeyID present? */ if ( (result == kTokenHdlrOk) && (FblDiagIsTokenKeyIDRequired(tokenBuf)) ) { /* KeyID must not be present */ result = kTokenHdlrInternalFailed; } /* Are reserved bits set? */ if ( (result == kTokenHdlrOk) && (FblDiagIsTokenReserverdBitsSet(tokenBuf)) ) { /* Reserved bits must not be set */ result = kTokenHdlrInternalFailed; } /* Is FESN present? */ if ( (result == kTokenHdlrOk) && FblDiagIsTokenFesnRequired(tokenBuf) && (FblDiagGetTokenCommandType(tokenBuf) != FBL_DIAG_TOKEN_CMD_PROGKEY) ) { /* Check if FESN match */ for (idx = 0u; idx < FBL_DIAG_TOKEN_FESN_LEN; idx++) { if (FblDiagGetTokenFesn(tokenBuf)[idx] != fesnPtr[idx]) { result = kTokenHdlrFesnFailed; } } } /* For Mode 5 check the first three characters of the FESN */ if ( (result == kTokenHdlrOk) && (FblDiagGetTokenCommandType(tokenBuf) == FBL_DIAG_TOKEN_CMD_PROGKEY) ) { if (FblDiagIsTokenFesnRequired(tokenBuf)) { /* FESN required bit must not be set for mode 5 token */ result = kTokenHdlrFesnFailed; } else { /* Check if the first 3 character of the FESN match */ for (idx = 0u; idx < FBL_DIAG_TOKEN_MOD5_FESN_LEN; idx++) { if (FblDiagGetTokenPayloadFesn(tokenBuf)[idx] != fesnPtr[idx]) { result = kTokenHdlrFesnFailed; } } } } /* Check if CPU destination match */ if ((result == kTokenHdlrOk) && (FblDiagGetTokenCPUDestination(tokenBuf) != FBL_DIAG_TOKEN_CPU_DEST)) { result = kTokenHdlrInternalFailed; } /* Check if service type match */ if ((result == kTokenHdlrOk) && (FblDiagGetTokenServiceType(tokenBuf) != FBL_DIAG_TOKEN_SERVICE_TYPE)) { result = kTokenHdlrInternalFailed; } /* Check if crypto type match */ if ((result == kTokenHdlrOk) && (FblDiagGetTokenCryptoType(tokenBuf) != FBL_DIAG_TOKEN_CRYPTOTYPE)) { result = kTokenHdlrInternalFailed; } /* Check if payload size match */ if (result == kTokenHdlrOk) { if (FblDiagGetTokenCommandType(tokenBuf) == FBL_DIAG_TOKEN_CMD_PROGKEY) { if (FblDiagGetTokenPayloadSize(tokenBuf) != FBL_DIAG_TOKEN_PAYLOAD_SIZE_MODE5) { result = kTokenHdlrInternalFailed; } } else { if (FblDiagGetTokenPayloadSize(tokenBuf) != FBL_DIAG_TOKEN_PAYLOAD_SIZE_MODE0_4) { result = kTokenHdlrInternalFailed; } } } /* Check if correct key index match the token public key */ if (result == kTokenHdlrOk) { if (FblDiagGetTokenCommandType(tokenBuf) == FBL_DIAG_TOKEN_CMD_PROGKEY) { if (FblDiagGetTokenKeyIndex(tokenBuf) != FBL_DIAG_TOKEN_KEY_INDEX_0) { result = kTokenHdlrInternalFailed; } } else { if (FblDiagGetTokenKeyIndex(tokenBuf) != FBL_DIAG_TOKEN_KEY_INDEX_1) { result = kTokenHdlrInternalFailed; } } } /* Check protocol version */ if ( (result == kTokenHdlrOk) && (!FblDiagIsTokenProtocolVersionCorrect(tokenBuf))) { result = kTokenHdlrProtocolFailed; } /* Check token name length */ if ( (result == kTokenHdlrOk) && (FblDiagGetTokenTokenNameLength(tokenBuf) != FBL_DIAG_TOKEN_NAME_LENGTH) ) { result = kTokenHdlrInternalFailed; } /* Check token name */ if (result == kTokenHdlrOk) { vuint8 const tokenName[(FBL_DIAG_TOKEN_NAME_LENGTH + 1u)] = FBL_DIAG_TOKEN_NAME; for (idx = 0u; idx < FBL_DIAG_TOKEN_NAME_LENGTH; idx++) { if (FblDiagGetTokenTokenName(tokenBuf)[idx] != tokenName[idx]) { result = kTokenHdlrInternalFailed; } } } return result; } /*********************************************************************************************************************** * FblDiagCheckServerMessageId **********************************************************************************************************************/ /*! \brief Check if Server Message ID is valid * \return Possible return values: * - kFblOk: Server Message ID is valid * - kFblFailed: Server Message ID is not valid **********************************************************************************************************************/ /* PRQA S 6010, 6030 1 */ /* MD_MSR_STPTH, MD_MSR_STCYC */ static tFblResult FblDiagCheckServerMessageId( const V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * tokenBuf ) { tFblResult result = kFblOk; tFblResult srvMsgIdCompareFinished = kFblFailed; vuint8 lastServerMessageId[8] = {0}; vuint8 srvMsgIdFlag; vuintx idx; /* Check if Server Message ID was stored before */ if (ApplFblReadSrvMsgIDFlag(&srvMsgIdFlag) == kFblOk) { if (srvMsgIdFlag == (vuint8)FBL_DIAG_SRVMSGID_STORED) { /* Read last Server Message ID from NV Memory */ result = ApplFblReadLastServerMsgId(lastServerMessageId); } else { /* Initialize last Server Message ID */ result = ApplFblWriteLastServerMsgId(lastServerMessageId); if (result == kFblOk) { /* Set Server Message ID Flag so next time it will be read from NV Memory */ srvMsgIdFlag = (vuint8)FBL_DIAG_SRVMSGID_STORED; result = ApplFblWriteSrvMsgIDFlag(&srvMsgIdFlag); } } } else { result = kFblFailed; } if (result == kFblOk) { /* Read current Server Message ID from token buffer and compare with last Server Message ID */ const vuint8 *currentServerMessageId = FblDiagGetTokenServerMsgIdPtr(tokenBuf); result = kFblFailed; /* Check each byte, starting from MSB (index 0 due to network byte order) */ for (idx = 0u; idx < 8u; idx++) { if (currentServerMessageId[idx] > lastServerMessageId[idx]) { /* Received server message ID is higher than last server message ID */ result = kFblOk; srvMsgIdCompareFinished = kFblOk; } else if (currentServerMessageId[idx] < lastServerMessageId[idx]) { /* Received server message ID is lower than last server message ID. Break loop so result * cannot be ok if a byte with lower significance has a higher value in the current server * message ID */ srvMsgIdCompareFinished = kFblOk; } else { /* Values are the same, continue with check */ } if (srvMsgIdCompareFinished == kFblOk) { break; } } if (result == kFblOk) { result = ApplFblWriteLastServerMsgId(currentServerMessageId); } } return result; } /*********************************************************************************************************************** * FblDiagTokenCallout **********************************************************************************************************************/ /*! \brief Calls for each Token mode the related Callout * \param[in] cmdType The Token mode from TokenCommandType * \return Possible return values: * - tTokenHdlResult: result of the callout function **********************************************************************************************************************/ static tTokenHdlResult FblDiagTokenCallout( vuint8 cmdType, const V_MEMRAM1 vuint8 V_MEMRAM2 V_MEMRAM3 * tokenBuf, vuint16 tokenLength ) { tTokenHdlResult result; switch (cmdType) { case FBL_DIAG_TOKEN_CMD_REVERTPROD: { result = ApplFblTokenRevertKey(tokenBuf, tokenLength); break; } case FBL_DIAG_TOKEN_CMD_USEDEVPERM: { result = ApplFblTokenUseDevPermKey(tokenBuf, tokenLength); break; } case FBL_DIAG_TOKEN_CMD_USEDEVTEMP: { result = ApplFblTokenUseDevTempKey(tokenBuf, tokenLength); break; } case FBL_DIAG_TOKEN_CMD_USEDEVDATE: { result = ApplFblTokenUseDevDateKey(tokenBuf, tokenLength); break; } case FBL_DIAG_TOKEN_CMD_USEDEVIGNI: { result = ApplFblTokenUseDevIgniKey(tokenBuf, tokenLength); break; } case FBL_DIAG_TOKEN_CMD_PROGKEY: { result = ApplFblTokenProgKey(tokenBuf, tokenLength); break; } default: { result = kTokenHdlrInternalFailed; break; } } return result; } # endif /* FBL_ENABLE_TOKEN_DOWNLOAD_HANDLING */ #endif /* SEC_SECURITY_CLASS_VERIFY == SEC_CLASS_CCC */ #define FBLDIAG_STOP_SEC_CODE #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ /*********************************************************************************************************************** * MISRA DEVIATIONS **********************************************************************************************************************/ /* Justification for module-specific MISRA deviations: MD_FblDiag_0306: Reason: Address conversion between integer values and pointers is required to allow for hardware independent configuration and address range checks. Risk: The size of integer required to hold the result of a pointer cast is implementation-defined. Prevention: The size of the respective integer data type which holds the address value is adapted on a hardware specific basis. The correctness of the respective implementation is verified by runtime tests. MD_FblDiag_0313_VerifyFctOutput: Reason: Signature/checksum verification functions are stored as void pointers as actual type is not known at configuration time. Risk: Function signature not compatible with expected type. Prevention: Integrator has to take care the configured functions match with the expected signature. MD_FblDiag_0314_MemCpy: Reason: The copy function have a void pointer as a function parameter. Risk: No risk, because the underlying vuint8 pointer type is known. Prevention: No prevention necessary. MD_FblDiag_0314_KeyPtr: Reason: The verification parameter structure has a void pointer member for the key to support different key types for different use cases Risk: No risk, because the underlying key pointer type is known. Prevention: No prevention necessary. MD_FblDiag_0883: Reason: This file has to be included multiple times explicitly, due to creation of multiple structures via fbl_diag.def. Risk: No identifiable risk because defines are undefined in fbl_diag.imp Prevention: No prevention required. MD_FblDiag_1514: Reason: The variable is used by other modules and can't be declared static. Risk: Name conflicts. Prevention: Compile and link of the different variants in the component and integration test. MD_FblDiag_2214: Reason: Assertion macros have to be disabled in production code and are used only for development. Risk: Assertion code may be enabled in production code unintentionally. If a assertion condition is unexpectedly false, the code is active. A problem may occur if the Macro is additionally changed from single statement to multiple statement. Prevention: Macro is not allowed to be changed without review. Development code is automatically disabled via configuration of project state "Production". MD_FblDiag_2741: Reason: Some if conditions seems to be static only on certain compiling conditions. Risk: A condition is always false or true independently from the compiling configuration. Prevention: Code inspection and test of the different variants in the component test. MD_FblDiag_2790_kDiagStateMaskAllLong: Reason: Create a mask where all bits are set. Generic implementation shifts therefore too many bytes. Risk: No identifiable risk. Prevention: No prevention required. MD_FblDiag_2880_UnreachableCode: Reason: A code section can be executed only based on some static compile time configurations. Risk: A code section is never executed independently from the compiling configuration. Prevention: Code inspection and test of the different variants in the component test. MD_FblDiag_2889: Reason: Multiple return paths are used to reduce code complexity, increase readability and reducing nesting level. Risk: Some operations intended to conclude the function (e.g. states cleaning) can be unintentionally jumped. Prevention: Code inspection and runtime tests. MD_FblDiag_2916: Reason: Assignment to pointer is done within a function to make code more readable. Risk: No identifiable risk. Prevention: No prevention required. MD_FblDiag_2983_2985_RedundantAssignment: Reason: Assignments are redundant only on certain configurations Risk: Some code part can be really redundant in all possible configurations. Prevention: Code review. MD_FblDiag_3218: Reason: The local data of this module is kept at a central location for a better overview and maintenance. Risk: Scope is larger than required (whole file instead of one function). Some other function could access the variable. Prevention: Restrict the functionality in this module to the intended purpose. Don't add functions which shall not be able to access the local data. MD_FblDiag_3415: Reason: Side effect (conditional execution) is intended. Risk: Unintended side effects. Prevention: Code is checked for unintended side effects by code inspection. MD_FblDiag_3493: Reason: Depending on the configuration the value is not always true. Risk: No identifiable risk. Prevention: No prevention required. MD_FblDiag_3678: Reason: The buffer is actually modified and can therefore not be a const buffer. Risk: No identifiable risk. Prevention: No prevention required. MD_FblDiag_5087_DiagDef: Reason: Multiple includes of fbl_diag.def are required for building the configuration tables of the diagnostic layer. Risk: Resulting code is difficult to understand and maintain. Prevention: All changes to the affected code parts have to be reviewed by the module responsible. On a mid term view, the respective implementation will be replaced by generated code. MD_FblDiag_ConstValue: Reason: Value is constant depending on configuration aspects or platform specific implementation. This leads to constant control expressions, unreachable code or redundant operations. Risk: Wrong or missing functionality. Prevention: Code inspection and test of the different variants in the component test. */ /*********************************************************************************************************************** * END OF FILE: FBL_DIAG.C **********************************************************************************************************************/