FLEX-FORD-OBC-BM/Source/bsw/Fbl/fbl_diag.c

6493 lines
262 KiB
C

/***********************************************************************************************************************
* 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)&currentDiagnosticApp, 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
**********************************************************************************************************************/