diff --git a/matter/efr32/efr32mg24/BRD2601B/autogen/sl_ot_custom_cli.c b/matter/efr32/efr32mg24/BRD2601B/autogen/sl_ot_custom_cli.c index caef419a61..ca55d64636 100644 --- a/matter/efr32/efr32mg24/BRD2601B/autogen/sl_ot_custom_cli.c +++ b/matter/efr32/efr32mg24/BRD2601B/autogen/sl_ot_custom_cli.c @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief Custom CLI support for OpenThread ******************************************************************************* diff --git a/matter/efr32/efr32mg24/BRD2601B/autogen/sl_ot_init.h b/matter/efr32/efr32mg24/BRD2601B/autogen/sl_ot_init.h index c663079541..4afeb49d91 100644 --- a/matter/efr32/efr32mg24/BRD2601B/autogen/sl_ot_init.h +++ b/matter/efr32/efr32mg24/BRD2601B/autogen/sl_ot_init.h @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief This generated header includes declaration of all functions required * during initialization that must be defined by the OpenThread application. diff --git a/matter/efr32/efr32mg24/BRD2601B/autogen/sli_psa_config_autogen.h b/matter/efr32/efr32mg24/BRD2601B/autogen/sli_psa_config_autogen.h index c2a379f438..44af12aeaa 100644 --- a/matter/efr32/efr32mg24/BRD2601B/autogen/sli_psa_config_autogen.h +++ b/matter/efr32/efr32mg24/BRD2601B/autogen/sli_psa_config_autogen.h @@ -7,19 +7,19 @@ #define PSA_WANT_ALG_CCM 1 #define PSA_WANT_ALG_ECB_NO_PADDING 1 #define PSA_WANT_ALG_CMAC 1 +#define PSA_WANT_ALG_SHA_256 1 +#define PSA_WANT_ALG_ECDSA 1 +#define PSA_WANT_ALG_ECDH 1 #define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY 1 +#define PSA_WANT_ECC_SECP_R1_256 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE 1 -#define PSA_WANT_ECC_SECP_R1_256 1 -#define PSA_WANT_ALG_ECDH 1 -#define PSA_WANT_ALG_ECDSA 1 #define PSA_WANT_ALG_HKDF 1 #define PSA_WANT_ALG_HMAC 1 #define PSA_WANT_KEY_TYPE_HMAC 1 #define PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 1 -#define PSA_WANT_ALG_SHA_256 1 #define PSA_WANT_ALG_TLS12_PRF 1 #define PSA_WANT_ALG_TLS12_PSK_TO_MS 1 #define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG diff --git a/matter/efr32/efr32mg24/BRD2703A/autogen/sl_ot_custom_cli.c b/matter/efr32/efr32mg24/BRD2703A/autogen/sl_ot_custom_cli.c index caef419a61..ca55d64636 100644 --- a/matter/efr32/efr32mg24/BRD2703A/autogen/sl_ot_custom_cli.c +++ b/matter/efr32/efr32mg24/BRD2703A/autogen/sl_ot_custom_cli.c @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief Custom CLI support for OpenThread ******************************************************************************* diff --git a/matter/efr32/efr32mg24/BRD2703A/autogen/sl_ot_init.h b/matter/efr32/efr32mg24/BRD2703A/autogen/sl_ot_init.h index c663079541..4afeb49d91 100644 --- a/matter/efr32/efr32mg24/BRD2703A/autogen/sl_ot_init.h +++ b/matter/efr32/efr32mg24/BRD2703A/autogen/sl_ot_init.h @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief This generated header includes declaration of all functions required * during initialization that must be defined by the OpenThread application. diff --git a/matter/efr32/efr32mg24/BRD2703A/autogen/sli_psa_config_autogen.h b/matter/efr32/efr32mg24/BRD2703A/autogen/sli_psa_config_autogen.h index c2a379f438..44af12aeaa 100644 --- a/matter/efr32/efr32mg24/BRD2703A/autogen/sli_psa_config_autogen.h +++ b/matter/efr32/efr32mg24/BRD2703A/autogen/sli_psa_config_autogen.h @@ -7,19 +7,19 @@ #define PSA_WANT_ALG_CCM 1 #define PSA_WANT_ALG_ECB_NO_PADDING 1 #define PSA_WANT_ALG_CMAC 1 +#define PSA_WANT_ALG_SHA_256 1 +#define PSA_WANT_ALG_ECDSA 1 +#define PSA_WANT_ALG_ECDH 1 #define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY 1 +#define PSA_WANT_ECC_SECP_R1_256 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE 1 -#define PSA_WANT_ECC_SECP_R1_256 1 -#define PSA_WANT_ALG_ECDH 1 -#define PSA_WANT_ALG_ECDSA 1 #define PSA_WANT_ALG_HKDF 1 #define PSA_WANT_ALG_HMAC 1 #define PSA_WANT_KEY_TYPE_HMAC 1 #define PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 1 -#define PSA_WANT_ALG_SHA_256 1 #define PSA_WANT_ALG_TLS12_PRF 1 #define PSA_WANT_ALG_TLS12_PSK_TO_MS 1 #define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG diff --git a/matter/efr32/efr32mg24/BRD4186A/autogen/sl_ot_custom_cli.c b/matter/efr32/efr32mg24/BRD4186A/autogen/sl_ot_custom_cli.c index caef419a61..ca55d64636 100644 --- a/matter/efr32/efr32mg24/BRD4186A/autogen/sl_ot_custom_cli.c +++ b/matter/efr32/efr32mg24/BRD4186A/autogen/sl_ot_custom_cli.c @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief Custom CLI support for OpenThread ******************************************************************************* diff --git a/matter/efr32/efr32mg24/BRD4186A/autogen/sl_ot_init.h b/matter/efr32/efr32mg24/BRD4186A/autogen/sl_ot_init.h index c663079541..4afeb49d91 100644 --- a/matter/efr32/efr32mg24/BRD4186A/autogen/sl_ot_init.h +++ b/matter/efr32/efr32mg24/BRD4186A/autogen/sl_ot_init.h @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief This generated header includes declaration of all functions required * during initialization that must be defined by the OpenThread application. diff --git a/matter/efr32/efr32mg24/BRD4186A/autogen/sli_psa_config_autogen.h b/matter/efr32/efr32mg24/BRD4186A/autogen/sli_psa_config_autogen.h index c2a379f438..44af12aeaa 100644 --- a/matter/efr32/efr32mg24/BRD4186A/autogen/sli_psa_config_autogen.h +++ b/matter/efr32/efr32mg24/BRD4186A/autogen/sli_psa_config_autogen.h @@ -7,19 +7,19 @@ #define PSA_WANT_ALG_CCM 1 #define PSA_WANT_ALG_ECB_NO_PADDING 1 #define PSA_WANT_ALG_CMAC 1 +#define PSA_WANT_ALG_SHA_256 1 +#define PSA_WANT_ALG_ECDSA 1 +#define PSA_WANT_ALG_ECDH 1 #define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY 1 +#define PSA_WANT_ECC_SECP_R1_256 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE 1 -#define PSA_WANT_ECC_SECP_R1_256 1 -#define PSA_WANT_ALG_ECDH 1 -#define PSA_WANT_ALG_ECDSA 1 #define PSA_WANT_ALG_HKDF 1 #define PSA_WANT_ALG_HMAC 1 #define PSA_WANT_KEY_TYPE_HMAC 1 #define PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 1 -#define PSA_WANT_ALG_SHA_256 1 #define PSA_WANT_ALG_TLS12_PRF 1 #define PSA_WANT_ALG_TLS12_PSK_TO_MS 1 #define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG diff --git a/matter/efr32/efr32mg24/BRD4186C/autogen/sl_ot_custom_cli.c b/matter/efr32/efr32mg24/BRD4186C/autogen/sl_ot_custom_cli.c index caef419a61..ca55d64636 100644 --- a/matter/efr32/efr32mg24/BRD4186C/autogen/sl_ot_custom_cli.c +++ b/matter/efr32/efr32mg24/BRD4186C/autogen/sl_ot_custom_cli.c @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief Custom CLI support for OpenThread ******************************************************************************* diff --git a/matter/efr32/efr32mg24/BRD4186C/autogen/sl_ot_init.h b/matter/efr32/efr32mg24/BRD4186C/autogen/sl_ot_init.h index c663079541..4afeb49d91 100644 --- a/matter/efr32/efr32mg24/BRD4186C/autogen/sl_ot_init.h +++ b/matter/efr32/efr32mg24/BRD4186C/autogen/sl_ot_init.h @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief This generated header includes declaration of all functions required * during initialization that must be defined by the OpenThread application. diff --git a/matter/efr32/efr32mg24/BRD4186C/autogen/sli_psa_config_autogen.h b/matter/efr32/efr32mg24/BRD4186C/autogen/sli_psa_config_autogen.h index c2a379f438..44af12aeaa 100644 --- a/matter/efr32/efr32mg24/BRD4186C/autogen/sli_psa_config_autogen.h +++ b/matter/efr32/efr32mg24/BRD4186C/autogen/sli_psa_config_autogen.h @@ -7,19 +7,19 @@ #define PSA_WANT_ALG_CCM 1 #define PSA_WANT_ALG_ECB_NO_PADDING 1 #define PSA_WANT_ALG_CMAC 1 +#define PSA_WANT_ALG_SHA_256 1 +#define PSA_WANT_ALG_ECDSA 1 +#define PSA_WANT_ALG_ECDH 1 #define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY 1 +#define PSA_WANT_ECC_SECP_R1_256 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE 1 -#define PSA_WANT_ECC_SECP_R1_256 1 -#define PSA_WANT_ALG_ECDH 1 -#define PSA_WANT_ALG_ECDSA 1 #define PSA_WANT_ALG_HKDF 1 #define PSA_WANT_ALG_HMAC 1 #define PSA_WANT_KEY_TYPE_HMAC 1 #define PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 1 -#define PSA_WANT_ALG_SHA_256 1 #define PSA_WANT_ALG_TLS12_PRF 1 #define PSA_WANT_ALG_TLS12_PSK_TO_MS 1 #define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG diff --git a/matter/efr32/efr32mg24/BRD4187A/autogen/sl_ot_custom_cli.c b/matter/efr32/efr32mg24/BRD4187A/autogen/sl_ot_custom_cli.c index caef419a61..ca55d64636 100644 --- a/matter/efr32/efr32mg24/BRD4187A/autogen/sl_ot_custom_cli.c +++ b/matter/efr32/efr32mg24/BRD4187A/autogen/sl_ot_custom_cli.c @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief Custom CLI support for OpenThread ******************************************************************************* diff --git a/matter/efr32/efr32mg24/BRD4187A/autogen/sl_ot_init.h b/matter/efr32/efr32mg24/BRD4187A/autogen/sl_ot_init.h index c663079541..4afeb49d91 100644 --- a/matter/efr32/efr32mg24/BRD4187A/autogen/sl_ot_init.h +++ b/matter/efr32/efr32mg24/BRD4187A/autogen/sl_ot_init.h @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief This generated header includes declaration of all functions required * during initialization that must be defined by the OpenThread application. diff --git a/matter/efr32/efr32mg24/BRD4187A/autogen/sli_psa_config_autogen.h b/matter/efr32/efr32mg24/BRD4187A/autogen/sli_psa_config_autogen.h index c2a379f438..44af12aeaa 100644 --- a/matter/efr32/efr32mg24/BRD4187A/autogen/sli_psa_config_autogen.h +++ b/matter/efr32/efr32mg24/BRD4187A/autogen/sli_psa_config_autogen.h @@ -7,19 +7,19 @@ #define PSA_WANT_ALG_CCM 1 #define PSA_WANT_ALG_ECB_NO_PADDING 1 #define PSA_WANT_ALG_CMAC 1 +#define PSA_WANT_ALG_SHA_256 1 +#define PSA_WANT_ALG_ECDSA 1 +#define PSA_WANT_ALG_ECDH 1 #define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY 1 +#define PSA_WANT_ECC_SECP_R1_256 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE 1 -#define PSA_WANT_ECC_SECP_R1_256 1 -#define PSA_WANT_ALG_ECDH 1 -#define PSA_WANT_ALG_ECDSA 1 #define PSA_WANT_ALG_HKDF 1 #define PSA_WANT_ALG_HMAC 1 #define PSA_WANT_KEY_TYPE_HMAC 1 #define PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 1 -#define PSA_WANT_ALG_SHA_256 1 #define PSA_WANT_ALG_TLS12_PRF 1 #define PSA_WANT_ALG_TLS12_PSK_TO_MS 1 #define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG diff --git a/matter/efr32/efr32mg24/BRD4187C/autogen/sl_ot_custom_cli.c b/matter/efr32/efr32mg24/BRD4187C/autogen/sl_ot_custom_cli.c index caef419a61..ca55d64636 100644 --- a/matter/efr32/efr32mg24/BRD4187C/autogen/sl_ot_custom_cli.c +++ b/matter/efr32/efr32mg24/BRD4187C/autogen/sl_ot_custom_cli.c @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief Custom CLI support for OpenThread ******************************************************************************* diff --git a/matter/efr32/efr32mg24/BRD4187C/autogen/sl_ot_init.h b/matter/efr32/efr32mg24/BRD4187C/autogen/sl_ot_init.h index c663079541..4afeb49d91 100644 --- a/matter/efr32/efr32mg24/BRD4187C/autogen/sl_ot_init.h +++ b/matter/efr32/efr32mg24/BRD4187C/autogen/sl_ot_init.h @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief This generated header includes declaration of all functions required * during initialization that must be defined by the OpenThread application. diff --git a/matter/efr32/efr32mg24/BRD4187C/autogen/sli_psa_config_autogen.h b/matter/efr32/efr32mg24/BRD4187C/autogen/sli_psa_config_autogen.h index c2a379f438..44af12aeaa 100644 --- a/matter/efr32/efr32mg24/BRD4187C/autogen/sli_psa_config_autogen.h +++ b/matter/efr32/efr32mg24/BRD4187C/autogen/sli_psa_config_autogen.h @@ -7,19 +7,19 @@ #define PSA_WANT_ALG_CCM 1 #define PSA_WANT_ALG_ECB_NO_PADDING 1 #define PSA_WANT_ALG_CMAC 1 +#define PSA_WANT_ALG_SHA_256 1 +#define PSA_WANT_ALG_ECDSA 1 +#define PSA_WANT_ALG_ECDH 1 #define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY 1 +#define PSA_WANT_ECC_SECP_R1_256 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE 1 -#define PSA_WANT_ECC_SECP_R1_256 1 -#define PSA_WANT_ALG_ECDH 1 -#define PSA_WANT_ALG_ECDSA 1 #define PSA_WANT_ALG_HKDF 1 #define PSA_WANT_ALG_HMAC 1 #define PSA_WANT_KEY_TYPE_HMAC 1 #define PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 1 -#define PSA_WANT_ALG_SHA_256 1 #define PSA_WANT_ALG_TLS12_PRF 1 #define PSA_WANT_ALG_TLS12_PSK_TO_MS 1 #define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG diff --git a/matter/efr32/efr32mg26/BRD2608A/autogen/sl_ot_custom_cli.c b/matter/efr32/efr32mg26/BRD2608A/autogen/sl_ot_custom_cli.c index caef419a61..ca55d64636 100644 --- a/matter/efr32/efr32mg26/BRD2608A/autogen/sl_ot_custom_cli.c +++ b/matter/efr32/efr32mg26/BRD2608A/autogen/sl_ot_custom_cli.c @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief Custom CLI support for OpenThread ******************************************************************************* diff --git a/matter/efr32/efr32mg26/BRD2608A/autogen/sl_ot_init.h b/matter/efr32/efr32mg26/BRD2608A/autogen/sl_ot_init.h index c663079541..4afeb49d91 100644 --- a/matter/efr32/efr32mg26/BRD2608A/autogen/sl_ot_init.h +++ b/matter/efr32/efr32mg26/BRD2608A/autogen/sl_ot_init.h @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief This generated header includes declaration of all functions required * during initialization that must be defined by the OpenThread application. diff --git a/matter/efr32/efr32mg26/BRD2608A/autogen/sli_psa_config_autogen.h b/matter/efr32/efr32mg26/BRD2608A/autogen/sli_psa_config_autogen.h index c2a379f438..44af12aeaa 100644 --- a/matter/efr32/efr32mg26/BRD2608A/autogen/sli_psa_config_autogen.h +++ b/matter/efr32/efr32mg26/BRD2608A/autogen/sli_psa_config_autogen.h @@ -7,19 +7,19 @@ #define PSA_WANT_ALG_CCM 1 #define PSA_WANT_ALG_ECB_NO_PADDING 1 #define PSA_WANT_ALG_CMAC 1 +#define PSA_WANT_ALG_SHA_256 1 +#define PSA_WANT_ALG_ECDSA 1 +#define PSA_WANT_ALG_ECDH 1 #define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY 1 +#define PSA_WANT_ECC_SECP_R1_256 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE 1 -#define PSA_WANT_ECC_SECP_R1_256 1 -#define PSA_WANT_ALG_ECDH 1 -#define PSA_WANT_ALG_ECDSA 1 #define PSA_WANT_ALG_HKDF 1 #define PSA_WANT_ALG_HMAC 1 #define PSA_WANT_KEY_TYPE_HMAC 1 #define PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 1 -#define PSA_WANT_ALG_SHA_256 1 #define PSA_WANT_ALG_TLS12_PRF 1 #define PSA_WANT_ALG_TLS12_PSK_TO_MS 1 #define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG diff --git a/matter/efr32/efr32mg26/BRD4116A/autogen/sl_ot_custom_cli.c b/matter/efr32/efr32mg26/BRD4116A/autogen/sl_ot_custom_cli.c index caef419a61..ca55d64636 100644 --- a/matter/efr32/efr32mg26/BRD4116A/autogen/sl_ot_custom_cli.c +++ b/matter/efr32/efr32mg26/BRD4116A/autogen/sl_ot_custom_cli.c @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief Custom CLI support for OpenThread ******************************************************************************* diff --git a/matter/efr32/efr32mg26/BRD4116A/autogen/sl_ot_init.h b/matter/efr32/efr32mg26/BRD4116A/autogen/sl_ot_init.h index c663079541..4afeb49d91 100644 --- a/matter/efr32/efr32mg26/BRD4116A/autogen/sl_ot_init.h +++ b/matter/efr32/efr32mg26/BRD4116A/autogen/sl_ot_init.h @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief This generated header includes declaration of all functions required * during initialization that must be defined by the OpenThread application. diff --git a/matter/efr32/efr32mg26/BRD4116A/autogen/sli_psa_config_autogen.h b/matter/efr32/efr32mg26/BRD4116A/autogen/sli_psa_config_autogen.h index c2a379f438..44af12aeaa 100644 --- a/matter/efr32/efr32mg26/BRD4116A/autogen/sli_psa_config_autogen.h +++ b/matter/efr32/efr32mg26/BRD4116A/autogen/sli_psa_config_autogen.h @@ -7,19 +7,19 @@ #define PSA_WANT_ALG_CCM 1 #define PSA_WANT_ALG_ECB_NO_PADDING 1 #define PSA_WANT_ALG_CMAC 1 +#define PSA_WANT_ALG_SHA_256 1 +#define PSA_WANT_ALG_ECDSA 1 +#define PSA_WANT_ALG_ECDH 1 #define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY 1 +#define PSA_WANT_ECC_SECP_R1_256 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE 1 -#define PSA_WANT_ECC_SECP_R1_256 1 -#define PSA_WANT_ALG_ECDH 1 -#define PSA_WANT_ALG_ECDSA 1 #define PSA_WANT_ALG_HKDF 1 #define PSA_WANT_ALG_HMAC 1 #define PSA_WANT_KEY_TYPE_HMAC 1 #define PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 1 -#define PSA_WANT_ALG_SHA_256 1 #define PSA_WANT_ALG_TLS12_PRF 1 #define PSA_WANT_ALG_TLS12_PSK_TO_MS 1 #define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG diff --git a/matter/efr32/efr32mg26/BRD4117A/autogen/sl_ot_custom_cli.c b/matter/efr32/efr32mg26/BRD4117A/autogen/sl_ot_custom_cli.c index caef419a61..ca55d64636 100644 --- a/matter/efr32/efr32mg26/BRD4117A/autogen/sl_ot_custom_cli.c +++ b/matter/efr32/efr32mg26/BRD4117A/autogen/sl_ot_custom_cli.c @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief Custom CLI support for OpenThread ******************************************************************************* diff --git a/matter/efr32/efr32mg26/BRD4117A/autogen/sl_ot_init.h b/matter/efr32/efr32mg26/BRD4117A/autogen/sl_ot_init.h index c663079541..4afeb49d91 100644 --- a/matter/efr32/efr32mg26/BRD4117A/autogen/sl_ot_init.h +++ b/matter/efr32/efr32mg26/BRD4117A/autogen/sl_ot_init.h @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief This generated header includes declaration of all functions required * during initialization that must be defined by the OpenThread application. diff --git a/matter/efr32/efr32mg26/BRD4117A/autogen/sli_psa_config_autogen.h b/matter/efr32/efr32mg26/BRD4117A/autogen/sli_psa_config_autogen.h index c2a379f438..44af12aeaa 100644 --- a/matter/efr32/efr32mg26/BRD4117A/autogen/sli_psa_config_autogen.h +++ b/matter/efr32/efr32mg26/BRD4117A/autogen/sli_psa_config_autogen.h @@ -7,19 +7,19 @@ #define PSA_WANT_ALG_CCM 1 #define PSA_WANT_ALG_ECB_NO_PADDING 1 #define PSA_WANT_ALG_CMAC 1 +#define PSA_WANT_ALG_SHA_256 1 +#define PSA_WANT_ALG_ECDSA 1 +#define PSA_WANT_ALG_ECDH 1 #define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY 1 +#define PSA_WANT_ECC_SECP_R1_256 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE 1 -#define PSA_WANT_ECC_SECP_R1_256 1 -#define PSA_WANT_ALG_ECDH 1 -#define PSA_WANT_ALG_ECDSA 1 #define PSA_WANT_ALG_HKDF 1 #define PSA_WANT_ALG_HMAC 1 #define PSA_WANT_KEY_TYPE_HMAC 1 #define PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 1 -#define PSA_WANT_ALG_SHA_256 1 #define PSA_WANT_ALG_TLS12_PRF 1 #define PSA_WANT_ALG_TLS12_PSK_TO_MS 1 #define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG diff --git a/matter/efr32/efr32mg26/BRD4118A/autogen/sl_ot_custom_cli.c b/matter/efr32/efr32mg26/BRD4118A/autogen/sl_ot_custom_cli.c index caef419a61..ca55d64636 100644 --- a/matter/efr32/efr32mg26/BRD4118A/autogen/sl_ot_custom_cli.c +++ b/matter/efr32/efr32mg26/BRD4118A/autogen/sl_ot_custom_cli.c @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief Custom CLI support for OpenThread ******************************************************************************* diff --git a/matter/efr32/efr32mg26/BRD4118A/autogen/sl_ot_init.h b/matter/efr32/efr32mg26/BRD4118A/autogen/sl_ot_init.h index c663079541..4afeb49d91 100644 --- a/matter/efr32/efr32mg26/BRD4118A/autogen/sl_ot_init.h +++ b/matter/efr32/efr32mg26/BRD4118A/autogen/sl_ot_init.h @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief This generated header includes declaration of all functions required * during initialization that must be defined by the OpenThread application. diff --git a/matter/efr32/efr32mg26/BRD4118A/autogen/sli_psa_config_autogen.h b/matter/efr32/efr32mg26/BRD4118A/autogen/sli_psa_config_autogen.h index c2a379f438..44af12aeaa 100644 --- a/matter/efr32/efr32mg26/BRD4118A/autogen/sli_psa_config_autogen.h +++ b/matter/efr32/efr32mg26/BRD4118A/autogen/sli_psa_config_autogen.h @@ -7,19 +7,19 @@ #define PSA_WANT_ALG_CCM 1 #define PSA_WANT_ALG_ECB_NO_PADDING 1 #define PSA_WANT_ALG_CMAC 1 +#define PSA_WANT_ALG_SHA_256 1 +#define PSA_WANT_ALG_ECDSA 1 +#define PSA_WANT_ALG_ECDH 1 #define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY 1 +#define PSA_WANT_ECC_SECP_R1_256 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE 1 -#define PSA_WANT_ECC_SECP_R1_256 1 -#define PSA_WANT_ALG_ECDH 1 -#define PSA_WANT_ALG_ECDSA 1 #define PSA_WANT_ALG_HKDF 1 #define PSA_WANT_ALG_HMAC 1 #define PSA_WANT_KEY_TYPE_HMAC 1 #define PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 1 -#define PSA_WANT_ALG_SHA_256 1 #define PSA_WANT_ALG_TLS12_PRF 1 #define PSA_WANT_ALG_TLS12_PSK_TO_MS 1 #define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG diff --git a/matter/efr32/mgm24/BRD2704A/autogen/sl_ot_custom_cli.c b/matter/efr32/mgm24/BRD2704A/autogen/sl_ot_custom_cli.c index caef419a61..ca55d64636 100644 --- a/matter/efr32/mgm24/BRD2704A/autogen/sl_ot_custom_cli.c +++ b/matter/efr32/mgm24/BRD2704A/autogen/sl_ot_custom_cli.c @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief Custom CLI support for OpenThread ******************************************************************************* diff --git a/matter/efr32/mgm24/BRD2704A/autogen/sl_ot_init.h b/matter/efr32/mgm24/BRD2704A/autogen/sl_ot_init.h index c663079541..4afeb49d91 100644 --- a/matter/efr32/mgm24/BRD2704A/autogen/sl_ot_init.h +++ b/matter/efr32/mgm24/BRD2704A/autogen/sl_ot_init.h @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief This generated header includes declaration of all functions required * during initialization that must be defined by the OpenThread application. diff --git a/matter/efr32/mgm24/BRD2704A/autogen/sli_psa_config_autogen.h b/matter/efr32/mgm24/BRD2704A/autogen/sli_psa_config_autogen.h index c2a379f438..44af12aeaa 100644 --- a/matter/efr32/mgm24/BRD2704A/autogen/sli_psa_config_autogen.h +++ b/matter/efr32/mgm24/BRD2704A/autogen/sli_psa_config_autogen.h @@ -7,19 +7,19 @@ #define PSA_WANT_ALG_CCM 1 #define PSA_WANT_ALG_ECB_NO_PADDING 1 #define PSA_WANT_ALG_CMAC 1 +#define PSA_WANT_ALG_SHA_256 1 +#define PSA_WANT_ALG_ECDSA 1 +#define PSA_WANT_ALG_ECDH 1 #define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY 1 +#define PSA_WANT_ECC_SECP_R1_256 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE 1 -#define PSA_WANT_ECC_SECP_R1_256 1 -#define PSA_WANT_ALG_ECDH 1 -#define PSA_WANT_ALG_ECDSA 1 #define PSA_WANT_ALG_HKDF 1 #define PSA_WANT_ALG_HMAC 1 #define PSA_WANT_KEY_TYPE_HMAC 1 #define PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 1 -#define PSA_WANT_ALG_SHA_256 1 #define PSA_WANT_ALG_TLS12_PRF 1 #define PSA_WANT_ALG_TLS12_PSK_TO_MS 1 #define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG diff --git a/matter/efr32/mgm24/BRD4316A/autogen/sl_ot_custom_cli.c b/matter/efr32/mgm24/BRD4316A/autogen/sl_ot_custom_cli.c index caef419a61..ca55d64636 100644 --- a/matter/efr32/mgm24/BRD4316A/autogen/sl_ot_custom_cli.c +++ b/matter/efr32/mgm24/BRD4316A/autogen/sl_ot_custom_cli.c @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief Custom CLI support for OpenThread ******************************************************************************* diff --git a/matter/efr32/mgm24/BRD4316A/autogen/sl_ot_init.h b/matter/efr32/mgm24/BRD4316A/autogen/sl_ot_init.h index c663079541..4afeb49d91 100644 --- a/matter/efr32/mgm24/BRD4316A/autogen/sl_ot_init.h +++ b/matter/efr32/mgm24/BRD4316A/autogen/sl_ot_init.h @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief This generated header includes declaration of all functions required * during initialization that must be defined by the OpenThread application. diff --git a/matter/efr32/mgm24/BRD4316A/autogen/sli_psa_config_autogen.h b/matter/efr32/mgm24/BRD4316A/autogen/sli_psa_config_autogen.h index c2a379f438..44af12aeaa 100644 --- a/matter/efr32/mgm24/BRD4316A/autogen/sli_psa_config_autogen.h +++ b/matter/efr32/mgm24/BRD4316A/autogen/sli_psa_config_autogen.h @@ -7,19 +7,19 @@ #define PSA_WANT_ALG_CCM 1 #define PSA_WANT_ALG_ECB_NO_PADDING 1 #define PSA_WANT_ALG_CMAC 1 +#define PSA_WANT_ALG_SHA_256 1 +#define PSA_WANT_ALG_ECDSA 1 +#define PSA_WANT_ALG_ECDH 1 #define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY 1 +#define PSA_WANT_ECC_SECP_R1_256 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE 1 -#define PSA_WANT_ECC_SECP_R1_256 1 -#define PSA_WANT_ALG_ECDH 1 -#define PSA_WANT_ALG_ECDSA 1 #define PSA_WANT_ALG_HKDF 1 #define PSA_WANT_ALG_HMAC 1 #define PSA_WANT_KEY_TYPE_HMAC 1 #define PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 1 -#define PSA_WANT_ALG_SHA_256 1 #define PSA_WANT_ALG_TLS12_PRF 1 #define PSA_WANT_ALG_TLS12_PSK_TO_MS 1 #define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG diff --git a/matter/efr32/mgm24/BRD4317A/autogen/sl_ot_custom_cli.c b/matter/efr32/mgm24/BRD4317A/autogen/sl_ot_custom_cli.c index caef419a61..ca55d64636 100644 --- a/matter/efr32/mgm24/BRD4317A/autogen/sl_ot_custom_cli.c +++ b/matter/efr32/mgm24/BRD4317A/autogen/sl_ot_custom_cli.c @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief Custom CLI support for OpenThread ******************************************************************************* diff --git a/matter/efr32/mgm24/BRD4317A/autogen/sl_ot_init.h b/matter/efr32/mgm24/BRD4317A/autogen/sl_ot_init.h index c663079541..4afeb49d91 100644 --- a/matter/efr32/mgm24/BRD4317A/autogen/sl_ot_init.h +++ b/matter/efr32/mgm24/BRD4317A/autogen/sl_ot_init.h @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief This generated header includes declaration of all functions required * during initialization that must be defined by the OpenThread application. diff --git a/matter/efr32/mgm24/BRD4317A/autogen/sli_psa_config_autogen.h b/matter/efr32/mgm24/BRD4317A/autogen/sli_psa_config_autogen.h index c2a379f438..44af12aeaa 100644 --- a/matter/efr32/mgm24/BRD4317A/autogen/sli_psa_config_autogen.h +++ b/matter/efr32/mgm24/BRD4317A/autogen/sli_psa_config_autogen.h @@ -7,19 +7,19 @@ #define PSA_WANT_ALG_CCM 1 #define PSA_WANT_ALG_ECB_NO_PADDING 1 #define PSA_WANT_ALG_CMAC 1 +#define PSA_WANT_ALG_SHA_256 1 +#define PSA_WANT_ALG_ECDSA 1 +#define PSA_WANT_ALG_ECDH 1 #define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY 1 +#define PSA_WANT_ECC_SECP_R1_256 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE 1 -#define PSA_WANT_ECC_SECP_R1_256 1 -#define PSA_WANT_ALG_ECDH 1 -#define PSA_WANT_ALG_ECDSA 1 #define PSA_WANT_ALG_HKDF 1 #define PSA_WANT_ALG_HMAC 1 #define PSA_WANT_KEY_TYPE_HMAC 1 #define PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 1 -#define PSA_WANT_ALG_SHA_256 1 #define PSA_WANT_ALG_TLS12_PRF 1 #define PSA_WANT_ALG_TLS12_PSK_TO_MS 1 #define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG diff --git a/matter/efr32/mgm24/BRD4318A/autogen/sl_ot_custom_cli.c b/matter/efr32/mgm24/BRD4318A/autogen/sl_ot_custom_cli.c index caef419a61..ca55d64636 100644 --- a/matter/efr32/mgm24/BRD4318A/autogen/sl_ot_custom_cli.c +++ b/matter/efr32/mgm24/BRD4318A/autogen/sl_ot_custom_cli.c @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief Custom CLI support for OpenThread ******************************************************************************* diff --git a/matter/efr32/mgm24/BRD4318A/autogen/sl_ot_init.h b/matter/efr32/mgm24/BRD4318A/autogen/sl_ot_init.h index c663079541..4afeb49d91 100644 --- a/matter/efr32/mgm24/BRD4318A/autogen/sl_ot_init.h +++ b/matter/efr32/mgm24/BRD4318A/autogen/sl_ot_init.h @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief This generated header includes declaration of all functions required * during initialization that must be defined by the OpenThread application. diff --git a/matter/efr32/mgm24/BRD4318A/autogen/sli_psa_config_autogen.h b/matter/efr32/mgm24/BRD4318A/autogen/sli_psa_config_autogen.h index c2a379f438..44af12aeaa 100644 --- a/matter/efr32/mgm24/BRD4318A/autogen/sli_psa_config_autogen.h +++ b/matter/efr32/mgm24/BRD4318A/autogen/sli_psa_config_autogen.h @@ -7,19 +7,19 @@ #define PSA_WANT_ALG_CCM 1 #define PSA_WANT_ALG_ECB_NO_PADDING 1 #define PSA_WANT_ALG_CMAC 1 +#define PSA_WANT_ALG_SHA_256 1 +#define PSA_WANT_ALG_ECDSA 1 +#define PSA_WANT_ALG_ECDH 1 #define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY 1 +#define PSA_WANT_ECC_SECP_R1_256 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE 1 -#define PSA_WANT_ECC_SECP_R1_256 1 -#define PSA_WANT_ALG_ECDH 1 -#define PSA_WANT_ALG_ECDSA 1 #define PSA_WANT_ALG_HKDF 1 #define PSA_WANT_ALG_HMAC 1 #define PSA_WANT_KEY_TYPE_HMAC 1 #define PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 1 -#define PSA_WANT_ALG_SHA_256 1 #define PSA_WANT_ALG_TLS12_PRF 1 #define PSA_WANT_ALG_TLS12_PSK_TO_MS 1 #define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG diff --git a/matter/efr32/mgm24/BRD4319A/autogen/sl_ot_custom_cli.c b/matter/efr32/mgm24/BRD4319A/autogen/sl_ot_custom_cli.c index caef419a61..ca55d64636 100644 --- a/matter/efr32/mgm24/BRD4319A/autogen/sl_ot_custom_cli.c +++ b/matter/efr32/mgm24/BRD4319A/autogen/sl_ot_custom_cli.c @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief Custom CLI support for OpenThread ******************************************************************************* diff --git a/matter/efr32/mgm24/BRD4319A/autogen/sl_ot_init.h b/matter/efr32/mgm24/BRD4319A/autogen/sl_ot_init.h index c663079541..4afeb49d91 100644 --- a/matter/efr32/mgm24/BRD4319A/autogen/sl_ot_init.h +++ b/matter/efr32/mgm24/BRD4319A/autogen/sl_ot_init.h @@ -1,4 +1,4 @@ -/***************************************************************************//** +/******************************************************************************* * @file * @brief This generated header includes declaration of all functions required * during initialization that must be defined by the OpenThread application. diff --git a/matter/efr32/mgm24/BRD4319A/autogen/sli_psa_config_autogen.h b/matter/efr32/mgm24/BRD4319A/autogen/sli_psa_config_autogen.h index c2a379f438..44af12aeaa 100644 --- a/matter/efr32/mgm24/BRD4319A/autogen/sli_psa_config_autogen.h +++ b/matter/efr32/mgm24/BRD4319A/autogen/sli_psa_config_autogen.h @@ -7,19 +7,19 @@ #define PSA_WANT_ALG_CCM 1 #define PSA_WANT_ALG_ECB_NO_PADDING 1 #define PSA_WANT_ALG_CMAC 1 +#define PSA_WANT_ALG_SHA_256 1 +#define PSA_WANT_ALG_ECDSA 1 +#define PSA_WANT_ALG_ECDH 1 #define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY 1 +#define PSA_WANT_ECC_SECP_R1_256 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT 1 #define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE 1 -#define PSA_WANT_ECC_SECP_R1_256 1 -#define PSA_WANT_ALG_ECDH 1 -#define PSA_WANT_ALG_ECDSA 1 #define PSA_WANT_ALG_HKDF 1 #define PSA_WANT_ALG_HMAC 1 #define PSA_WANT_KEY_TYPE_HMAC 1 #define PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 1 -#define PSA_WANT_ALG_SHA_256 1 #define PSA_WANT_ALG_TLS12_PRF 1 #define PSA_WANT_ALG_TLS12_PSK_TO_MS 1 #define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG diff --git a/platform/emdrv/nvm3/lib/libnvm3_CM33_gcc.a b/platform/emdrv/nvm3/lib/libnvm3_CM33_gcc.a index fbe9a9aeb2..5bf07dd108 100644 Binary files a/platform/emdrv/nvm3/lib/libnvm3_CM33_gcc.a and b/platform/emdrv/nvm3/lib/libnvm3_CM33_gcc.a differ diff --git a/platform/emdrv/nvm3/lib/libnvm3_CM33_iar.a b/platform/emdrv/nvm3/lib/libnvm3_CM33_iar.a index 5eb81c66f0..4809334e8b 100644 Binary files a/platform/emdrv/nvm3/lib/libnvm3_CM33_iar.a and b/platform/emdrv/nvm3/lib/libnvm3_CM33_iar.a differ diff --git a/platform/emdrv/nvm3/lib/libnvm3_CM4_gcc.a b/platform/emdrv/nvm3/lib/libnvm3_CM4_gcc.a index 99ef50056a..16cde25023 100644 Binary files a/platform/emdrv/nvm3/lib/libnvm3_CM4_gcc.a and b/platform/emdrv/nvm3/lib/libnvm3_CM4_gcc.a differ diff --git a/platform/emdrv/nvm3/lib/libnvm3_CM4_iar.a b/platform/emdrv/nvm3/lib/libnvm3_CM4_iar.a index 595c94f3d6..6ae7977318 100644 Binary files a/platform/emdrv/nvm3/lib/libnvm3_CM4_iar.a and b/platform/emdrv/nvm3/lib/libnvm3_CM4_iar.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240l022rnf_iar.a b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240l022rnf_iar.a index 2438082da1..8f78796d8b 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240l022rnf_iar.a and b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240l022rnf_iar.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240l022vif_iar.a b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240l022vif_iar.a index e8d169098f..4ab5395ba4 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240l022vif_iar.a and b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240l022vif_iar.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240l022vnf_iar.a b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240l022vnf_iar.a index 28d6517f09..0df59af134 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240l022vnf_iar.a and b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240l022vnf_iar.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240la22uif_iar.a b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240la22uif_iar.a index 9415f2bfab..dff8529167 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240la22uif_iar.a and b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240la22uif_iar.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240la22vif_iar.a b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240la22vif_iar.a index 584564bfc0..03b52bff3a 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240la22vif_iar.a and b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240la22vif_iar.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240ld22vif_iar.a b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240ld22vif_iar.a index 47afdf4e3d..65ef957755 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240ld22vif_iar.a and b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240ld22vif_iar.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pa22vna_iar.a b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pa22vna_iar.a index 1652542719..a235de4b20 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pa22vna_iar.a and b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pa22vna_iar.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pa32vna_iar.a b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pa32vna_iar.a index f088552aec..51b3130970 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pa32vna_iar.a and b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pa32vna_iar.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pa32vnn_iar.a b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pa32vnn_iar.a index 1cafa98a59..ad3b33a21f 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pa32vnn_iar.a and b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pa32vnn_iar.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pb22vna_iar.a b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pb22vna_iar.a index b9737e6094..3e5ca8ac23 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pb22vna_iar.a and b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pb22vna_iar.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pb32vna_iar.a b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pb32vna_iar.a index 42564aeecf..abb4657882 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pb32vna_iar.a and b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pb32vna_iar.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pb32vnn_iar.a b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pb32vnn_iar.a index f45d0f4d3c..3c267f03a8 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pb32vnn_iar.a and b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240pb32vnn_iar.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240sa22vna_iar.a b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240sa22vna_iar.a index f1d1fb7dce..73ab480c8c 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240sa22vna_iar.a and b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240sa22vna_iar.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240sb22vna_iar.a b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240sb22vna_iar.a index 33a4532f97..7d112ae1a8 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240sb22vna_iar.a and b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240sb22vna_iar.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240sd22vna_iar.a b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240sd22vna_iar.a index 6bf2ffe45b..8a82333465 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240sd22vna_iar.a and b/platform/radio/rail_lib/autogen/librail_release/librail_config_mgm240sd22vna_iar.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_efr32xg24_gcc_release.a b/platform/radio/rail_lib/autogen/librail_release/librail_efr32xg24_gcc_release.a index 7df1f212a1..e26e1ae1e7 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_efr32xg24_gcc_release.a and b/platform/radio/rail_lib/autogen/librail_release/librail_efr32xg24_gcc_release.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_efr32xg24_iar_release.a b/platform/radio/rail_lib/autogen/librail_release/librail_efr32xg24_iar_release.a index a0ccdf2751..2a4a5a6427 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_efr32xg24_iar_release.a and b/platform/radio/rail_lib/autogen/librail_release/librail_efr32xg24_iar_release.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_efr32xg26_gcc_release.a b/platform/radio/rail_lib/autogen/librail_release/librail_efr32xg26_gcc_release.a index 90630e79b8..50f6a6ca9b 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_efr32xg26_gcc_release.a and b/platform/radio/rail_lib/autogen/librail_release/librail_efr32xg26_gcc_release.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_efr32xg26_iar_release.a b/platform/radio/rail_lib/autogen/librail_release/librail_efr32xg26_iar_release.a index 5211a812c5..44ff550cd0 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_efr32xg26_iar_release.a and b/platform/radio/rail_lib/autogen/librail_release/librail_efr32xg26_iar_release.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_module_efr32xg24_gcc_release.a b/platform/radio/rail_lib/autogen/librail_release/librail_module_efr32xg24_gcc_release.a index 9d59815fb0..3f9a85e602 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_module_efr32xg24_gcc_release.a and b/platform/radio/rail_lib/autogen/librail_release/librail_module_efr32xg24_gcc_release.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_module_efr32xg24_iar_release.a b/platform/radio/rail_lib/autogen/librail_release/librail_module_efr32xg24_iar_release.a index c161c64e65..88a54c1e86 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_module_efr32xg24_iar_release.a and b/platform/radio/rail_lib/autogen/librail_release/librail_module_efr32xg24_iar_release.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_module_efr32xg26_gcc_release.a b/platform/radio/rail_lib/autogen/librail_release/librail_module_efr32xg26_gcc_release.a index 62e3e660f2..370b96f9a2 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_module_efr32xg26_gcc_release.a and b/platform/radio/rail_lib/autogen/librail_release/librail_module_efr32xg26_gcc_release.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_module_efr32xg26_iar_release.a b/platform/radio/rail_lib/autogen/librail_release/librail_module_efr32xg26_iar_release.a index 2b81e643dc..d4e693d0c4 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_module_efr32xg26_iar_release.a and b/platform/radio/rail_lib/autogen/librail_release/librail_module_efr32xg26_iar_release.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_efr32xg24_gcc_release.a b/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_efr32xg24_gcc_release.a index 71df82c431..03269a8604 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_efr32xg24_gcc_release.a and b/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_efr32xg24_gcc_release.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_efr32xg24_iar_release.a b/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_efr32xg24_iar_release.a index 3952558fa7..e42165aae2 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_efr32xg24_iar_release.a and b/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_efr32xg24_iar_release.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_efr32xg26_gcc_release.a b/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_efr32xg26_gcc_release.a index 6e6babf190..aa8a934955 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_efr32xg26_gcc_release.a and b/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_efr32xg26_gcc_release.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_efr32xg26_iar_release.a b/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_efr32xg26_iar_release.a index 5f1d3b7309..2a81a41bc2 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_efr32xg26_iar_release.a and b/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_efr32xg26_iar_release.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_module_efr32xg24_gcc_release.a b/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_module_efr32xg24_gcc_release.a index e64b3fe9c9..a73d88d649 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_module_efr32xg24_gcc_release.a and b/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_module_efr32xg24_gcc_release.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_module_efr32xg24_iar_release.a b/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_module_efr32xg24_iar_release.a index 0bceac7caf..36deb2f48f 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_module_efr32xg24_iar_release.a and b/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_module_efr32xg24_iar_release.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_module_efr32xg26_gcc_release.a b/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_module_efr32xg26_gcc_release.a index e47468ff34..1fc743f1b7 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_module_efr32xg26_gcc_release.a and b/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_module_efr32xg26_gcc_release.a differ diff --git a/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_module_efr32xg26_iar_release.a b/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_module_efr32xg26_iar_release.a index b361f8d740..dfe11984e0 100644 Binary files a/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_module_efr32xg26_iar_release.a and b/platform/radio/rail_lib/autogen/librail_release/librail_multiprotocol_module_efr32xg26_iar_release.a differ diff --git a/platform/security/sl_component/sl_psa_driver/src/sl_psa_its_nvm3.c b/platform/security/sl_component/sl_psa_driver/src/sl_psa_its_nvm3.c deleted file mode 100644 index 22c97fee22..0000000000 --- a/platform/security/sl_component/sl_psa_driver/src/sl_psa_its_nvm3.c +++ /dev/null @@ -1,3265 +0,0 @@ -/******************************************************************************* - * @file - * @brief PSA ITS implementation based on Silicon Labs NVM3 - ******************************************************************************* - * # License - * Copyright 2020 Silicon Laboratories Inc. www.silabs.com - ******************************************************************************* - * - * SPDX-License-Identifier: Zlib - * - * The licensor of this software is Silicon Laboratories Inc. - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - * - ******************************************************************************/ - -// The psa_driver_wrappers.h file that we're including here assumes that it has -// access to private struct members. Define this here in order to avoid -// compilation errors. -#define MBEDTLS_ALLOW_PRIVATE_ACCESS - -// ------------------------------------- -// Includes - -#include - -#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) && !defined(MBEDTLS_PSA_ITS_FILE_C) - -#include "mbedtls/platform.h" -#include "nvm3_default.h" -#include "psa/internal_trusted_storage.h" -#include "psa/sli_internal_trusted_storage.h" -#include -#include - -#if defined(TFM_CONFIG_SL_SECURE_LIBRARY) -#include "psa/storage_common.h" -#include -#endif // TFM_CONFIG_SL_SECURE_LIBRARY - -#if defined(SLI_PSA_ITS_ENCRYPTED) -#include "psa_crypto_core.h" -#include "psa_crypto_driver_wrappers.h" -#if defined(SEMAILBOX_PRESENT) -#include "psa/crypto_extra.h" -#include "sl_psa_values.h" -#include "sli_se_opaque_functions.h" -#endif // defined(SEMAILBOX_PRESENT) -#endif // defined(SLI_PSA_ITS_ENCRYPTED) - -// SLI_STATIC_TESTABLE is used to expose otherwise-static variables during -// internal testing. -#if defined(SLI_STATIC_TESTABLE) -#define SLI_STATIC -#else -#define SLI_STATIC static -#endif - -// ------------------------------------- -// Threading support - -#if defined(MBEDTLS_THREADING_C) -#include "cmsis_os2.h" -#include "mbedtls/threading.h" - -// Mutex for protecting access to the ITS instance -SLI_STATIC mbedtls_threading_mutex_t its_mutex MUTEX_INIT; -static volatile bool its_mutex_inited = false; - -/** - * \brief Lock all task switches - * - * \return Previous lock state - * - */ -static inline int32_t lock_task_switches(void) { - int32_t kernel_lock_state = 0; - osKernelState_t kernel_state = osKernelGetState(); - if (kernel_state != osKernelInactive && kernel_state != osKernelReady) { - kernel_lock_state = osKernelLock(); - } - return kernel_lock_state; -} - -/** - * \brief Restores the previous lock state - */ -static inline void restore_lock_state(int32_t kernel_lock_state) { - osKernelState_t kernel_state = osKernelGetState(); - if (kernel_state != osKernelInactive && kernel_state != osKernelReady) { - if (osKernelRestoreLock(kernel_lock_state) < 0) { - EFM_ASSERT(false); - } - } -} - -#endif // defined(MBEDTLS_THREADING_C) - -/** - * \brief Pend on the ITS mutex - */ -void sli_its_acquire_mutex(void) { -#if defined(MBEDTLS_THREADING_C) - if (!its_mutex_inited) { - int32_t kernel_lock_state = lock_task_switches(); - if (!its_mutex_inited) { - // The ITS mutex needs to be recursive since the same thread may need - // to acquire it more than one time. - its_mutex.mutex_attr.attr_bits |= osMutexRecursive; - mbedtls_mutex_init(&its_mutex); - its_mutex_inited = true; - } - restore_lock_state(kernel_lock_state); - } - if (mbedtls_mutex_lock(&its_mutex) != 0) { - EFM_ASSERT(false); - } -#endif -} - -/** - * \brief Free the ITS mutex. - */ -void sli_its_release_mutex(void) { -#if defined(MBEDTLS_THREADING_C) - if (its_mutex_inited) { - mbedtls_mutex_unlock(&its_mutex); - } -#endif -} - -// ------------------------------------- -// Defines - -#if (!SL_PSA_ITS_SUPPORT_V3_DRIVER) -#define SLI_PSA_ITS_NVM3_RANGE_START SLI_PSA_ITS_NVM3_RANGE_BASE -#define SLI_PSA_ITS_NVM3_RANGE_END \ - SLI_PSA_ITS_NVM3_RANGE_START + SL_PSA_ITS_MAX_FILES - -#define SLI_PSA_ITS_NVM3_INVALID_KEY (0) -#define SLI_PSA_ITS_NVM3_UNKNOWN_KEY (1) - -#if SL_PSA_ITS_MAX_FILES > SLI_PSA_ITS_NVM3_RANGE_SIZE -#error "Trying to store more ITS files then our NVM3 range allows for" -#endif - -#define SLI_PSA_ITS_CACHE_INIT_CHUNK_SIZE 16 - -// Enable backwards-compatibility with keys stored with a v1 header unless -// disabled. -#if !defined(SL_PSA_ITS_REMOVE_V1_HEADER_SUPPORT) -#define SLI_PSA_ITS_SUPPORT_V1_FORMAT -#endif - -// Internal error codes local to this compile unit -#define SLI_PSA_ITS_ECODE_NO_VALID_HEADER (ECODE_EMDRV_NVM3_BASE - 1) -#define SLI_PSA_ITS_ECODE_NEEDS_UPGRADE (ECODE_EMDRV_NVM3_BASE - 2) - -#if defined(SLI_PSA_ITS_ENCRYPTED) -// Define some cryptographic constants if not already set. This depends on the -// underlying crypto accelerator in use (CRYPTOACC has these defines, but not -// SEMAILBOX). -#if !defined(AES_MAC_SIZE) -#define AES_MAC_SIZE 16 -#endif - -#if !defined(AES_IV_GCM_SIZE) -#define AES_IV_GCM_SIZE 12 -#endif - -#define SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD (AES_IV_GCM_SIZE + AES_MAC_SIZE) -#endif // defined(SLI_PSA_ITS_ENCRYPTED) - -// ------------------------------------- -// Local global static variables - -SLI_STATIC bool nvm3_uid_set_cache_initialized = false; -SLI_STATIC uint32_t nvm3_uid_set_cache[(SL_PSA_ITS_MAX_FILES + 31) / 32] = {0}; - -typedef struct { - psa_storage_uid_t uid; - nvm3_ObjectKey_t object_id; - bool set; -} previous_lookup_t; - -static previous_lookup_t previous_lookup = {0, 0, false}; - -#if defined(SLI_PSA_ITS_ENCRYPTED) -// The root key is an AES-256 key, and is therefore 32 bytes. -#define ROOT_KEY_SIZE (32) -// The session key is derived from CMAC, which means it is equal to the AES -// block size, i.e. 16 bytes -#define SESSION_KEY_SIZE (16) - -#if !defined(SEMAILBOX_PRESENT) -typedef struct { - bool initialized; - uint8_t data[ROOT_KEY_SIZE]; -} root_key_t; - -static root_key_t g_root_key = { - .initialized = false, - .data = {0}, -}; -#endif // !defined(SEMAILBOX_PRESENT) - -typedef struct { - bool active; - psa_storage_uid_t uid; - uint8_t data[SESSION_KEY_SIZE]; -} session_key_t; - -static session_key_t g_cached_session_key = { - .active = false, - .uid = 0, - .data = {0}, -}; -#endif // defined(SLI_PSA_ITS_ENCRYPTED) - -// ------------------------------------- -// Structs - -#if defined(SLI_PSA_ITS_SUPPORT_V1_FORMAT) -typedef struct { - uint32_t magic; - psa_storage_uid_t uid; - psa_storage_create_flags_t flags; -} sl_its_file_meta_v1_t; -#endif // defined(SLI_PSA_ITS_SUPPORT_V1_FORMAT) - -// Due to alignment constraints on the 64-bit UID, the v2 header struct is -// serialized to 16 bytes instead of the 24 bytes the v1 header compiles to. -typedef struct { - uint32_t magic; - psa_storage_create_flags_t flags; - psa_storage_uid_t uid; -} sli_its_file_meta_v2_t; - -#if defined(SLI_PSA_ITS_ENCRYPTED) -typedef struct { - uint8_t iv[AES_IV_GCM_SIZE]; - // When encrypted & authenticated, MAC is stored at the end of the data array - uint8_t data[]; -} sli_its_encrypted_blob_t; -#endif // defined(SLI_PSA_ITS_ENCRYPTED) - -// ------------------------------------- -// Local function prototypes - -static nvm3_ObjectKey_t get_nvm3_id(psa_storage_uid_t uid, - bool find_empty_slot); -static nvm3_ObjectKey_t prepare_its_get_nvm3_id(psa_storage_uid_t uid); - -#if defined(TFM_CONFIG_SL_SECURE_LIBRARY) -static inline bool object_lives_in_s(const void *object, size_t object_size); -#endif // defined(TFM_CONFIG_SL_SECURE_LIBRARY) - -#if defined(SLI_PSA_ITS_ENCRYPTED) -static psa_status_t derive_session_key(uint8_t *iv, size_t iv_size, - uint8_t *session_key, - size_t session_key_size); - -static psa_status_t encrypt_its_file(sli_its_file_meta_v2_t *metadata, - uint8_t *plaintext, size_t plaintext_size, - sli_its_encrypted_blob_t *blob, - size_t blob_size, size_t *blob_length); - -static psa_status_t decrypt_its_file(sli_its_file_meta_v2_t *metadata, - sli_its_encrypted_blob_t *blob, - size_t blob_size, uint8_t *plaintext, - size_t plaintext_size, - size_t *plaintext_length); - -static psa_status_t authenticate_its_file(nvm3_ObjectKey_t nvm3_object_id, - psa_storage_uid_t *authenticated_uid); -#endif // defined(SLI_PSA_ITS_ENCRYPTED) - -// ------------------------------------- -// Local function definitions - -#if defined(TFM_CONFIG_SL_SECURE_LIBRARY) -// If an object of given size is fully encapsulated in a region of -// secure domain the function returns true. -static inline bool object_lives_in_s(const void *object, size_t object_size) { - cmse_address_info_t cmse_flags; - - for (size_t i = 0u; i < object_size; i++) { - cmse_flags = cmse_TTA((uint32_t *)object + i); - if (!cmse_flags.flags.secure) { - return false; - } - } - - return true; -} -#endif // defined(TFM_CONFIG_SL_SECURE_LIBRARY) - -static inline void cache_set(nvm3_ObjectKey_t key) { - uint32_t i = key - SLI_PSA_ITS_NVM3_RANGE_START; - uint32_t bin = i / 32; - uint32_t offset = i - 32 * bin; - nvm3_uid_set_cache[bin] |= (1 << offset); -} - -static inline void cache_clear(nvm3_ObjectKey_t key) { - uint32_t i = key - SLI_PSA_ITS_NVM3_RANGE_START; - uint32_t bin = i / 32; - uint32_t offset = i - 32 * bin; - nvm3_uid_set_cache[bin] ^= (1 << offset); -} - -static inline bool cache_lookup(nvm3_ObjectKey_t key) { - uint32_t i = key - SLI_PSA_ITS_NVM3_RANGE_START; - uint32_t bin = i / 32; - uint32_t offset = i - 32 * bin; - return (bool)((nvm3_uid_set_cache[bin] >> offset) & 0x1); -} - -static void init_cache(void) { - size_t num_keys_referenced_by_nvm3; - nvm3_ObjectKey_t keys_referenced_by_nvm3[SLI_PSA_ITS_CACHE_INIT_CHUNK_SIZE] = - {0}; - - for (nvm3_ObjectKey_t range_start = SLI_PSA_ITS_NVM3_RANGE_START; - range_start < SLI_PSA_ITS_NVM3_RANGE_END; - range_start += SLI_PSA_ITS_CACHE_INIT_CHUNK_SIZE) { - nvm3_ObjectKey_t range_end = - range_start + SLI_PSA_ITS_CACHE_INIT_CHUNK_SIZE; - if (range_end > SLI_PSA_ITS_NVM3_RANGE_END) { - range_end = SLI_PSA_ITS_NVM3_RANGE_END; - } - - num_keys_referenced_by_nvm3 = nvm3_enumObjects( - nvm3_defaultHandle, keys_referenced_by_nvm3, - sizeof(keys_referenced_by_nvm3) / sizeof(nvm3_ObjectKey_t), range_start, - range_end - 1); - - for (size_t i = 0; i < num_keys_referenced_by_nvm3; i++) { - cache_set(keys_referenced_by_nvm3[i]); - } - } - - nvm3_uid_set_cache_initialized = true; -} - -// Read the file metadata for a specific NVM3 ID -static Ecode_t get_file_metadata(nvm3_ObjectKey_t key, - sli_its_file_meta_v2_t *metadata, - size_t *its_file_offset, - size_t *its_file_size) { - // Initialize output variables to safe default - if (its_file_offset != NULL) { - *its_file_offset = 0; - } - if (its_file_size != NULL) { - *its_file_size = 0; - } - - Ecode_t status = nvm3_readPartialData(nvm3_defaultHandle, key, metadata, 0, - sizeof(sli_its_file_meta_v2_t)); - if (status != ECODE_NVM3_OK) { - return status; - } - -#if defined(SLI_PSA_ITS_SUPPORT_V1_FORMAT) - // Re-read in v1 header format and translate to the latest structure version - if (metadata->magic == SLI_PSA_ITS_META_MAGIC_V1) { - sl_its_file_meta_v1_t key_meta_v1 = {0}; - status = nvm3_readPartialData(nvm3_defaultHandle, key, &key_meta_v1, 0, - sizeof(sl_its_file_meta_v1_t)); - - if (status != ECODE_NVM3_OK) { - return status; - } - - metadata->flags = key_meta_v1.flags; - metadata->uid = key_meta_v1.uid; - metadata->magic = SLI_PSA_ITS_META_MAGIC_V2; - - if (its_file_offset != NULL) { - *its_file_offset = sizeof(sl_its_file_meta_v1_t); - } - - status = SLI_PSA_ITS_ECODE_NEEDS_UPGRADE; - } else -#endif - { - if (its_file_offset != NULL) { - *its_file_offset = sizeof(sli_its_file_meta_v2_t); - } - } - - if (metadata->magic != SLI_PSA_ITS_META_MAGIC_V2) { - // No valid header found in this object - return SLI_PSA_ITS_ECODE_NO_VALID_HEADER; - } - - if (its_file_offset != NULL && its_file_size != NULL) { - // Calculate the ITS file size if requested - uint32_t obj_type; - Ecode_t info_status = - nvm3_getObjectInfo(nvm3_defaultHandle, key, &obj_type, its_file_size); - if (info_status != ECODE_NVM3_OK) { - return info_status; - } - - *its_file_size = *its_file_size - *its_file_offset; - } - - return status; -} - -// Search through NVM3 for uid -static nvm3_ObjectKey_t get_nvm3_id(psa_storage_uid_t uid, - bool find_empty_slot) { - Ecode_t status; - sli_its_file_meta_v2_t key_meta; - - if (find_empty_slot) { - for (size_t i = 0; i < SL_PSA_ITS_MAX_FILES; i++) { - if (!cache_lookup(i + SLI_PSA_ITS_NVM3_RANGE_START)) { - return i + SLI_PSA_ITS_NVM3_RANGE_START; - } - } - } else { - if (previous_lookup.set) { - if (previous_lookup.uid == uid) { - return previous_lookup.object_id; - } - } - - for (size_t i = 0; i < SL_PSA_ITS_MAX_FILES; i++) { - if (!cache_lookup(i + SLI_PSA_ITS_NVM3_RANGE_START)) { - continue; - } - nvm3_ObjectKey_t object_id = i + SLI_PSA_ITS_NVM3_RANGE_START; - - status = get_file_metadata(object_id, &key_meta, NULL, NULL); - - if (status == ECODE_NVM3_OK || - status == SLI_PSA_ITS_ECODE_NEEDS_UPGRADE) { - if (key_meta.uid == uid) { - previous_lookup.set = true; - previous_lookup.object_id = object_id; - previous_lookup.uid = uid; - - return object_id; - } else { - continue; - } - } - - if (status == SLI_PSA_ITS_ECODE_NO_VALID_HEADER || - status == ECODE_NVM3_ERR_READ_DATA_SIZE) { - // we don't expect any other data in our range then PSA ITS files. - // delete the file if the magic doesn't match or the object on disk - // is too small to even have full metadata. - status = nvm3_deleteObject(nvm3_defaultHandle, object_id); - if (status != ECODE_NVM3_OK) { - return SLI_PSA_ITS_NVM3_RANGE_END + 1U; - } - } - } - } - - return SLI_PSA_ITS_NVM3_RANGE_END + 1U; -} - -// Perform NVM3 open and fill the look-up table. -// Try to find the mapping NVM3 object ID with PSA ITS UID. -static nvm3_ObjectKey_t prepare_its_get_nvm3_id(psa_storage_uid_t uid) { -#if defined(TFM_CONFIG_SL_SECURE_LIBRARY) - // With SKL the NVM3 instance must be initialized by the NS app. We therefore - // check that it has been opened (which is done on init) rather than actually - // doing the init. - if (!nvm3_defaultHandle->hasBeenOpened) { -#else - if (nvm3_initDefault() != ECODE_NVM3_OK) { -#endif - return SLI_PSA_ITS_NVM3_RANGE_END + 1U; - } - - if (nvm3_uid_set_cache_initialized == false) { - init_cache(); - } - - return get_nvm3_id(uid, false); -} - -#if defined(SLI_PSA_ITS_ENCRYPTED) -static inline void cache_session_key(uint8_t *session_key, - psa_storage_uid_t uid) { - // Cache the session key - memcpy(g_cached_session_key.data, session_key, - sizeof(g_cached_session_key.data)); - g_cached_session_key.uid = uid; - g_cached_session_key.active = true; -} - -/** - * \brief Derive a session key for ITS file encryption from the initialized root - * key and provided IV. - * - * \param[in] iv Pointer to array containing the initialization - * vector to be used in the key derivation. \param[in] iv_size Size of - * the IV buffer in bytes. Must be 12 bytes (AES-GCM IV size). \param[out] - * session_key Pointer to array where derived session key shall be stored. - * \param[out] session_key_size Size of the derived session key output array. - * Must be at least 32 bytes (AES-256 key size). - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed - * successfully \retval PSA_ERROR_BAD_STATE The root key has - * not been initialized. \retval PSA_ERROR_INVALID_ARGUMENT The - * operation failed because iv or session_key is NULL, or their sizes are - * incorrect. \retval PSA_ERROR_HARDWARE_FAILURE The operation failed - * because an internal cryptographic operation failed. - */ -static psa_status_t derive_session_key(uint8_t *iv, size_t iv_size, - uint8_t *session_key, - size_t session_key_size) { - if (iv == NULL || iv_size != AES_IV_GCM_SIZE || session_key == NULL || - session_key_size < SESSION_KEY_SIZE) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; - -#if defined(SEMAILBOX_PRESENT) - // For HSE devices, use the builtin TrustZone Root Key - psa_set_key_id(&attributes, SL_SE_BUILTIN_KEY_TRUSTZONE_ID); - - psa_key_lifetime_t reported_lifetime; - psa_drv_slot_number_t reported_slot; - status = mbedtls_psa_platform_get_builtin_key( - psa_get_key_id(&attributes), &reported_lifetime, &reported_slot); - - if (status != PSA_SUCCESS) { - return status; - } - - psa_set_key_lifetime(&attributes, reported_lifetime); - - uint8_t key_buffer[sizeof(sli_se_opaque_key_context_header_t)]; - size_t key_buffer_size; - status = sli_se_opaque_get_builtin_key(reported_slot, &attributes, key_buffer, - sizeof(key_buffer), &key_buffer_size); - if (status != PSA_SUCCESS) { - return status; - } -#else // defined(SEMAILBOX_PRESENT) - // For VSE devices, use the previously initialized root key - if (!g_root_key.initialized) { - return PSA_ERROR_BAD_STATE; - } - - // Prepare root key attributes - psa_set_key_algorithm(&attributes, PSA_ALG_CMAC); - psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); - psa_set_key_bits(&attributes, ROOT_KEY_SIZE * 8); - - // Point the key buffer to the global root key - uint8_t *key_buffer = (uint8_t *)g_root_key.data; - size_t key_buffer_size = sizeof(g_root_key.data); -#endif // defined(SEMAILBOX_PRESENT) - - // Use CMAC as a key derivation function - size_t session_key_length; - status = psa_driver_wrapper_mac_compute( - &attributes, key_buffer, key_buffer_size, PSA_ALG_CMAC, iv, iv_size, - session_key, session_key_size, &session_key_length); - - // Verify that the key derivation was successful before transferring the key - // to the caller - if (status != PSA_SUCCESS || session_key_length != SESSION_KEY_SIZE) { - memset(session_key, 0, session_key_size); - return PSA_ERROR_HARDWARE_FAILURE; - } - - return status; -} - -/** - * \brief Encrypt and authenticate ITS data with AES-128-GCM, storing the result - * in an encrypted blob. - * - * \param[in] metadata ITS metadata to be used as authenticated - * additional data. \param[in] plaintext Pointer to array containing data - * to be encrypted. \param[in] plaintext_size Size of provided plaintext data - * array. \param[out] blob Pointer to array where the resulting - * encrypted blob shall be placed. \param[in] blob_size Size of the output - * array. Must be at least as big as plaintext_size + - * SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD \param[out] blob_length Resulting - * size of the output blob. - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed - * successfully \retval PSA_ERROR_BAD_STATE The root key has - * not been initialized. \retval PSA_ERROR_INVALID_ARGUMENT The - * operation failed because one or more arguments are NULL or of invalid size. - * \retval PSA_ERROR_HARDWARE_FAILURE The operation failed because an - * internal cryptographic operation failed. - */ -static psa_status_t encrypt_its_file(sli_its_file_meta_v2_t *metadata, - uint8_t *plaintext, size_t plaintext_size, - sli_its_encrypted_blob_t *blob, - size_t blob_size, size_t *blob_length) { - if (metadata == NULL || (plaintext == NULL && plaintext_size > 0) || - blob == NULL || - blob_size < plaintext_size + SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD || - blob_length == NULL) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - // Generate IV - size_t iv_length = 0; - psa_status_t psa_status = mbedtls_psa_external_get_random( - NULL, blob->iv, AES_IV_GCM_SIZE, &iv_length); - - if (psa_status != PSA_SUCCESS || iv_length != AES_IV_GCM_SIZE) { - return PSA_ERROR_HARDWARE_FAILURE; - } - - // Prepare encryption key - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT); - psa_set_key_algorithm(&attributes, PSA_ALG_GCM); - psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); - psa_set_key_bits(&attributes, SESSION_KEY_SIZE * 8); - - uint8_t session_key[SESSION_KEY_SIZE]; - psa_status = derive_session_key(blob->iv, AES_IV_GCM_SIZE, session_key, - sizeof(session_key)); - if (psa_status != PSA_SUCCESS) { - return psa_status; - } - - cache_session_key(session_key, metadata->uid); - - // Retrieve data to be encrypted - if (plaintext_size != 0U) { - memcpy(blob->data, ((uint8_t *)plaintext), plaintext_size); - } - - // Encrypt and authenticate blob - size_t output_length = 0; - psa_status = psa_driver_wrapper_aead_encrypt( - &attributes, session_key, sizeof(session_key), PSA_ALG_GCM, blob->iv, - sizeof(blob->iv), (uint8_t *)metadata, - sizeof(sli_its_file_meta_v2_t), // metadata is AAD - blob->data, plaintext_size, blob->data, - plaintext_size + AES_MAC_SIZE, // output == input for in-place encryption - &output_length); - - // Clear the local session key immediately after we're done using it - memset(session_key, 0, sizeof(session_key)); - - if (psa_status != PSA_SUCCESS) { - return PSA_ERROR_HARDWARE_FAILURE; - } - - if (output_length != plaintext_size + AES_MAC_SIZE) { - return PSA_ERROR_HARDWARE_FAILURE; - } - - *blob_length = output_length + AES_IV_GCM_SIZE; - - return PSA_SUCCESS; -} - -/** - * \brief Decrypt and authenticate encrypted ITS data. - * - * \param[in] metadata ITS metadata to be used as authenticated - * additional data. Must be identical to the metadata used during encryption. - * \param[in] blob Encrypted blob containing data to be decrypted. - * \param[in] blob_size Size of the encrypted blob in bytes. - * \param[out] plaintext Pointer to array where the decrypted plaintext - * shall be placed. \param[in] plaintext_size Size of the plaintext array. - * Must be equal to sizeof(blob->data) - AES_MAC_SIZE. \param[out] - * plaintext_length Resulting length of the decrypted plaintext. - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed - * successfully \retval PSA_ERROR_INVALID_SIGANTURE The operation - * failed because authentication of the decrypted data failed. \retval - * PSA_ERROR_BAD_STATE The root key has not been initialized. - * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because - * one or more arguments are NULL or of invalid size. \retval - * PSA_ERROR_HARDWARE_FAILURE The operation failed because an internal - * cryptographic operation failed. - */ -static psa_status_t decrypt_its_file(sli_its_file_meta_v2_t *metadata, - sli_its_encrypted_blob_t *blob, - size_t blob_size, uint8_t *plaintext, - size_t plaintext_size, - size_t *plaintext_length) { - if (metadata == NULL || blob == NULL || - blob_size < plaintext_size + SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD || - (plaintext == NULL && plaintext_size > 0) || plaintext_length == NULL) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - // Prepare decryption key - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT); - psa_set_key_algorithm(&attributes, PSA_ALG_GCM); - psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); - psa_set_key_bits(&attributes, SESSION_KEY_SIZE * 8); - - psa_status_t psa_status = PSA_ERROR_CORRUPTION_DETECTED; - uint8_t session_key[SESSION_KEY_SIZE]; - - if (g_cached_session_key.active && - g_cached_session_key.uid == metadata->uid) { - // Use cached session key if it's already set and UID matches - memcpy(session_key, g_cached_session_key.data, sizeof(session_key)); - } else { - psa_status = derive_session_key(blob->iv, AES_IV_GCM_SIZE, session_key, - sizeof(session_key)); - if (psa_status != PSA_SUCCESS) { - return psa_status; - } - cache_session_key(session_key, metadata->uid); - } - - // Decrypt and authenticate blob - size_t output_length = 0; - psa_status = psa_driver_wrapper_aead_decrypt( - &attributes, session_key, sizeof(session_key), PSA_ALG_GCM, blob->iv, - sizeof(blob->iv), (uint8_t *)metadata, - sizeof(sli_its_file_meta_v2_t), // metadata is AAD - blob->data, plaintext_size + AES_MAC_SIZE, plaintext, plaintext_size, - &output_length); - - // Clear the session key immediately after we're done using it - memset(session_key, 0, sizeof(session_key)); - - // Invalid signature likely means that NVM data was tampered with - if (psa_status == PSA_ERROR_INVALID_SIGNATURE) { - return PSA_ERROR_INVALID_SIGNATURE; - } - - if (psa_status != PSA_SUCCESS || output_length != plaintext_size) { - return PSA_ERROR_HARDWARE_FAILURE; - } - - *plaintext_length = output_length; - - return PSA_SUCCESS; -} - -/** - * \brief Authenticate encrypted ITS data and return the UID of the ITS file - * that was authenticated. - * - * \details NOTE: This function will run decrypt_its_file() internally. The - * difference from the decrypt_its_file() function is that - * authenticate_its_file() reads the NVM3 data, decrypts it in order to - * authenticate the stored data, and then discards the plaintext. This is needed - * since PSA Crypto doesn't support the GMAC primitive directly, which means we - * have to run a full GCM decrypt for authentication. - * - * \param[in] nvm3_object_id The NVM3 id corresponding to the stored ITS - * file. \param[out] authenticated_uid UID for the authenticated ITS file. - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed - * successfully \retval PSA_ERROR_INVALID_SIGANTURE The operation - * failed because authentication of the decrypted data failed. \retval - * PSA_ERROR_BAD_STATE The root key has not been initialized. - * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because - * one or more arguments are NULL or of invalid size. \retval - * PSA_ERROR_HARDWARE_FAILURE The operation failed because an internal - * cryptographic operation failed. - */ -static psa_status_t -authenticate_its_file(nvm3_ObjectKey_t nvm3_object_id, - psa_storage_uid_t *authenticated_uid) { - psa_status_t ret = PSA_ERROR_CORRUPTION_DETECTED; - sli_its_file_meta_v2_t *its_file_meta = NULL; - sli_its_encrypted_blob_t *blob = NULL; - - uint32_t obj_type; - size_t its_file_size = 0; - Ecode_t status = nvm3_getObjectInfo(nvm3_defaultHandle, nvm3_object_id, - &obj_type, &its_file_size); - if (status != ECODE_NVM3_OK) { - return PSA_ERROR_STORAGE_FAILURE; - } - - uint8_t *its_file_buffer = mbedtls_calloc(1, its_file_size); - if (its_file_buffer == NULL) { - return PSA_ERROR_INSUFFICIENT_MEMORY; - } - memset(its_file_buffer, 0, its_file_size); - - status = nvm3_readData(nvm3_defaultHandle, nvm3_object_id, its_file_buffer, - its_file_size); - if (status != ECODE_NVM3_OK) { - ret = PSA_ERROR_STORAGE_FAILURE; - goto cleanup; - } - - its_file_meta = (sli_its_file_meta_v2_t *)its_file_buffer; - blob = (sli_its_encrypted_blob_t *)(its_file_buffer + - sizeof(sli_its_file_meta_v2_t)); - - // Decrypt and authenticate blob - size_t plaintext_length; - ret = decrypt_its_file(its_file_meta, blob, - its_file_size - sizeof(sli_its_file_meta_v2_t), - blob->data, - its_file_size - sizeof(sli_its_file_meta_v2_t) - - SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD, - &plaintext_length); - - if (ret != PSA_SUCCESS) { - goto cleanup; - } - - if (plaintext_length != (its_file_size - sizeof(sli_its_file_meta_v2_t) - - SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD)) { - ret = PSA_ERROR_INVALID_SIGNATURE; - goto cleanup; - } - - if (authenticated_uid != NULL) { - *authenticated_uid = its_file_meta->uid; - } - - ret = PSA_SUCCESS; - -cleanup: - - // Discard output, as we're only interested in whether the authentication - // check passed or not. - memset(its_file_buffer, 0, its_file_size); - mbedtls_free(its_file_buffer); - - return ret; -} -#endif // defined(SLI_PSA_ITS_ENCRYPTED) - -// ------------------------------------- -// Global function definitions - -/** - * \brief create a new or modify an existing uid/value pair - * - * \param[in] uid the identifier for the data - * \param[in] data_length The size in bytes of the data in `p_data` - * \param[in] p_data A buffer containing the data - * \param[in] create_flags The flags that the data will be stored with - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed - * successfully \retval PSA_ERROR_NOT_PERMITTED The operation - * failed because the provided `uid` value was already created with - * PSA_STORAGE_FLAG_WRITE_ONCE \retval PSA_ERROR_NOT_SUPPORTED The - * operation failed because one or more of the flags provided in `create_flags` - * is not supported or is not valid \retval PSA_ERROR_INSUFFICIENT_STORAGE - * The operation failed because there was insufficient space on the storage - * medium \retval PSA_ERROR_STORAGE_FAILURE The operation failed - * because the physical storage has failed (Fatal error) \retval - * PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the - * provided pointers(`p_data`) is invalid, for example is `NULL` or references - * memory the caller cannot access \retval PSA_ERROR_HARDWARE_FAILURE The - * operation failed because an internal cryptographic operation failed. - */ -psa_status_t psa_its_set(psa_storage_uid_t uid, uint32_t data_length, - const void *p_data, - psa_storage_create_flags_t create_flags) { - if (data_length > NVM3_MAX_OBJECT_SIZE) { - return PSA_ERROR_STORAGE_FAILURE; - } - if ((data_length != 0U) && (p_data == NULL)) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - if (create_flags != PSA_STORAGE_FLAG_WRITE_ONCE && - create_flags != PSA_STORAGE_FLAG_NONE -#if defined(TFM_CONFIG_SL_SECURE_LIBRARY) - && create_flags != PSA_STORAGE_FLAG_WRITE_ONCE_SECURE_ACCESSIBLE -#endif - ) { - return PSA_ERROR_NOT_SUPPORTED; - } - -#if defined(TFM_CONFIG_SL_SECURE_LIBRARY) - if ((create_flags == PSA_STORAGE_FLAG_WRITE_ONCE_SECURE_ACCESSIBLE) && - (!object_lives_in_s(p_data, data_length))) { - // The flag indicates that this data should not be set by the non-secure - // domain - return PSA_ERROR_INVALID_ARGUMENT; - } -#endif - sli_its_acquire_mutex(); - nvm3_ObjectKey_t nvm3_object_id = prepare_its_get_nvm3_id(uid); - Ecode_t status; - psa_status_t ret = PSA_SUCCESS; - sli_its_file_meta_v2_t *its_file_meta; - -#if defined(SLI_PSA_ITS_ENCRYPTED) - psa_storage_uid_t authenticated_uid; - sli_its_encrypted_blob_t *blob = NULL; - size_t blob_length = 0u; - psa_status_t psa_status; - - size_t its_file_size = data_length + SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD; -#else - size_t its_file_size = data_length; -#endif - - uint8_t *its_file_buffer = - mbedtls_calloc(1, its_file_size + sizeof(sli_its_file_meta_v2_t)); - if (its_file_buffer == NULL) { - ret = PSA_ERROR_INSUFFICIENT_MEMORY; - goto exit; - } - memset(its_file_buffer, 0, its_file_size + sizeof(sli_its_file_meta_v2_t)); - - its_file_meta = (sli_its_file_meta_v2_t *)its_file_buffer; - if (nvm3_object_id > SLI_PSA_ITS_NVM3_RANGE_END) { - // ITS UID was not found. Request a new. - nvm3_object_id = get_nvm3_id(0ULL, true); - if (nvm3_object_id > SLI_PSA_ITS_NVM3_RANGE_END) { - // The storage is full, or an error was returned during cleanup. - ret = PSA_ERROR_INSUFFICIENT_STORAGE; - } else { - its_file_meta->uid = uid; - its_file_meta->magic = SLI_PSA_ITS_META_MAGIC_V2; - } - } else { - // ITS UID was found. Read ITS meta data. - status = get_file_metadata(nvm3_object_id, its_file_meta, NULL, NULL); - - if (status != ECODE_NVM3_OK && status != SLI_PSA_ITS_ECODE_NEEDS_UPGRADE) { - ret = PSA_ERROR_STORAGE_FAILURE; - goto exit; - } - - if (its_file_meta->flags == PSA_STORAGE_FLAG_WRITE_ONCE -#if defined(TFM_CONFIG_SL_SECURE_LIBRARY) - || its_file_meta->flags == PSA_STORAGE_FLAG_WRITE_ONCE_SECURE_ACCESSIBLE -#endif - ) { - ret = PSA_ERROR_NOT_PERMITTED; - goto exit; - } - -#if defined(SLI_PSA_ITS_ENCRYPTED) - // If the UID already exists, authenticate the existing value and make sure - // the stored UID is the same. - ret = authenticate_its_file(nvm3_object_id, &authenticated_uid); - if (ret != PSA_SUCCESS) { - goto exit; - } - - if (authenticated_uid != uid) { - ret = PSA_ERROR_NOT_PERMITTED; - goto exit; - } -#endif - } - - its_file_meta->flags = create_flags; - -#if defined(SLI_PSA_ITS_ENCRYPTED) - // Everything after the file metadata will make up the encrypted & - // authenticated blob - blob = (sli_its_encrypted_blob_t *)(its_file_buffer + - sizeof(sli_its_file_meta_v2_t)); - - // Encrypt and authenticate the provided data - psa_status = encrypt_its_file(its_file_meta, (uint8_t *)p_data, data_length, - blob, its_file_size, &blob_length); - - if (psa_status != PSA_SUCCESS) { - ret = psa_status; - goto exit; - } - - if (blob_length != its_file_size) { - ret = PSA_ERROR_HARDWARE_FAILURE; - goto exit; - } - -#else - if (data_length != 0U) { - memcpy(its_file_buffer + sizeof(sli_its_file_meta_v2_t), - ((uint8_t *)p_data), data_length); - } -#endif - - status = nvm3_writeData(nvm3_defaultHandle, nvm3_object_id, its_file_buffer, - its_file_size + sizeof(sli_its_file_meta_v2_t)); - - if (status == ECODE_NVM3_OK) { - // Power-loss might occur, however upon boot, the look-up table will be - // re-filled as long as the data has been successfully written to NVM3. - cache_set(nvm3_object_id); - } else { - ret = PSA_ERROR_STORAGE_FAILURE; - } - -exit: - if (its_file_buffer != NULL) { - // Clear and free key buffer before return. - memset(its_file_buffer, 0, its_file_size + sizeof(sli_its_file_meta_v2_t)); - mbedtls_free(its_file_buffer); - } - sli_its_release_mutex(); - return ret; -} - -/** - * \brief Retrieve the value associated with a provided uid - * - * \param[in] uid The uid value - * \param[in] data_offset The starting offset of the data requested - * \param[in] data_length the amount of data requested (and the minimum - * allocated size of the `p_data` buffer) \param[out] p_data The - * buffer where the data will be placed upon successful completion \param[out] - * p_data_length The amount of data returned in the p_data buffer - * - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed - * successfully \retval PSA_ERROR_DOES_NOT_EXIST The operation failed - * because the provided `uid` value was not found in the storage \retval - * PSA_ERROR_BUFFER_TOO_SMALL The operation failed because the data associated - * with provided uid is larger than `data_size` \retval - * PSA_ERROR_STORAGE_FAILURE The operation failed because the physical - * storage has failed (Fatal error) \retval PSA_ERROR_INVALID_ARGUMENT The - * operation failed because one of the provided pointers(`p_data`, - * `p_data_length`) is invalid. For example is `NULL` or references memory the - * caller cannot access. In addition, this can also happen if an invalid offset - * was provided. - */ -psa_status_t psa_its_get(psa_storage_uid_t uid, uint32_t data_offset, - uint32_t data_length, void *p_data, - size_t *p_data_length) { - psa_status_t ret = PSA_ERROR_CORRUPTION_DETECTED; - - if ((data_length != 0U) && (p_data_length == NULL)) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - if (data_length != 0U) { - // If the request amount of data is 0, allow invalid pointer of the output - // buffer. - if ((p_data == NULL) || ((uint32_t)p_data < SRAM_BASE) || - ((uint32_t)p_data > (SRAM_BASE + SRAM_SIZE - data_length))) { - return PSA_ERROR_INVALID_ARGUMENT; - } - } - -#if defined(SLI_PSA_ITS_ENCRYPTED) - sli_its_encrypted_blob_t *blob = NULL; - size_t plaintext_length; - psa_status_t psa_status; -#endif - size_t its_file_data_size = 0u; - Ecode_t status; - sli_its_file_meta_v2_t its_file_meta = {0}; - size_t its_file_size = 0; - size_t its_file_offset = 0; - - sli_its_acquire_mutex(); - nvm3_ObjectKey_t nvm3_object_id = prepare_its_get_nvm3_id(uid); - if (nvm3_object_id > SLI_PSA_ITS_NVM3_RANGE_END) { - ret = PSA_ERROR_DOES_NOT_EXIST; - goto exit; - } - - status = get_file_metadata(nvm3_object_id, &its_file_meta, &its_file_offset, - &its_file_size); - if (status == SLI_PSA_ITS_ECODE_NO_VALID_HEADER) { - ret = PSA_ERROR_DOES_NOT_EXIST; - goto exit; - } - if (status != ECODE_NVM3_OK && status != SLI_PSA_ITS_ECODE_NEEDS_UPGRADE) { - ret = PSA_ERROR_STORAGE_FAILURE; - goto exit; - } - -#if defined(TFM_CONFIG_SL_SECURE_LIBRARY) - if (its_file_meta.flags == PSA_STORAGE_FLAG_WRITE_ONCE_SECURE_ACCESSIBLE && - !object_lives_in_s(p_data, data_length)) { - // The flag indicates that this data should not be read back to the - // non-secure domain - ret = PSA_ERROR_INVALID_ARGUMENT; - goto exit; - } -#endif - -#if defined(SLI_PSA_ITS_ENCRYPTED) - // Subtract IV and MAC from ITS file as the below checks concern the actual - // data size - its_file_data_size = its_file_size - SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD; -#else - its_file_data_size = its_file_size; -#endif - - if (data_length != 0U) { - if ((data_offset >= its_file_data_size) && (its_file_data_size != 0U)) { - ret = PSA_ERROR_INVALID_ARGUMENT; - goto exit; - } - - if ((its_file_data_size == 0U) && (data_offset != 0U)) { - ret = PSA_ERROR_INVALID_ARGUMENT; - goto exit; - } - } else { - // Allow the offset at the data size boundary if the requested amount of - // data is zero. - if (data_offset > its_file_data_size) { - ret = PSA_ERROR_INVALID_ARGUMENT; - goto exit; - } - } - - if (data_length > (its_file_data_size - data_offset)) { - *p_data_length = its_file_data_size - data_offset; - } else { - *p_data_length = data_length; - } - -#if defined(SLI_PSA_ITS_ENCRYPTED) - // its_file_size includes size of sli_its_encrypted_blob_t struct - blob = (sli_its_encrypted_blob_t *)mbedtls_calloc(1, its_file_size); - if (blob == NULL) { - ret = PSA_ERROR_INSUFFICIENT_MEMORY; - goto exit; - } - memset(blob, 0, its_file_size); - - status = nvm3_readPartialData(nvm3_defaultHandle, nvm3_object_id, blob, - its_file_offset, its_file_size); - if (status != ECODE_NVM3_OK) { - ret = PSA_ERROR_STORAGE_FAILURE; - goto exit; - } - - // Decrypt and authenticate blob - psa_status = decrypt_its_file( - &its_file_meta, blob, its_file_size, blob->data, - its_file_size - SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD, &plaintext_length); - - if (psa_status != PSA_SUCCESS) { - ret = psa_status; - goto exit; - } - - if (plaintext_length != - (its_file_size - SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD)) { - ret = PSA_ERROR_INVALID_SIGNATURE; - goto exit; - } - - // Verify that the requested UID is equal to the retrieved and authenticated - // UID - if (uid != its_file_meta.uid) { - ret = PSA_ERROR_INVALID_ARGUMENT; - goto exit; - } - - if (*p_data_length > 0) { - memcpy(p_data, blob->data + data_offset, *p_data_length); - } - ret = PSA_SUCCESS; - -exit: - if (blob != NULL) { - memset(blob, 0, its_file_size); - mbedtls_free(blob); - } - sli_its_release_mutex(); -#else - // If no encryption is used, just read out the data and write it directly to - // the output buffer - status = nvm3_readPartialData(nvm3_defaultHandle, nvm3_object_id, p_data, - its_file_offset + data_offset, *p_data_length); - - if (status != ECODE_NVM3_OK) { - ret = PSA_ERROR_STORAGE_FAILURE; - } else { - ret = PSA_SUCCESS; - } - -exit: - sli_its_release_mutex(); -#endif - - return ret; -} - -/** - * \brief Retrieve the metadata about the provided uid - * - * \param[in] uid The uid value - * \param[out] p_info A pointer to the `psa_storage_info_t` struct that - * will be populated with the metadata - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed - * successfully \retval PSA_ERROR_DOES_NOT_EXIST The operation failed - * because the provided uid value was not found in the storage \retval - * PSA_ERROR_STORAGE_FAILURE The operation failed because the physical - * storage has failed (Fatal error) \retval PSA_ERROR_INVALID_ARGUMENT The - * operation failed because one of the provided pointers(`p_info`) is invalid, - * for example is `NULL` or references memory the caller cannot access \retval - * PSA_ERROR_INVALID_SIGANTURE The operation failed because authentication of - * the stored metadata failed. - */ -psa_status_t psa_its_get_info(psa_storage_uid_t uid, - struct psa_storage_info_t *p_info) { - psa_status_t psa_status = PSA_ERROR_CORRUPTION_DETECTED; - - if (p_info == NULL) { - return PSA_ERROR_INVALID_ARGUMENT; - } - Ecode_t status; - sli_its_file_meta_v2_t its_file_meta = {0}; - size_t its_file_size = 0; - size_t its_file_offset = 0; - - sli_its_acquire_mutex(); - nvm3_ObjectKey_t nvm3_object_id = prepare_its_get_nvm3_id(uid); - if (nvm3_object_id > SLI_PSA_ITS_NVM3_RANGE_END) { - psa_status = PSA_ERROR_DOES_NOT_EXIST; - goto exit; - } - - status = get_file_metadata(nvm3_object_id, &its_file_meta, &its_file_offset, - &its_file_size); - if (status == SLI_PSA_ITS_ECODE_NO_VALID_HEADER) { - psa_status = PSA_ERROR_DOES_NOT_EXIST; - goto exit; - } - if (status != ECODE_NVM3_OK && status != SLI_PSA_ITS_ECODE_NEEDS_UPGRADE) { - psa_status = PSA_ERROR_STORAGE_FAILURE; - goto exit; - } - -#if defined(SLI_PSA_ITS_ENCRYPTED) - // Authenticate the ITS file (both metadata and ciphertext) before returning - // the metadata. Note that this can potentially induce a significant - // performance hit. - psa_storage_uid_t authenticated_uid; - psa_status = authenticate_its_file(nvm3_object_id, &authenticated_uid); - if (psa_status != PSA_SUCCESS) { - goto exit; - } - - if (authenticated_uid != uid) { - psa_status = PSA_ERROR_INVALID_SIGNATURE; - goto exit; - } -#endif - - p_info->flags = its_file_meta.flags; - p_info->size = its_file_size; - - psa_status = PSA_SUCCESS; - -#if defined(SLI_PSA_ITS_ENCRYPTED) - // Remove IV and MAC size from file size - p_info->size = its_file_size - SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD; -#endif -exit: - sli_its_release_mutex(); - return psa_status; -} - -/** - * \brief Remove the provided key and its associated data from the storage - * - * \param[in] uid The uid value - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed - * successfully \retval PSA_ERROR_DOES_NOT_EXIST The operation failed - * because the provided key value was not found in the storage \retval - * PSA_ERROR_NOT_PERMITTED The operation failed because the provided key - * value was created with PSA_STORAGE_FLAG_WRITE_ONCE \retval - * PSA_ERROR_STORAGE_FAILURE The operation failed because the physical - * storage has failed (Fatal error) - */ -psa_status_t psa_its_remove(psa_storage_uid_t uid) { - psa_status_t psa_status = PSA_ERROR_CORRUPTION_DETECTED; - Ecode_t status; - sli_its_file_meta_v2_t its_file_meta = {0}; - size_t its_file_size = 0; - size_t its_file_offset = 0; - - sli_its_acquire_mutex(); - nvm3_ObjectKey_t nvm3_object_id = prepare_its_get_nvm3_id(uid); - if (nvm3_object_id > SLI_PSA_ITS_NVM3_RANGE_END) { - psa_status = PSA_ERROR_DOES_NOT_EXIST; - goto exit; - } - - status = get_file_metadata(nvm3_object_id, &its_file_meta, &its_file_offset, - &its_file_size); - if (status == SLI_PSA_ITS_ECODE_NO_VALID_HEADER) { - psa_status = PSA_ERROR_DOES_NOT_EXIST; - goto exit; - } - if (status != ECODE_NVM3_OK && status != SLI_PSA_ITS_ECODE_NEEDS_UPGRADE) { - psa_status = PSA_ERROR_STORAGE_FAILURE; - goto exit; - } - - if (its_file_meta.flags == PSA_STORAGE_FLAG_WRITE_ONCE -#if defined(TFM_CONFIG_SL_SECURE_LIBRARY) - || its_file_meta.flags == PSA_STORAGE_FLAG_WRITE_ONCE_SECURE_ACCESSIBLE -#endif - ) { - psa_status = PSA_ERROR_NOT_PERMITTED; - goto exit; - } - -#if defined(SLI_PSA_ITS_ENCRYPTED) - // If the UID already exists, authenticate the existing value and make sure - // the stored UID is the same. - psa_storage_uid_t authenticated_uid; - psa_status = authenticate_its_file(nvm3_object_id, &authenticated_uid); - if (psa_status != PSA_SUCCESS) { - goto exit; - } - - if (authenticated_uid != uid) { - psa_status = PSA_ERROR_NOT_PERMITTED; - goto exit; - } -#endif - - status = nvm3_deleteObject(nvm3_defaultHandle, nvm3_object_id); - - if (status == ECODE_NVM3_OK) { - // Power-loss might occur, however upon boot, the look-up table will be - // re-filled as long as the data has been successfully written to NVM3. - if (previous_lookup.set && previous_lookup.uid == uid) { - previous_lookup.set = false; - } - cache_clear(nvm3_object_id); - - psa_status = PSA_SUCCESS; - } else { - psa_status = PSA_ERROR_STORAGE_FAILURE; - } - -exit: - sli_its_release_mutex(); - return psa_status; -} - -// ------------------------------------- -// Silicon Labs extensions -static psa_storage_uid_t psa_its_identifier_of_slot(mbedtls_svc_key_id_t key) { -#if defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER) - // Encode the owner in the upper 32 bits. This means that if - // owner values are nonzero (as they are on a PSA platform), - // no key file will ever have a value less than 0x100000000, so - // the whole range 0..0xffffffff is available for non-key files. - uint32_t unsigned_owner_id = MBEDTLS_SVC_KEY_ID_GET_OWNER_ID(key); - return ((uint64_t)unsigned_owner_id << 32) | - MBEDTLS_SVC_KEY_ID_GET_KEY_ID(key); -#else - // Use the key id directly as a file name. - // psa_is_key_id_valid() in psa_crypto_slot_management.c - // is responsible for ensuring that key identifiers do not have a - // value that is reserved for non-key files. - return key; -#endif -} - -psa_status_t sli_psa_its_change_key_id(mbedtls_svc_key_id_t old_id, - mbedtls_svc_key_id_t new_id) { - psa_storage_uid_t old_uid = psa_its_identifier_of_slot(old_id); - psa_storage_uid_t new_uid = psa_its_identifier_of_slot(new_id); - Ecode_t status; - uint32_t obj_type; - size_t its_file_size = 0; - psa_status_t psa_status = PSA_ERROR_CORRUPTION_DETECTED; - int8_t *its_file_buffer = NULL; - sli_its_file_meta_v2_t *metadata = NULL; - -#if defined(SLI_PSA_ITS_ENCRYPTED) - sli_its_encrypted_blob_t *blob = NULL; - size_t plaintext_length; - size_t blob_length; - psa_status_t encrypt_status; - psa_status_t decrypt_status; -#endif - sli_its_acquire_mutex(); - - // Check whether the key to migrate exists on disk - nvm3_ObjectKey_t nvm3_object_id = prepare_its_get_nvm3_id(old_uid); - if (nvm3_object_id > SLI_PSA_ITS_NVM3_RANGE_END) { - psa_status = PSA_ERROR_DOES_NOT_EXIST; - goto exit; - } - - // Get total length to allocate - status = nvm3_getObjectInfo(nvm3_defaultHandle, nvm3_object_id, &obj_type, - &its_file_size); - if (status != ECODE_NVM3_OK) { - psa_status = PSA_ERROR_STORAGE_FAILURE; - goto exit; - } - - // Allocate temporary buffer and cast it to the metadata format - its_file_buffer = mbedtls_calloc(1, its_file_size); - if (its_file_buffer == NULL) { - psa_status = PSA_ERROR_INSUFFICIENT_MEMORY; - goto exit; - } - metadata = (sli_its_file_meta_v2_t *)its_file_buffer; - - // Read contents of pre-existing key into the temporary buffer - status = nvm3_readData(nvm3_defaultHandle, nvm3_object_id, its_file_buffer, - its_file_size); - if (status != ECODE_NVM3_OK) { - psa_status = PSA_ERROR_STORAGE_FAILURE; - goto exit; - } - -#if defined(SLI_PSA_ITS_ENCRYPTED) - // Decrypt and authenticate blob - blob = (sli_its_encrypted_blob_t *)(its_file_buffer + - sizeof(sli_its_file_meta_v2_t)); - decrypt_status = decrypt_its_file( - metadata, blob, its_file_size - sizeof(sli_its_file_meta_v2_t), - blob->data, - its_file_size - sizeof(sli_its_file_meta_v2_t) - - SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD, - &plaintext_length); - - if (decrypt_status != PSA_SUCCESS) { - psa_status = decrypt_status; - goto exit; - } - - if (plaintext_length != (its_file_size - sizeof(sli_its_file_meta_v2_t) - - SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD)) { - psa_status = PSA_ERROR_INVALID_SIGNATURE; - goto exit; - } -#endif - - // Swap out the old UID for the new one -#if defined(SLI_PSA_ITS_SUPPORT_V1_FORMAT) - if (metadata->magic == SLI_PSA_ITS_META_MAGIC_V1) { - // Recast as v1 metadata - sl_its_file_meta_v1_t *metadata_v1 = - (sl_its_file_meta_v1_t *)its_file_buffer; - if (metadata_v1->uid != old_uid) { - psa_status = PSA_ERROR_CORRUPTION_DETECTED; - goto exit; - } - metadata_v1->uid = new_uid; - } else -#endif - if (metadata->magic == SLI_PSA_ITS_META_MAGIC_V2) { - if (metadata->uid != old_uid) { - psa_status = PSA_ERROR_CORRUPTION_DETECTED; - goto exit; - } - metadata->uid = new_uid; - } else { - psa_status = PSA_ERROR_CORRUPTION_DETECTED; - goto exit; - } - -#if defined(SLI_PSA_ITS_ENCRYPTED) - // Encrypt and authenticate the modified data data - encrypt_status = encrypt_its_file( - metadata, blob->data, plaintext_length, blob, - its_file_size - sizeof(sli_its_file_meta_v2_t), &blob_length); - - if (encrypt_status != PSA_SUCCESS) { - psa_status = encrypt_status; - goto exit; - } - - if (blob_length != (its_file_size - sizeof(sli_its_file_meta_v2_t))) { - psa_status = PSA_ERROR_HARDWARE_FAILURE; - goto exit; - } -#endif - - // Overwrite the NVM3 token with the changed buffer - status = nvm3_writeData(nvm3_defaultHandle, nvm3_object_id, its_file_buffer, - its_file_size); - if (status == ECODE_NVM3_OK) { - // Update last lookup and report success - if (previous_lookup.set) { - if (previous_lookup.uid == old_uid) { - previous_lookup.uid = new_uid; - } - } - psa_status = PSA_SUCCESS; - } else { - psa_status = PSA_ERROR_STORAGE_FAILURE; - } - -exit: - if (its_file_buffer != NULL) { - // Clear and free key buffer before return. - memset(its_file_buffer, 0, its_file_size); - mbedtls_free(its_file_buffer); - } - sli_its_release_mutex(); - return psa_status; -} - -/** - * \brief Check if the ITS encryption is enabled - */ -psa_status_t sli_psa_its_encrypted(void) { -#if defined(SLI_PSA_ITS_ENCRYPTED) - return PSA_SUCCESS; -#else - return PSA_ERROR_NOT_SUPPORTED; -#endif -} - -#if defined(SLI_PSA_ITS_ENCRYPTED) && !defined(SEMAILBOX_PRESENT) -/** - * \brief Set the root key to be used when deriving session keys for ITS - * encryption. - * - * \param[in] root_key Buffer containing the root key. - * \param[in] root_key_size Size of the root key in bytes. Must be 32 (256 - * bits). - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The key was successfully set. - * \retval PSA_ERROR_INVALID_ARGUMENT The root key was NULL or had an - * invalid size. \retval PSA_ERROR_ALREADY_EXISTS The root key has - * already been initialized. - */ -psa_status_t sli_psa_its_set_root_key(uint8_t *root_key, size_t root_key_size) { - // Check that arguments are valid - if (root_key == NULL || root_key_size != sizeof(g_root_key.data)) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - // Check that the root key has not already been set - // (This is possibly too restrictive. For TrustZone usage this can be enforced - // by not exposing the function to NS instead.) - if (g_root_key.initialized) { - return PSA_ERROR_ALREADY_EXISTS; - } - - // Store the provided root key and mark it as initialized - memcpy(g_root_key.data, root_key, sizeof(g_root_key.data)); - g_root_key.initialized = true; - - return PSA_SUCCESS; -} -#endif // defined(SLI_PSA_ITS_ENCRYPTED) && !defined(SEMAILBOX_PRESENT) - -#else // (!SL_PSA_ITS_SUPPORT_V3_DRIVER) - -// ------------------------------------- -// Defines -#define SLI_PSA_ITS_V3_DRIVER (0x3A) -#define SLI_PSA_ITS_V2_DRIVER (0x74) -#define SLI_PSA_ITS_NOT_CHECKED (0xE8) -#define SLI_PSA_ITS_V2_DRIVER_FLAG_NVM3_ID (SLI_PSA_ITS_NVM3_RANGE_START - 1) -#define SLI_PSA_ITS_NVM3_INVALID_KEY (0) -#define SLI_PSA_ITS_NVM3_UNKNOWN_KEY (1) - -#if SL_PSA_ITS_MAX_FILES > SLI_PSA_ITS_NVM3_RANGE_SIZE -#error "Trying to store more ITS files then our NVM3 range allows for" -#endif - -#define SLI_PSA_ITS_CACHE_INIT_CHUNK_SIZE 16 - -// Internal error codes local to this compile unit -#define SLI_PSA_ITS_ECODE_NO_VALID_HEADER (ECODE_EMDRV_NVM3_BASE - 1) -#define SLI_PSA_ITS_ECODE_NEEDS_UPGRADE (ECODE_EMDRV_NVM3_BASE - 2) - -// ------------------------------------- -// Local global static variables - -SLI_STATIC bool nvm3_uid_set_cache_initialized = false; -SLI_STATIC uint32_t nvm3_uid_set_cache[(SL_PSA_ITS_MAX_FILES + 31) / 32] = {0}; -SLI_STATIC uint32_t nvm3_uid_tomb_cache[(SL_PSA_ITS_MAX_FILES + 31) / 32] = {0}; -#if SL_PSA_ITS_SUPPORT_V2_DRIVER -SLI_STATIC uint32_t its_driver_version = SLI_PSA_ITS_NOT_CHECKED; -#endif // SL_PSA_ITS_SUPPORT_V2_DRIVER - -#if defined(SLI_PSA_ITS_ENCRYPTED) -// The root key is an AES-256 key, and is therefore 32 bytes. -#define ROOT_KEY_SIZE (32) -// The session key is derived from CMAC, which means it is equal to the AES -// block size, i.e. 16 bytes -#define SESSION_KEY_SIZE (16) - -#if !defined(SEMAILBOX_PRESENT) -typedef struct { - bool initialized; - uint8_t data[ROOT_KEY_SIZE]; -} root_key_t; - -static root_key_t g_root_key = { - .initialized = false, - .data = {0}, -}; -#endif // !defined(SEMAILBOX_PRESENT) - -typedef struct { - bool active; - psa_storage_uid_t uid; - uint8_t data[SESSION_KEY_SIZE]; -} session_key_t; - -static session_key_t g_cached_session_key = { - .active = false, - .uid = 0, - .data = {0}, -}; -#endif // defined(SLI_PSA_ITS_ENCRYPTED) - -// ------------------------------------- -// Structs - -#if defined(SLI_PSA_ITS_SUPPORT_V1_FORMAT_INTERNAL) -typedef struct { - uint32_t magic; - psa_storage_uid_t uid; - psa_storage_create_flags_t flags; -} sl_its_file_meta_v1_t; -#endif // defined(SLI_PSA_ITS_SUPPORT_V1_FORMAT_INTERNAL) - -// ------------------------------------- -// Local function prototypes - -static psa_status_t find_nvm3_id(psa_storage_uid_t uid, bool find_empty_slot, - sli_its_file_meta_v2_t *its_file_meta, - size_t *its_file_offset, size_t *its_file_size, - nvm3_ObjectKey_t *output_nvm3_id); -static nvm3_ObjectKey_t derive_nvm3_id(psa_storage_uid_t uid); - -#if defined(TFM_CONFIG_SL_SECURE_LIBRARY) -static inline bool object_lives_in_s(const void *object, size_t object_size); -#endif - -#if defined(SLI_PSA_ITS_ENCRYPTED) -static psa_status_t derive_session_key(uint8_t *iv, size_t iv_size, - uint8_t *session_key, - size_t session_key_size); - -static psa_status_t sli_decrypt_its_file(sli_its_file_meta_v2_t *metadata, - sli_its_encrypted_blob_t *blob, - size_t blob_size, uint8_t *plaintext, - size_t plaintext_size, - size_t *plaintext_length); - -static psa_status_t authenticate_its_file(nvm3_ObjectKey_t nvm3_object_id, - psa_storage_uid_t *authenticated_uid); -#endif - -#if SL_PSA_ITS_SUPPORT_V2_DRIVER -static psa_status_t psa_its_get_legacy(nvm3_ObjectKey_t nvm3_object_id, - sli_its_file_meta_v2_t *its_file_meta, - size_t its_file_size, - size_t its_file_offset, void *p_data); -static psa_status_t detect_legacy_versions(); -static psa_status_t upgrade_all_keys(); - -#if defined(SLI_PSA_ITS_SUPPORT_V1_FORMAT_INTERNAL) -psa_status_t psa_its_set_v1(psa_storage_uid_t uid, uint32_t data_length, - const void *p_data, - psa_storage_create_flags_t create_flags); -#endif // SLI_PSA_ITS_SUPPORT_V1_FORMAT_INTERNAL -#endif // SL_PSA_ITS_SUPPORT_V2_DRIVER - -// ------------------------------------- -// Local function definitions -static inline uint32_t get_index(nvm3_ObjectKey_t key) { - return (key - (SLI_PSA_ITS_NVM3_RANGE_START)) / 32; -} - -static inline uint32_t get_offset(nvm3_ObjectKey_t key) { - return (key - (SLI_PSA_ITS_NVM3_RANGE_START)) % 32; -} - -static inline void set_cache(nvm3_ObjectKey_t key) { - nvm3_uid_set_cache[get_index(key)] |= (1 << get_offset(key)); - nvm3_uid_tomb_cache[get_index(key)] &= ~(1 << get_offset(key)); -} - -static inline void set_tomb(nvm3_ObjectKey_t key) { - nvm3_uid_tomb_cache[get_index(key)] |= (1 << get_offset(key)); - - uint32_t cache_not_empty = 0; - for (size_t i = 0; i < (((SL_PSA_ITS_MAX_FILES) + 31) / 32); i++) { - cache_not_empty += nvm3_uid_set_cache[i]; - } - if (cache_not_empty == 0) { - for (size_t i = 0; i < (((SL_PSA_ITS_MAX_FILES) + 31) / 32); i++) { - nvm3_uid_tomb_cache[i] = 0; - } - } -} - -#if SL_PSA_ITS_SUPPORT_V2_DRIVER -static inline psa_status_t write_driver_v3() { - uint8_t driver_verison = SLI_PSA_ITS_V3_DRIVER; - Ecode_t status; - status = - nvm3_writeData(nvm3_defaultHandle, SLI_PSA_ITS_V2_DRIVER_FLAG_NVM3_ID, - &driver_verison, sizeof(uint8_t)); - if (status != ECODE_NVM3_OK) { - return PSA_ERROR_STORAGE_FAILURE; - } - return PSA_SUCCESS; -} -#endif - -#if defined(TFM_CONFIG_SL_SECURE_LIBRARY) -// If an object of given size is fully encapsulated in a region of -// secure domain the function returns true. -static inline bool object_lives_in_s(const void *object, size_t object_size) { - cmse_address_info_t cmse_flags; - - for (size_t i = 0u; i < object_size; i++) { - cmse_flags = cmse_TTA((uint32_t *)object + i); - if (!cmse_flags.flags.secure) { - return false; - } - } - - return true; -} -#endif - -static inline void clear_cache(nvm3_ObjectKey_t key) { - nvm3_uid_set_cache[get_index(key)] ^= (1 << get_offset(key)); -} - -static inline bool lookup_cache(nvm3_ObjectKey_t key) { - return (bool)((nvm3_uid_set_cache[get_index(key)] >> get_offset(key)) & 0x1); -} - -static inline bool lookup_tomb(nvm3_ObjectKey_t key) { - return (bool)((nvm3_uid_tomb_cache[get_index(key)] >> get_offset(key)) & 0x1); -} - -static inline nvm3_ObjectKey_t increment_obj_id(nvm3_ObjectKey_t id) { - return SLI_PSA_ITS_NVM3_RANGE_START + - ((id - SLI_PSA_ITS_NVM3_RANGE_START + 1) % SL_PSA_ITS_MAX_FILES); -} -static inline nvm3_ObjectKey_t prng(psa_storage_uid_t uid) { - // Squash uid down to a 32 bit word - nvm3_ObjectKey_t uid_32 = uid & 0xFFFFFFFF; - nvm3_ObjectKey_t xored_32 = (uid >> 32) ^ uid_32; - nvm3_ObjectKey_t temp; - // Accumulate all "entropy" towards the LSB, since that is where we need it - for (size_t i = 1; i < 4; i++) { - temp = xored_32 ^ (xored_32 >> (8 * i)); - if ((temp & 0x3) != 0) { - temp = temp << 2; - } - uid_32 = (uid_32 + temp); - } - return uid_32; -} - -static inline nvm3_ObjectKey_t derive_nvm3_id(psa_storage_uid_t uid) { - return SLI_PSA_ITS_NVM3_RANGE_START + (prng(uid) % (SL_PSA_ITS_MAX_FILES)); -} - -static void init_cache(void) { - size_t num_keys_referenced_by_nvm3; - nvm3_ObjectKey_t keys_referenced_by_nvm3[SLI_PSA_ITS_CACHE_INIT_CHUNK_SIZE] = - {0}; - size_t num_del_keys_from_nvm3; - nvm3_ObjectKey_t deleted_keys_from_nvm3[SLI_PSA_ITS_CACHE_INIT_CHUNK_SIZE] = { - 0}; - for (nvm3_ObjectKey_t range_start = SLI_PSA_ITS_NVM3_RANGE_START; - range_start < SLI_PSA_ITS_NVM3_RANGE_END; - range_start += SLI_PSA_ITS_CACHE_INIT_CHUNK_SIZE) { - nvm3_ObjectKey_t range_end = - range_start + SLI_PSA_ITS_CACHE_INIT_CHUNK_SIZE; - if (range_end > SLI_PSA_ITS_NVM3_RANGE_END) { - range_end = SLI_PSA_ITS_NVM3_RANGE_END; - } - - num_keys_referenced_by_nvm3 = nvm3_enumObjects( - nvm3_defaultHandle, keys_referenced_by_nvm3, - sizeof(keys_referenced_by_nvm3) / sizeof(nvm3_ObjectKey_t), range_start, - range_end - 1); - - for (size_t i = 0; i < num_keys_referenced_by_nvm3; i++) { - set_cache(keys_referenced_by_nvm3[i]); - } - num_del_keys_from_nvm3 = nvm3_enumDeletedObjects( - nvm3_defaultHandle, deleted_keys_from_nvm3, - sizeof(deleted_keys_from_nvm3) / sizeof(nvm3_ObjectKey_t), range_start, - range_end - 1); - for (size_t i = 0; i < num_del_keys_from_nvm3; i++) { - set_tomb(deleted_keys_from_nvm3[i]); - } - } - nvm3_uid_set_cache_initialized = true; -} - -// Read the file metadata for a specific NVM3 ID -static Ecode_t get_file_metadata(nvm3_ObjectKey_t key, - sli_its_file_meta_v2_t *metadata, - size_t *its_file_offset, - size_t *its_file_size) { - // Initialize output variables to safe default - if (its_file_offset != NULL) { - *its_file_offset = 0; - } - if (its_file_size != NULL) { - *its_file_size = 0; - } - - Ecode_t status = nvm3_readPartialData(nvm3_defaultHandle, key, metadata, 0, - sizeof(sli_its_file_meta_v2_t)); - if (status != ECODE_NVM3_OK) { - return status; - } - -#if defined(SLI_PSA_ITS_SUPPORT_V1_FORMAT_INTERNAL) - // Re-read in v1 header format and translate to the latest structure version - if (metadata->magic == SLI_PSA_ITS_META_MAGIC_V1) { - sl_its_file_meta_v1_t key_meta_v1 = {0}; - status = nvm3_readPartialData(nvm3_defaultHandle, key, &key_meta_v1, 0, - sizeof(sl_its_file_meta_v1_t)); - - if (status != ECODE_NVM3_OK) { - return status; - } - - metadata->flags = key_meta_v1.flags; - metadata->uid = key_meta_v1.uid; - metadata->magic = SLI_PSA_ITS_META_MAGIC_V2; - - if (its_file_offset != NULL) { - *its_file_offset = sizeof(sl_its_file_meta_v1_t); - } - - status = SLI_PSA_ITS_ECODE_NEEDS_UPGRADE; - } else -#endif - { - if (its_file_offset != NULL) { - *its_file_offset = sizeof(sli_its_file_meta_v2_t); - } - } - - if (metadata->magic != SLI_PSA_ITS_META_MAGIC_V2) { - // No valid header found in this object - return SLI_PSA_ITS_ECODE_NO_VALID_HEADER; - } - - if (its_file_offset != NULL && its_file_size != NULL) { - // Calculate the ITS file size if requested - uint32_t obj_type; - Ecode_t info_status = - nvm3_getObjectInfo(nvm3_defaultHandle, key, &obj_type, its_file_size); - if (info_status != ECODE_NVM3_OK) { - return info_status; - } - - *its_file_size = *its_file_size - *its_file_offset; - } - - return status; -} - -#if SL_PSA_ITS_SUPPORT_V2_DRIVER -static psa_status_t psa_its_get_legacy(nvm3_ObjectKey_t nvm3_object_id, - sli_its_file_meta_v2_t *its_file_meta, - size_t its_file_size, - size_t its_file_offset, void *p_data) { - Ecode_t status; - if (its_file_size == 0) { - if (its_file_meta != NULL) { - return PSA_ERROR_DATA_INVALID; - } - } - -#if defined(SLI_PSA_ITS_ENCRYPTED) - psa_status_t psa_status = PSA_ERROR_CORRUPTION_DETECTED; - sli_its_encrypted_blob_t *blob = NULL; - size_t plaintext_length; - - // its_file_size includes size of sli_its_encrypted_blob_t struct - blob = (sli_its_encrypted_blob_t *)mbedtls_calloc(1, its_file_size); - if (blob == NULL) { - return PSA_ERROR_INSUFFICIENT_MEMORY; - } - memset(blob, 0, its_file_size); - - status = nvm3_readPartialData(nvm3_defaultHandle, nvm3_object_id, blob, - its_file_offset, its_file_size); - if (status != ECODE_NVM3_OK) { - psa_status = PSA_ERROR_STORAGE_FAILURE; - goto cleanup; - } - - // Decrypt and authenticate blob - psa_status = sli_decrypt_its_file( - its_file_meta, blob, its_file_size, blob->data, - its_file_size - SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD, &plaintext_length); - - if (psa_status != PSA_SUCCESS) { - goto cleanup; - } - - if (plaintext_length != - (its_file_size - SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD)) { - psa_status = PSA_ERROR_INVALID_SIGNATURE; - goto cleanup; - } - - if (its_file_size + its_file_offset > 0) { - memcpy(p_data, blob->data, its_file_size + its_file_offset); - } - psa_status = PSA_SUCCESS; - -cleanup: - if (blob != NULL) { - memset(blob, 0, its_file_size); - mbedtls_free(blob); - } - return psa_status; -#else - // If no encryption is used, just read out the data and write it directly to - // the output buffer - status = nvm3_readPartialData(nvm3_defaultHandle, nvm3_object_id, p_data, - its_file_offset, its_file_size); - - if (status != ECODE_NVM3_OK) { - return PSA_ERROR_STORAGE_FAILURE; - } else { - return PSA_SUCCESS; - } -#endif -} - -// Function sets detect the presence of v1 and v2 its driver. If there is -// something stored in v1/v2 driver range, it sets its_driver_version to -// SLI_PSA_ITS_V2_DRIVER. -static psa_status_t detect_legacy_versions() { - uint8_t driver_verison = 0; - Ecode_t status; - status = nvm3_readData(nvm3_defaultHandle, SLI_PSA_ITS_V2_DRIVER_FLAG_NVM3_ID, - &driver_verison, sizeof(uint8_t)); - if ((status != ECODE_NVM3_OK) && (status != ECODE_NVM3_ERR_KEY_NOT_FOUND)) { - return PSA_ERROR_STORAGE_FAILURE; - } - if (driver_verison == SLI_PSA_ITS_V3_DRIVER) { - its_driver_version = SLI_PSA_ITS_V3_DRIVER; - return PSA_SUCCESS; - } - - size_t num_keys_referenced_by_nvm3; - - nvm3_ObjectKey_t keys_referenced_by_nvm3[SLI_PSA_ITS_CACHE_INIT_CHUNK_SIZE] = - {0}; - - for (nvm3_ObjectKey_t range_start = SLI_PSA_ITS_NVM3_RANGE_START_V2_DRIVER; - range_start < SLI_PSA_ITS_NVM3_RANGE_END_V2_DRIVER; - range_start += SLI_PSA_ITS_CACHE_INIT_CHUNK_SIZE) { - nvm3_ObjectKey_t range_end = - range_start + SLI_PSA_ITS_CACHE_INIT_CHUNK_SIZE; - if (range_end > SLI_PSA_ITS_NVM3_RANGE_END_V2_DRIVER) { - range_end = SLI_PSA_ITS_NVM3_RANGE_END_V2_DRIVER; - } - - num_keys_referenced_by_nvm3 = nvm3_enumObjects( - nvm3_defaultHandle, keys_referenced_by_nvm3, - sizeof(keys_referenced_by_nvm3) / sizeof(nvm3_ObjectKey_t), range_start, - range_end - 1); - - if (num_keys_referenced_by_nvm3 > 0) { - sli_its_file_meta_v2_t its_file_meta = {0}; - size_t its_file_size = 0; - size_t its_file_offset = 0; - status = get_file_metadata(keys_referenced_by_nvm3[0], &its_file_meta, - &its_file_offset, &its_file_size); - if (status == SLI_PSA_ITS_ECODE_NO_VALID_HEADER) { - return PSA_ERROR_DOES_NOT_EXIST; - } - if (status != ECODE_NVM3_OK && - status != SLI_PSA_ITS_ECODE_NEEDS_UPGRADE) { - return PSA_ERROR_STORAGE_FAILURE; - } - - if ((its_file_meta.magic == SLI_PSA_ITS_META_MAGIC_V1) || - (its_file_meta.magic == SLI_PSA_ITS_META_MAGIC_V2)) { - its_driver_version = SLI_PSA_ITS_V2_DRIVER; - return PSA_SUCCESS; - } else { - return PSA_ERROR_STORAGE_FAILURE; - } - } - } - its_driver_version = SLI_PSA_ITS_V3_DRIVER; - return PSA_SUCCESS; -} - -static psa_status_t upgrade_all_keys() { - size_t num_keys_referenced_by_nvm3; - nvm3_ObjectKey_t keys_referenced_by_nvm3[SLI_PSA_ITS_CACHE_INIT_CHUNK_SIZE] = - {0}; - Ecode_t status; - psa_status_t psa_status = PSA_ERROR_CORRUPTION_DETECTED; - - sli_its_file_meta_v2_t its_file_meta = {0}; - size_t its_file_data_size; - uint8_t *its_file_buffer = NULL; - - size_t its_file_size = 0; - size_t its_file_offset; - - for (nvm3_ObjectKey_t range_start = SLI_PSA_ITS_NVM3_RANGE_START_V2_DRIVER; - range_start < SLI_PSA_ITS_NVM3_RANGE_END_V2_DRIVER; - range_start += SLI_PSA_ITS_CACHE_INIT_CHUNK_SIZE) { - nvm3_ObjectKey_t range_end = - range_start + SLI_PSA_ITS_CACHE_INIT_CHUNK_SIZE; - if (range_end >= SLI_PSA_ITS_NVM3_RANGE_END_V2_DRIVER) { - range_end = SLI_PSA_ITS_NVM3_RANGE_END_V2_DRIVER; - } - - num_keys_referenced_by_nvm3 = nvm3_enumObjects( - nvm3_defaultHandle, keys_referenced_by_nvm3, - sizeof(keys_referenced_by_nvm3) / sizeof(nvm3_ObjectKey_t), range_start, - range_end - 1); - for (size_t i = 0; i < num_keys_referenced_by_nvm3; i++) { - its_file_size = 0; - its_file_offset = 0; - status = get_file_metadata(keys_referenced_by_nvm3[i], &(its_file_meta), - &its_file_offset, &its_file_size); - if (status == SLI_PSA_ITS_ECODE_NO_VALID_HEADER) { - return PSA_ERROR_DOES_NOT_EXIST; - } - if (status != ECODE_NVM3_OK && - status != SLI_PSA_ITS_ECODE_NEEDS_UPGRADE) { - return PSA_ERROR_STORAGE_FAILURE; - } - -#if defined(SLI_PSA_ITS_ENCRYPTED) - // Subtract IV and MAC from ITS file as the below checks concern the - // actual data size - its_file_data_size = its_file_size - SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD; -#else - its_file_data_size = its_file_size; -#endif - - if ((its_file_meta.magic != SLI_PSA_ITS_META_MAGIC_V2) && - (its_file_meta.magic != SLI_PSA_ITS_META_MAGIC_V1)) { - return PSA_ERROR_STORAGE_FAILURE; - } - its_file_buffer = - mbedtls_calloc(1, its_file_size + sizeof(sli_its_file_meta_v2_t)); - if (its_file_buffer == NULL) { - return PSA_ERROR_INSUFFICIENT_MEMORY; - } -#if defined(SLI_PSA_ITS_ENCRYPTED) - psa_status = - psa_its_get_legacy(keys_referenced_by_nvm3[i], &(its_file_meta), - its_file_size, its_file_offset, its_file_buffer); -#else - psa_status = - psa_its_get_legacy(keys_referenced_by_nvm3[i], NULL, its_file_size, - its_file_offset, its_file_buffer); -#endif - if (psa_status != PSA_SUCCESS) { - psa_status = PSA_ERROR_STORAGE_FAILURE; - goto exit; - } - -#if defined(SLI_PSA_ITS_SUPPORT_V1_FORMAT_INTERNAL) - if (its_file_meta.magic == SLI_PSA_ITS_META_MAGIC_V1) { - psa_status = psa_its_set_v1(its_file_meta.uid, its_file_data_size, - its_file_buffer, its_file_meta.flags); - } else if (its_file_meta.magic == SLI_PSA_ITS_META_MAGIC_V2) -#endif - { - psa_status = psa_its_set(its_file_meta.uid, its_file_data_size, - its_file_buffer, its_file_meta.flags); - } - - if ((psa_status != PSA_SUCCESS) && - (psa_status != PSA_ERROR_NOT_PERMITTED)) { - goto exit; - } - status = - nvm3_deleteObject(nvm3_defaultHandle, keys_referenced_by_nvm3[i]); - - if (status != ECODE_NVM3_OK) { - psa_status = PSA_ERROR_STORAGE_FAILURE; - goto exit; - } - memset(its_file_buffer, 0, - its_file_size + sizeof(sli_its_file_meta_v2_t)); - mbedtls_free(its_file_buffer); - } - } - return PSA_SUCCESS; - -exit: - // Clear and free key buffer before return. - memset(its_file_buffer, 0, its_file_size + sizeof(sli_its_file_meta_v2_t)); - mbedtls_free(its_file_buffer); - return psa_status; -} - -#if defined(SLI_PSA_ITS_SUPPORT_V1_FORMAT_INTERNAL) -psa_status_t psa_its_set_v1(psa_storage_uid_t uid, uint32_t data_length, - const void *p_data, - psa_storage_create_flags_t create_flags) { - if ((data_length != 0U) && (p_data == NULL)) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - if (create_flags != PSA_STORAGE_FLAG_WRITE_ONCE && - create_flags != PSA_STORAGE_FLAG_NONE -#if defined(TFM_CONFIG_SL_SECURE_LIBRARY) - && create_flags != PSA_STORAGE_FLAG_WRITE_ONCE_SECURE_ACCESSIBLE -#endif - ) { - return PSA_ERROR_NOT_SUPPORTED; - } - -#if defined(TFM_CONFIG_SL_SECURE_LIBRARY) - if ((create_flags == PSA_STORAGE_FLAG_WRITE_ONCE_SECURE_ACCESSIBLE) && - (!object_lives_in_s(p_data, data_length))) { - // The flag indicates that this data should not be set by the non-secure - // domain - return PSA_ERROR_INVALID_ARGUMENT; - } -#endif - - Ecode_t status; - psa_status_t psa_status = PSA_ERROR_CORRUPTION_DETECTED; - sl_its_file_meta_v1_t *its_file_meta; - nvm3_ObjectKey_t nvm3_object_id = 0; - size_t its_file_size = data_length; - - uint8_t *its_file_buffer = - mbedtls_calloc(1, its_file_size + sizeof(sl_its_file_meta_v1_t)); - if (its_file_buffer == NULL) { - return PSA_ERROR_INSUFFICIENT_MEMORY; - } - memset(its_file_buffer, 0, its_file_size + sizeof(sl_its_file_meta_v1_t)); - - its_file_meta = (sl_its_file_meta_v1_t *)its_file_buffer; - sli_its_file_meta_v2_t its_file_meta_v2; - - sli_its_acquire_mutex(); - psa_status = - find_nvm3_id(uid, true, &its_file_meta_v2, NULL, NULL, &nvm3_object_id); - if (psa_status != PSA_SUCCESS) { - if (psa_status == PSA_ERROR_DOES_NOT_EXIST) { - psa_status = PSA_ERROR_INSUFFICIENT_STORAGE; - } - goto exit; - } - - its_file_meta->magic = SLI_PSA_ITS_META_MAGIC_V1; - its_file_meta->uid = uid; - its_file_meta->flags = create_flags; - - if (data_length != 0U) { - memcpy(its_file_buffer + sizeof(sl_its_file_meta_v1_t), ((uint8_t *)p_data), - data_length); - } - - status = nvm3_writeData(nvm3_defaultHandle, nvm3_object_id, its_file_buffer, - its_file_size + sizeof(sl_its_file_meta_v1_t)); - - if (status == ECODE_NVM3_OK) { - // Power-loss might occur, however upon boot, the look-up table will be - // re-filled as long as the data has been successfully written to NVM3. - set_cache(nvm3_object_id); - } else { - psa_status = PSA_ERROR_STORAGE_FAILURE; - } - -exit: - // Clear and free key buffer before return. - memset(its_file_buffer, 0, its_file_size + sizeof(sl_its_file_meta_v1_t)); - mbedtls_free(its_file_buffer); - sli_its_release_mutex(); - return psa_status; -} -#endif // SLI_PSA_ITS_SUPPORT_V1_FORMAT_INTERNAL -#endif // SL_PSA_ITS_SUPPORT_V1_DRIVER - -/** - * \brief Search through NVM3 for correct uid - * - * \param[in] uid UID under what we want to store the data - * \param[in] find_empty_slot Indicates whether we want to find existing data - * or empty space for storing new. \param[out] its_file_meta Meta information - * of ITS file \param[out] its_file_offset Offset of ITS file \param[out] - * its_file_size Size of ITS file \param[out] output_nvm3_id NVM3 ID - * corresponding to UID. - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed - * successfully \retval PSA_ERROR_DOES_NOT_EXIST The data with this - * UID are not stored in NVM3 \retval PSA_ERROR_NOT_PERMITTED The - * requested operation is not permitted - */ -static psa_status_t find_nvm3_id(psa_storage_uid_t uid, bool find_empty_slot, - sli_its_file_meta_v2_t *its_file_meta, - size_t *its_file_offset, size_t *its_file_size, - nvm3_ObjectKey_t *output_nvm3_id) { - Ecode_t status; - nvm3_ObjectKey_t tmp_id = 0; - nvm3_ObjectKey_t nvm3_object_id = 0; - nvm3_object_id = derive_nvm3_id(uid); - - if (nvm3_uid_set_cache_initialized == false) { -#if defined(TFM_CONFIG_SL_SECURE_LIBRARY) - // With SKL the NVM3 instance must be initialized by the NS app. We - // therefore check that it has been opened (which is done on init) rather - // than actually doing the init. - if (!nvm3_defaultHandle->hasBeenOpened) { -#else - if (nvm3_initDefault() != ECODE_NVM3_OK) { -#endif - return PSA_ERROR_STORAGE_FAILURE; - } - -#if SL_PSA_ITS_SUPPORT_V2_DRIVER - if (its_driver_version == SLI_PSA_ITS_NOT_CHECKED) { - if (detect_legacy_versions() != PSA_SUCCESS) { - return PSA_ERROR_STORAGE_FAILURE; - } - if (its_driver_version == SLI_PSA_ITS_V2_DRIVER) { - psa_status_t psa_status = upgrade_all_keys(); - if (psa_status != PSA_SUCCESS) { - return psa_status; - } - psa_status = write_driver_v3(); - if (psa_status != PSA_SUCCESS) { - return psa_status; - } - } else { - init_cache(); - } - } else { - init_cache(); - } -#else - init_cache(); -#endif - } - - for (size_t i = 0; i < SL_PSA_ITS_MAX_FILES; ++i) { - if (!lookup_cache(nvm3_object_id)) { - // dont exist - if (lookup_tomb(nvm3_object_id)) { - // tombstone - if (tmp_id == 0) { - // mark first empty space - tmp_id = nvm3_object_id; - } - nvm3_object_id = increment_obj_id(nvm3_object_id); - continue; - } else { - // empty space - if (find_empty_slot) { - if (tmp_id != 0) { - *output_nvm3_id = tmp_id; - return PSA_SUCCESS; - } - *output_nvm3_id = nvm3_object_id; - return PSA_SUCCESS; - } else { - return PSA_ERROR_DOES_NOT_EXIST; - } - } - } - status = get_file_metadata(nvm3_object_id, its_file_meta, its_file_offset, - its_file_size); - - if (status == SLI_PSA_ITS_ECODE_NO_VALID_HEADER || - status == ECODE_NVM3_ERR_READ_DATA_SIZE) { - // we don't expect any other data in our range then PSA ITS files. - // delete the file if the magic doesn't match or the object on disk - // is too small to even have full metadata. - status = nvm3_deleteObject(nvm3_defaultHandle, nvm3_object_id); - if (status != ECODE_NVM3_OK) { - return PSA_ERROR_DOES_NOT_EXIST; - } - } - - if (status != ECODE_NVM3_OK && status != SLI_PSA_ITS_ECODE_NEEDS_UPGRADE) { - return PSA_ERROR_STORAGE_FAILURE; - } - - if (its_file_meta->uid != uid) { - nvm3_object_id = increment_obj_id(nvm3_object_id); - } else { - if (find_empty_slot) { - if (its_file_meta->flags == PSA_STORAGE_FLAG_WRITE_ONCE -#if defined(TFM_CONFIG_SL_SECURE_LIBRARY) - || its_file_meta->flags == - PSA_STORAGE_FLAG_WRITE_ONCE_SECURE_ACCESSIBLE -#endif - ) { - return PSA_ERROR_NOT_PERMITTED; - } - } -#if defined(SLI_PSA_ITS_ENCRYPTED) - // If the UID already exists, authenticate the existing value and make - // sure the stored UID is the same. Note that this can potentially induce - // a significant performance hit. - psa_status_t psa_status = PSA_ERROR_CORRUPTION_DETECTED; - psa_storage_uid_t authenticated_uid = 0; - psa_status = authenticate_its_file(nvm3_object_id, &authenticated_uid); - if (psa_status != PSA_SUCCESS) { - return psa_status; - } - - if (authenticated_uid != uid) { - return PSA_ERROR_INVALID_SIGNATURE; - } -#endif - *output_nvm3_id = nvm3_object_id; - return PSA_SUCCESS; - } - } - if (find_empty_slot) { - if (tmp_id != 0) { - *output_nvm3_id = tmp_id; - return PSA_SUCCESS; - } - } - return PSA_ERROR_DOES_NOT_EXIST; -} - -#if defined(SLI_PSA_ITS_ENCRYPTED) -static inline void cache_session_key(uint8_t *session_key, - psa_storage_uid_t uid) { - // Cache the session key - memcpy(g_cached_session_key.data, session_key, - sizeof(g_cached_session_key.data)); - g_cached_session_key.uid = uid; - g_cached_session_key.active = true; -} - -/** - * \brief Derive a session key for ITS file encryption from the initialized root - * key and provided IV. - * - * \param[in] iv Pointer to array containing the initialization - * vector to be used in the key derivation. \param[in] iv_size Size of - * the IV buffer in bytes. Must be 12 bytes (AES-GCM IV size). \param[out] - * session_key Pointer to array where derived session key shall be stored. - * \param[out] session_key_size Size of the derived session key output array. - * Must be at least 32 bytes (AES-256 key size). - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed - * successfully \retval PSA_ERROR_BAD_STATE The root key has - * not been initialized. \retval PSA_ERROR_INVALID_ARGUMENT The - * operation failed because iv or session_key is NULL, or their sizes are - * incorrect. \retval PSA_ERROR_HARDWARE_FAILURE The operation failed - * because an internal cryptographic operation failed. - */ -static psa_status_t derive_session_key(uint8_t *iv, size_t iv_size, - uint8_t *session_key, - size_t session_key_size) { - if (iv == NULL || iv_size != AES_GCM_IV_SIZE || session_key == NULL || - session_key_size < SESSION_KEY_SIZE) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; - -#if defined(SEMAILBOX_PRESENT) - // For HSE devices, use the builtin TrustZone Root Key - psa_set_key_id(&attributes, SL_SE_BUILTIN_KEY_TRUSTZONE_ID); - - psa_key_lifetime_t reported_lifetime; - psa_drv_slot_number_t reported_slot; - status = mbedtls_psa_platform_get_builtin_key( - psa_get_key_id(&attributes), &reported_lifetime, &reported_slot); - - if (status != PSA_SUCCESS) { - return status; - } - - psa_set_key_lifetime(&attributes, reported_lifetime); - - uint8_t key_buffer[sizeof(sli_se_opaque_key_context_header_t)]; - size_t key_buffer_size; - status = sli_se_opaque_get_builtin_key(reported_slot, &attributes, key_buffer, - sizeof(key_buffer), &key_buffer_size); - if (status != PSA_SUCCESS) { - return status; - } -#else // defined(SEMAILBOX_PRESENT) - // For VSE devices, use the previously initialized root key - if (!g_root_key.initialized) { - return PSA_ERROR_BAD_STATE; - } - - // Prepare root key attributes - psa_set_key_algorithm(&attributes, PSA_ALG_CMAC); - psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); - psa_set_key_bits(&attributes, ROOT_KEY_SIZE * 8); - - // Point the key buffer to the global root key - uint8_t *key_buffer = (uint8_t *)g_root_key.data; - size_t key_buffer_size = sizeof(g_root_key.data); -#endif // defined(SEMAILBOX_PRESENT) - - // Use CMAC as a key derivation function - size_t session_key_length; - status = psa_driver_wrapper_mac_compute( - &attributes, key_buffer, key_buffer_size, PSA_ALG_CMAC, iv, iv_size, - session_key, session_key_size, &session_key_length); - - // Verify that the key derivation was successful before transferring the key - // to the caller - if (status != PSA_SUCCESS || session_key_length != SESSION_KEY_SIZE) { - memset(session_key, 0, session_key_size); - return PSA_ERROR_HARDWARE_FAILURE; - } - - return status; -} - -/** - * \brief Encrypt and authenticate ITS data with AES-128-GCM, storing the result - * in an encrypted blob. - * - * \param[in] metadata ITS metadata to be used as authenticated - * additional data. \param[in] plaintext Pointer to array containing data - * to be encrypted. \param[in] plaintext_size Size of provided plaintext data - * array. \param[out] blob Pointer to array where the resulting - * encrypted blob shall be placed. \param[in] blob_size Size of the output - * array. Must be at least as big as plaintext_size + - * SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD \param[out] blob_length Resulting - * size of the output blob. - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed - * successfully \retval PSA_ERROR_BAD_STATE The root key has - * not been initialized. \retval PSA_ERROR_INVALID_ARGUMENT The - * operation failed because one or more arguments are NULL or of invalid size. - * \retval PSA_ERROR_HARDWARE_FAILURE The operation failed because an - * internal cryptographic operation failed. - */ -psa_status_t sli_encrypt_its_file(sli_its_file_meta_v2_t *metadata, - uint8_t *plaintext, size_t plaintext_size, - sli_its_encrypted_blob_t *blob, - size_t blob_size, size_t *blob_length) { - if (metadata == NULL || (plaintext == NULL && plaintext_size > 0) || - blob == NULL || - blob_size < plaintext_size + SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD || - blob_length == NULL) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - // Generate IV - size_t iv_length = 0; - psa_status_t psa_status = mbedtls_psa_external_get_random( - NULL, blob->iv, AES_GCM_IV_SIZE, &iv_length); - - if (psa_status != PSA_SUCCESS || iv_length != AES_GCM_IV_SIZE) { - return PSA_ERROR_HARDWARE_FAILURE; - } - - // Prepare encryption key - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT); - psa_set_key_algorithm(&attributes, PSA_ALG_GCM); - psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); - psa_set_key_bits(&attributes, SESSION_KEY_SIZE * 8); - - uint8_t session_key[SESSION_KEY_SIZE]; - psa_status = derive_session_key(blob->iv, AES_GCM_IV_SIZE, session_key, - sizeof(session_key)); - if (psa_status != PSA_SUCCESS) { - return psa_status; - } - - cache_session_key(session_key, metadata->uid); - - // Retrieve data to be encrypted - if (plaintext_size != 0U) { - memcpy(blob->data, ((uint8_t *)plaintext), plaintext_size); - } - - // Encrypt and authenticate blob - size_t output_length = 0; - psa_status = psa_driver_wrapper_aead_encrypt( - &attributes, session_key, sizeof(session_key), PSA_ALG_GCM, blob->iv, - sizeof(blob->iv), (uint8_t *)metadata, - sizeof(sli_its_file_meta_v2_t), // metadata is AAD - blob->data, plaintext_size, blob->data, - plaintext_size + - AES_GCM_MAC_SIZE, // output == input for in-place encryption - &output_length); - - // Clear the local session key immediately after we're done using it - memset(session_key, 0, sizeof(session_key)); - - if (psa_status != PSA_SUCCESS) { - return PSA_ERROR_HARDWARE_FAILURE; - } - - if (output_length != plaintext_size + AES_GCM_MAC_SIZE) { - return PSA_ERROR_HARDWARE_FAILURE; - } - - *blob_length = output_length + AES_GCM_IV_SIZE; - - return PSA_SUCCESS; -} - -/** - * \brief Decrypt and authenticate encrypted ITS data. - * - * \param[in] metadata ITS metadata to be used as authenticated - * additional data. Must be identical to the metadata used during encryption. - * \param[in] blob Encrypted blob containing data to be decrypted. - * \param[in] blob_size Size of the encrypted blob in bytes. - * \param[out] plaintext Pointer to array where the decrypted plaintext - * shall be placed. \param[in] plaintext_size Size of the plaintext array. - * Must be equal to sizeof(blob->data) - AES_GCM_MAC_SIZE. \param[out] - * plaintext_length Resulting length of the decrypted plaintext. - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed - * successfully \retval PSA_ERROR_INVALID_SIGANTURE The operation - * failed because authentication of the decrypted data failed. \retval - * PSA_ERROR_BAD_STATE The root key has not been initialized. - * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because - * one or more arguments are NULL or of invalid size. \retval - * PSA_ERROR_HARDWARE_FAILURE The operation failed because an internal - * cryptographic operation failed. - */ -static psa_status_t sli_decrypt_its_file(sli_its_file_meta_v2_t *metadata, - sli_its_encrypted_blob_t *blob, - size_t blob_size, uint8_t *plaintext, - size_t plaintext_size, - size_t *plaintext_length) { - if (metadata == NULL || blob == NULL || - blob_size < plaintext_size + SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD || - (plaintext == NULL && plaintext_size > 0) || plaintext_length == NULL) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - // Prepare decryption key - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT); - psa_set_key_algorithm(&attributes, PSA_ALG_GCM); - psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); - psa_set_key_bits(&attributes, SESSION_KEY_SIZE * 8); - - psa_status_t psa_status = PSA_ERROR_CORRUPTION_DETECTED; - uint8_t session_key[SESSION_KEY_SIZE]; - - if (g_cached_session_key.active && - g_cached_session_key.uid == metadata->uid) { - // Use cached session key if it's already set and UID matches - memcpy(session_key, g_cached_session_key.data, sizeof(session_key)); - } else { - psa_status = derive_session_key(blob->iv, AES_GCM_IV_SIZE, session_key, - sizeof(session_key)); - if (psa_status != PSA_SUCCESS) { - return psa_status; - } - cache_session_key(session_key, metadata->uid); - } - - // Decrypt and authenticate blob - size_t output_length = 0; - psa_status = psa_driver_wrapper_aead_decrypt( - &attributes, session_key, sizeof(session_key), PSA_ALG_GCM, blob->iv, - sizeof(blob->iv), (uint8_t *)metadata, - sizeof(sli_its_file_meta_v2_t), // metadata is AAD - blob->data, plaintext_size + AES_GCM_MAC_SIZE, plaintext, plaintext_size, - &output_length); - - // Clear the session key immediately after we're done using it - memset(session_key, 0, sizeof(session_key)); - - // Invalid signature likely means that NVM data was tampered with - if (psa_status == PSA_ERROR_INVALID_SIGNATURE) { - return PSA_ERROR_INVALID_SIGNATURE; - } - - if (psa_status != PSA_SUCCESS || output_length != plaintext_size) { - return PSA_ERROR_HARDWARE_FAILURE; - } - - *plaintext_length = output_length; - - return PSA_SUCCESS; -} - -/** - * \brief Authenticate encrypted ITS data and return the UID of the ITS file - * that was authenticated. - * - * \details NOTE: This function will run sli_decrypt_its_file() internally. The - * difference from the sli_decrypt_its_file() function is that - * authenticate_its_file() reads the NVM3 data, decrypts it in order to - * authenticate the stored data, and then discards the plaintext. This is needed - * since PSA Crypto doesn't support the GMAC primitive directly, which means we - * have to run a full GCM decrypt for authentication. - * - * \param[in] nvm3_object_id The NVM3 id corresponding to the stored ITS - * file. \param[out] authenticated_uid UID for the authenticated ITS file. - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed - * successfully \retval PSA_ERROR_INVALID_SIGANTURE The operation - * failed because authentication of the decrypted data failed. \retval - * PSA_ERROR_BAD_STATE The root key has not been initialized. - * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because - * one or more arguments are NULL or of invalid size. \retval - * PSA_ERROR_HARDWARE_FAILURE The operation failed because an internal - * cryptographic operation failed. - */ -static psa_status_t -authenticate_its_file(nvm3_ObjectKey_t nvm3_object_id, - psa_storage_uid_t *authenticated_uid) { - psa_status_t psa_status = PSA_ERROR_CORRUPTION_DETECTED; - sli_its_file_meta_v2_t *its_file_meta = NULL; - sli_its_encrypted_blob_t *blob = NULL; - - uint32_t obj_type; - size_t its_file_size = 0; - Ecode_t status = nvm3_getObjectInfo(nvm3_defaultHandle, nvm3_object_id, - &obj_type, &its_file_size); - if (status != ECODE_NVM3_OK) { - return PSA_ERROR_STORAGE_FAILURE; - } - - uint8_t *its_file_buffer = mbedtls_calloc(1, its_file_size); - if (its_file_buffer == NULL) { - return PSA_ERROR_INSUFFICIENT_MEMORY; - } - memset(its_file_buffer, 0, its_file_size); - - status = nvm3_readData(nvm3_defaultHandle, nvm3_object_id, its_file_buffer, - its_file_size); - if (status != ECODE_NVM3_OK) { - psa_status = PSA_ERROR_STORAGE_FAILURE; - goto cleanup; - } - - its_file_meta = (sli_its_file_meta_v2_t *)its_file_buffer; - blob = (sli_its_encrypted_blob_t *)(its_file_buffer + - sizeof(sli_its_file_meta_v2_t)); - - // Decrypt and authenticate blob - size_t plaintext_length; - psa_status = sli_decrypt_its_file( - its_file_meta, blob, its_file_size - sizeof(sli_its_file_meta_v2_t), - blob->data, - its_file_size - sizeof(sli_its_file_meta_v2_t) - - SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD, - &plaintext_length); - - if (psa_status != PSA_SUCCESS) { - goto cleanup; - } - - if (plaintext_length != (its_file_size - sizeof(sli_its_file_meta_v2_t) - - SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD)) { - psa_status = PSA_ERROR_INVALID_SIGNATURE; - goto cleanup; - } - - if (authenticated_uid != NULL) { - *authenticated_uid = its_file_meta->uid; - } - - psa_status = PSA_SUCCESS; - -cleanup: - - // Discard output, as we're only interested in whether the authentication - // check passed or not. - memset(its_file_buffer, 0, its_file_size); - mbedtls_free(its_file_buffer); - - return psa_status; -} -#endif // defined(SLI_PSA_ITS_ENCRYPTED) - -// ------------------------------------- -// Global function definitions - -/** - * \brief create a new or modify an existing uid/value pair - * - * \param[in] uid the identifier for the data - * \param[in] data_length The size in bytes of the data in `p_data` - * \param[in] p_data A buffer containing the data - * \param[in] create_flags The flags that the data will be stored with - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed - * successfully \retval PSA_ERROR_NOT_PERMITTED The operation - * failed because the provided `uid` value was already created with - * PSA_STORAGE_FLAG_WRITE_ONCE \retval PSA_ERROR_NOT_SUPPORTED The - * operation failed because one or more of the flags provided in `create_flags` - * is not supported or is not valid \retval PSA_ERROR_INSUFFICIENT_STORAGE - * The operation failed because there was insufficient space on the storage - * medium \retval PSA_ERROR_STORAGE_FAILURE The operation failed - * because the physical storage has failed (Fatal error) \retval - * PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the - * provided pointers(`p_data`) is invalid, for example is `NULL` or references - * memory the caller cannot access \retval PSA_ERROR_HARDWARE_FAILURE The - * operation failed because an internal cryptographic operation failed. \retval - * PSA_ERROR_INVALID_SIGNATURE The operation failed because the provided - * `uid` doesnt match the autenticated uid from the storage - */ -psa_status_t psa_its_set(psa_storage_uid_t uid, uint32_t data_length, - const void *p_data, - psa_storage_create_flags_t create_flags) { - if ((data_length != 0U) && (p_data == NULL)) { - return PSA_ERROR_INVALID_ARGUMENT; - } - if ((data_length > NVM3_MAX_OBJECT_SIZE)) { - return PSA_ERROR_STORAGE_FAILURE; - } - - if (create_flags != PSA_STORAGE_FLAG_WRITE_ONCE && - create_flags != PSA_STORAGE_FLAG_NONE -#if defined(TFM_CONFIG_SL_SECURE_LIBRARY) - && create_flags != PSA_STORAGE_FLAG_WRITE_ONCE_SECURE_ACCESSIBLE -#endif - ) { - return PSA_ERROR_NOT_SUPPORTED; - } - -#if defined(TFM_CONFIG_SL_SECURE_LIBRARY) - if ((create_flags == PSA_STORAGE_FLAG_WRITE_ONCE_SECURE_ACCESSIBLE) && - (!object_lives_in_s(p_data, data_length))) { - // The flag indicates that this data should not be set by the non-secure - // domain - return PSA_ERROR_INVALID_ARGUMENT; - } -#endif - - Ecode_t status; - psa_status_t psa_status = PSA_ERROR_CORRUPTION_DETECTED; - sli_its_file_meta_v2_t *its_file_meta; - nvm3_ObjectKey_t nvm3_object_id = 0; -#if defined(SLI_PSA_ITS_ENCRYPTED) - sli_its_encrypted_blob_t *blob = NULL; - size_t its_file_size = data_length + SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD; - size_t blob_length = 0u; -#else - size_t its_file_size = data_length; -#endif - - uint8_t *its_file_buffer = - mbedtls_calloc(1, its_file_size + sizeof(sli_its_file_meta_v2_t)); - if (its_file_buffer == NULL) { - return PSA_ERROR_INSUFFICIENT_MEMORY; - } - memset(its_file_buffer, 0, its_file_size + sizeof(sli_its_file_meta_v2_t)); - - its_file_meta = (sli_its_file_meta_v2_t *)its_file_buffer; - - sli_its_acquire_mutex(); - psa_status = - find_nvm3_id(uid, true, its_file_meta, NULL, NULL, &nvm3_object_id); - if (psa_status != PSA_SUCCESS) { - if (psa_status == PSA_ERROR_DOES_NOT_EXIST) { - psa_status = PSA_ERROR_INSUFFICIENT_STORAGE; - } - goto exit; - } - - its_file_meta->magic = SLI_PSA_ITS_META_MAGIC_V2; - its_file_meta->uid = uid; - its_file_meta->flags = create_flags; - -#if defined(SLI_PSA_ITS_ENCRYPTED) - // Everything after the the file metadata will make up the encrypted & - // authenticated blob - blob = (sli_its_encrypted_blob_t *)(its_file_buffer + - sizeof(sli_its_file_meta_v2_t)); - - // Encrypt and authenticate the provided data - psa_status = - sli_encrypt_its_file(its_file_meta, (uint8_t *)p_data, data_length, blob, - its_file_size, &blob_length); - - if (psa_status != PSA_SUCCESS) { - goto exit; - } - - if (blob_length != its_file_size) { - psa_status = PSA_ERROR_HARDWARE_FAILURE; - goto exit; - } - -#else - if (data_length != 0U) { - memcpy(its_file_buffer + sizeof(sli_its_file_meta_v2_t), - ((uint8_t *)p_data), data_length); - } -#endif - - status = nvm3_writeData(nvm3_defaultHandle, nvm3_object_id, its_file_buffer, - its_file_size + sizeof(sli_its_file_meta_v2_t)); - - if (status == ECODE_NVM3_OK) { - // Power-loss might occur, however upon boot, the look-up table will be - // re-filled as long as the data has been successfully written to NVM3. - set_cache(nvm3_object_id); - } else { - psa_status = PSA_ERROR_STORAGE_FAILURE; - } - -exit: - // Clear and free key buffer before return. - memset(its_file_buffer, 0, its_file_size + sizeof(sli_its_file_meta_v2_t)); - mbedtls_free(its_file_buffer); - sli_its_release_mutex(); - return psa_status; -} - -/** - * \brief Retrieve the value associated with a provided uid - * - * \param[in] uid The uid value - * \param[in] data_offset The starting offset of the data requested - * \param[in] data_length the amount of data requested (and the minimum - * allocated size of the `p_data` buffer) \param[out] p_data The - * buffer where the data will be placed upon successful completion \param[out] - * p_data_length The amount of data returned in the p_data buffer - * - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed - * successfully \retval PSA_ERROR_DOES_NOT_EXIST The operation failed - * because the provided `uid` value was not found in the storage \retval - * PSA_ERROR_BUFFER_TOO_SMALL The operation failed because the data associated - * with provided uid is larger than `data_size` \retval - * PSA_ERROR_STORAGE_FAILURE The operation failed because the physical - * storage has failed (Fatal error) \retval PSA_ERROR_INVALID_ARGUMENT The - * operation failed because one of the provided pointers(`p_data`, - * `p_data_length`) is invalid. For example is `NULL` or references memory the - * caller cannot access. In addition, this can also happen if an invalid offset - * was provided. - */ -psa_status_t psa_its_get(psa_storage_uid_t uid, uint32_t data_offset, - uint32_t data_length, void *p_data, - size_t *p_data_length) { - if ((data_length != 0U) && (p_data_length == NULL)) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - if (data_length != 0U) { - // If the request amount of data is 0, allow invalid pointer of the output - // buffer. - if ((p_data == NULL) || ((uint32_t)p_data < SRAM_BASE) || - ((uint32_t)p_data > (SRAM_BASE + SRAM_SIZE - data_length))) { - return PSA_ERROR_INVALID_ARGUMENT; - } - } - -#if defined(SLI_PSA_ITS_ENCRYPTED) - size_t plaintext_length; - sli_its_encrypted_blob_t *blob = NULL; -#endif - psa_status_t psa_status = PSA_ERROR_CORRUPTION_DETECTED; - Ecode_t status; - sli_its_file_meta_v2_t its_file_meta = {0}; - size_t its_file_size = 0u; - size_t its_file_data_size = 0u; - size_t its_file_offset = 0u; - nvm3_ObjectKey_t nvm3_object_id; - - sli_its_acquire_mutex(); - psa_status = find_nvm3_id(uid, false, &its_file_meta, &its_file_offset, - &its_file_size, &nvm3_object_id); - if (psa_status != PSA_SUCCESS) { - goto exit; - } -#if defined(TFM_CONFIG_SL_SECURE_LIBRARY) - if (its_file_meta.flags == PSA_STORAGE_FLAG_WRITE_ONCE_SECURE_ACCESSIBLE && - !object_lives_in_s(p_data, data_length)) { - // The flag indicates that this data should not be read back to the - // non-secure domain - psa_status = PSA_ERROR_INVALID_ARGUMENT; - goto exit; - } -#endif - -#if defined(SLI_PSA_ITS_ENCRYPTED) - // Subtract IV and MAC from ITS file as the below checks concern the actual - // data size - its_file_data_size = its_file_size - SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD; -#else - its_file_data_size = its_file_size; -#endif - - if (data_length != 0U) { - if ((data_offset >= its_file_data_size) && (its_file_data_size != 0U)) { - psa_status = PSA_ERROR_INVALID_ARGUMENT; - goto exit; - } - - if ((its_file_data_size == 0U) && (data_offset != 0U)) { - psa_status = PSA_ERROR_INVALID_ARGUMENT; - goto exit; - } - } else { - // Allow the offset at the data size boundary if the requested amount of - // data is zero. - if (data_offset > its_file_data_size) { - psa_status = PSA_ERROR_INVALID_ARGUMENT; - goto exit; - } - } - - if (data_length > (its_file_data_size - data_offset)) { - *p_data_length = its_file_data_size - data_offset; - } else { - *p_data_length = data_length; - } - -#if defined(SLI_PSA_ITS_ENCRYPTED) - // its_file_size includes size of sli_its_encrypted_blob_t struct - blob = (sli_its_encrypted_blob_t *)mbedtls_calloc(1, its_file_size); - if (blob == NULL) { - psa_status = PSA_ERROR_INSUFFICIENT_MEMORY; - goto exit; - } - memset(blob, 0, its_file_size); - - status = nvm3_readPartialData(nvm3_defaultHandle, nvm3_object_id, blob, - its_file_offset, its_file_size); - if (status != ECODE_NVM3_OK) { - psa_status = PSA_ERROR_STORAGE_FAILURE; - goto exit; - } - - // Decrypt and authenticate blob - psa_status = sli_decrypt_its_file( - &its_file_meta, blob, its_file_size, blob->data, - its_file_size - SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD, &plaintext_length); - - if (psa_status != PSA_SUCCESS) { - goto exit; - } - - if (plaintext_length != - (its_file_size - SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD)) { - psa_status = PSA_ERROR_INVALID_SIGNATURE; - goto exit; - } - - // Verify that the requested UID is equal to the retrieved and authenticated - // UID - if (uid != its_file_meta.uid) { - psa_status = PSA_ERROR_INVALID_ARGUMENT; - goto exit; - } - - if (*p_data_length > 0) { - memcpy(p_data, blob->data + data_offset, *p_data_length); - } - psa_status = PSA_SUCCESS; - -exit: - if (blob != NULL) { - memset(blob, 0, its_file_size); - mbedtls_free(blob); - } - sli_its_release_mutex(); -#else - // If no encryption is used, just read out the data and write it directly to - // the output buffer - status = nvm3_readPartialData(nvm3_defaultHandle, nvm3_object_id, p_data, - its_file_offset + data_offset, *p_data_length); - - if (status != ECODE_NVM3_OK) { - psa_status = PSA_ERROR_STORAGE_FAILURE; - } else { - psa_status = PSA_SUCCESS; - } - -exit: - sli_its_release_mutex(); -#endif - - return psa_status; -} - -/** - * \brief Retrieve the metadata about the provided uid - * - * \param[in] uid The uid value - * \param[out] p_info A pointer to the `psa_storage_info_t` struct that - * will be populated with the metadata - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed - * successfully \retval PSA_ERROR_DOES_NOT_EXIST The operation failed - * because the provided uid value was not found in the storage \retval - * PSA_ERROR_STORAGE_FAILURE The operation failed because the physical - * storage has failed (Fatal error) \retval PSA_ERROR_INVALID_ARGUMENT The - * operation failed because one of the provided pointers(`p_info`) is invalid, - * for example is `NULL` or references memory the caller cannot access \retval - * PSA_ERROR_INVALID_SIGANTURE The operation failed because authentication of - * the stored metadata failed. - */ -psa_status_t psa_its_get_info(psa_storage_uid_t uid, - struct psa_storage_info_t *p_info) { - if (p_info == NULL) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - psa_status_t psa_status = PSA_ERROR_CORRUPTION_DETECTED; - sli_its_file_meta_v2_t its_file_meta = {0}; - size_t its_file_size = 0; - size_t its_file_offset = 0; - nvm3_ObjectKey_t nvm3_object_id; - - sli_its_acquire_mutex(); - psa_status = find_nvm3_id(uid, false, &its_file_meta, &its_file_offset, - &its_file_size, &nvm3_object_id); - if (psa_status != PSA_SUCCESS) { - sli_its_release_mutex(); - return psa_status; - } - - p_info->flags = its_file_meta.flags; - p_info->size = its_file_size; - -#if defined(SLI_PSA_ITS_ENCRYPTED) - // Remove IV and MAC size from file size - p_info->size = its_file_size - SLI_ITS_ENCRYPTED_BLOB_SIZE_OVERHEAD; -#endif - sli_its_release_mutex(); - return PSA_SUCCESS; -} - -/** - * \brief Remove the provided key and its associated data from the storage - * - * \param[in] uid The uid value - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed - * successfully \retval PSA_ERROR_DOES_NOT_EXIST The operation failed - * because the provided key value was not found in the storage \retval - * PSA_ERROR_NOT_PERMITTED The operation failed because the provided key - * value was created with PSA_STORAGE_FLAG_WRITE_ONCE \retval - * PSA_ERROR_STORAGE_FAILURE The operation failed because the physical - * storage has failed (Fatal error) - */ -psa_status_t psa_its_remove(psa_storage_uid_t uid) { - psa_status_t psa_status = PSA_ERROR_CORRUPTION_DETECTED; - Ecode_t status; - sli_its_file_meta_v2_t its_file_meta = {0}; - size_t its_file_size = 0; - size_t its_file_offset = 0; - nvm3_ObjectKey_t nvm3_object_id; - - sli_its_acquire_mutex(); - psa_status = find_nvm3_id(uid, false, &its_file_meta, &its_file_offset, - &its_file_size, &nvm3_object_id); - if (psa_status != PSA_SUCCESS) { - goto exit; - } - if (its_file_meta.flags == PSA_STORAGE_FLAG_WRITE_ONCE -#if defined(TFM_CONFIG_SL_SECURE_LIBRARY) - || (its_file_meta.flags == PSA_STORAGE_FLAG_WRITE_ONCE_SECURE_ACCESSIBLE) -#endif - ) { - psa_status = PSA_ERROR_NOT_PERMITTED; - goto exit; - } - status = nvm3_deleteObject(nvm3_defaultHandle, nvm3_object_id); - if (status == ECODE_NVM3_OK) { - // Power-loss might occur, however upon boot, the look-up table will be - // re-filled as long as the data has been successfully written to NVM3. - clear_cache(nvm3_object_id); - set_tomb(nvm3_object_id); - psa_status = PSA_SUCCESS; - } else { - psa_status = PSA_ERROR_STORAGE_FAILURE; - } - -exit: - sli_its_release_mutex(); - return psa_status; -} - -// ------------------------------------- -// Silicon Labs extensions - -static psa_storage_uid_t psa_its_identifier_of_slot(mbedtls_svc_key_id_t key) { -#if defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER) - /* Encode the owner in the upper 32 bits. This means that if - * owner values are nonzero (as they are on a PSA platform), - * no key file will ever have a value less than 0x100000000, so - * the whole range 0..0xffffffff is available for non-key files. */ - uint32_t unsigned_owner_id = MBEDTLS_SVC_KEY_ID_GET_OWNER_ID(key); - return ((uint64_t)unsigned_owner_id << 32) | - MBEDTLS_SVC_KEY_ID_GET_KEY_ID(key); -#else - /* Use the key id directly as a file name. - * psa_is_key_id_valid() in psa_crypto_slot_management.c - * is responsible for ensuring that key identifiers do not have a - * value that is reserved for non-key files. */ - return key; -#endif -} - -psa_status_t sli_psa_its_change_key_id(mbedtls_svc_key_id_t old_id, - mbedtls_svc_key_id_t new_id) { - psa_storage_uid_t old_uid = psa_its_identifier_of_slot(old_id); - psa_storage_uid_t new_uid = psa_its_identifier_of_slot(new_id); - size_t its_file_size = 0; - psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; - if (old_id == new_id) { - return PSA_SUCCESS; - } - // Check whether the key to migrate exists on disk - struct psa_storage_info_t p_info; - status = psa_its_get_info(old_uid, &p_info); - if (status != PSA_SUCCESS) { - return status; - } - - // Allocate temporary buffer and cast it to the metadata format - uint8_t *its_file_buffer = mbedtls_calloc(1, p_info.size); - if (its_file_buffer == NULL) { - return PSA_ERROR_INSUFFICIENT_MEMORY; - } - // Read contents of pre-existing key into the temporary buffer - status = - psa_its_get(old_uid, 0, p_info.size, its_file_buffer, &its_file_size); - - if (status != PSA_SUCCESS) { - goto exit; - } - - status = psa_its_set(new_uid, its_file_size, its_file_buffer, p_info.flags); - - if (status != PSA_SUCCESS) { - goto exit; - } - - status = psa_its_remove(old_uid); - - if (status != PSA_SUCCESS) { - goto exit; - } - -exit: - // Clear and free key buffer before return. - memset(its_file_buffer, 0, its_file_size); - mbedtls_free(its_file_buffer); - return status; -} - -/** - * \brief Check if the ITS encryption is enabled - */ -psa_status_t sli_psa_its_encrypted(void) { -#if defined(SLI_PSA_ITS_ENCRYPTED) - return PSA_SUCCESS; -#else - return PSA_ERROR_NOT_SUPPORTED; -#endif -} - -#if defined(SLI_PSA_ITS_ENCRYPTED) && !defined(SEMAILBOX_PRESENT) -/** - * \brief Set the root key to be used when deriving session keys for ITS - * encryption. - * - * \param[in] root_key Buffer containing the root key. - * \param[in] root_key_size Size of the root key in bytes. Must be 32 (256 - * bits). - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The key was successfully set. - * \retval PSA_ERROR_INVALID_ARGUMENT The root key was NULL or had an - * invalid size. \retval PSA_ERROR_ALREADY_EXISTS The root key has - * already been initialized. - */ -psa_status_t sli_psa_its_set_root_key(uint8_t *root_key, size_t root_key_size) { - // Check that arguments are valid - if (root_key == NULL || root_key_size != sizeof(g_root_key.data)) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - // Check that the root key has not already been set - // (This is possibly too restrictive. For TrustZone usage this can be enforced - // by not exposing the function to NS instead.) - if (g_root_key.initialized) { - return PSA_ERROR_ALREADY_EXISTS; - } - - // Store the provided root key and mark it as initialized - memcpy(g_root_key.data, root_key, sizeof(g_root_key.data)); - g_root_key.initialized = true; - - return PSA_SUCCESS; -} -#endif // defined(SLI_PSA_ITS_ENCRYPTED) && !defined(SEMAILBOX_PRESENT) -#endif // (!SL_PSA_ITS_SUPPORT_V3_DRIVER) -#endif // MBEDTLS_PSA_CRYPTO_STORAGE_C && !MBEDTLS_PSA_ITS_FILE_C diff --git a/protocol/bluetooth/bgcommon/lib/build/gcc/cortex-m33/bgcommon/release/libbgcommon.a b/protocol/bluetooth/bgcommon/lib/build/gcc/cortex-m33/bgcommon/release/libbgcommon.a index c11ef333f0..04a0654aac 100644 Binary files a/protocol/bluetooth/bgcommon/lib/build/gcc/cortex-m33/bgcommon/release/libbgcommon.a and b/protocol/bluetooth/bgcommon/lib/build/gcc/cortex-m33/bgcommon/release/libbgcommon.a differ diff --git a/protocol/bluetooth/bgcommon/lib/build/iar/cortex-m33/bgcommon/release/libbgcommon.a b/protocol/bluetooth/bgcommon/lib/build/iar/cortex-m33/bgcommon/release/libbgcommon.a index f844252bb1..f5d77ac3d1 100644 Binary files a/protocol/bluetooth/bgcommon/lib/build/iar/cortex-m33/bgcommon/release/libbgcommon.a and b/protocol/bluetooth/bgcommon/lib/build/iar/cortex-m33/bgcommon/release/libbgcommon.a differ diff --git a/protocol/bluetooth/bgstack/ll/lib/libbluetooth_controller_efr32xg24_gcc_release.a b/protocol/bluetooth/bgstack/ll/lib/libbluetooth_controller_efr32xg24_gcc_release.a index be720c886e..446f4d943e 100644 Binary files a/protocol/bluetooth/bgstack/ll/lib/libbluetooth_controller_efr32xg24_gcc_release.a and b/protocol/bluetooth/bgstack/ll/lib/libbluetooth_controller_efr32xg24_gcc_release.a differ diff --git a/protocol/bluetooth/bgstack/ll/lib/libbluetooth_controller_efr32xg24_iar_release.a b/protocol/bluetooth/bgstack/ll/lib/libbluetooth_controller_efr32xg24_iar_release.a index 7b0da41d29..196ff1e0ad 100644 Binary files a/protocol/bluetooth/bgstack/ll/lib/libbluetooth_controller_efr32xg24_iar_release.a and b/protocol/bluetooth/bgstack/ll/lib/libbluetooth_controller_efr32xg24_iar_release.a differ diff --git a/protocol/bluetooth/bgstack/ll/lib/libbluetooth_controller_efr32xg26_gcc_release.a b/protocol/bluetooth/bgstack/ll/lib/libbluetooth_controller_efr32xg26_gcc_release.a index 4f8309b815..4b2eb3f52e 100644 Binary files a/protocol/bluetooth/bgstack/ll/lib/libbluetooth_controller_efr32xg26_gcc_release.a and b/protocol/bluetooth/bgstack/ll/lib/libbluetooth_controller_efr32xg26_gcc_release.a differ diff --git a/protocol/bluetooth/bgstack/ll/lib/libbluetooth_controller_efr32xg26_iar_release.a b/protocol/bluetooth/bgstack/ll/lib/libbluetooth_controller_efr32xg26_iar_release.a index 080729015d..96090453da 100644 Binary files a/protocol/bluetooth/bgstack/ll/lib/libbluetooth_controller_efr32xg26_iar_release.a and b/protocol/bluetooth/bgstack/ll/lib/libbluetooth_controller_efr32xg26_iar_release.a differ diff --git a/protocol/bluetooth/build/gcc/cortex-m33/bt_host/hal/release/libbt_hal_series2.a b/protocol/bluetooth/build/gcc/cortex-m33/bt_host/hal/release/libbt_hal_series2.a index ff96471669..94c9c5e1c9 100644 Binary files a/protocol/bluetooth/build/gcc/cortex-m33/bt_host/hal/release/libbt_hal_series2.a and b/protocol/bluetooth/build/gcc/cortex-m33/bt_host/hal/release/libbt_hal_series2.a differ diff --git a/protocol/bluetooth/build/gcc/cortex-m33/bt_host/release/libbt_host.a b/protocol/bluetooth/build/gcc/cortex-m33/bt_host/release/libbt_host.a index eb9b8a9847..cb4210d269 100644 Binary files a/protocol/bluetooth/build/gcc/cortex-m33/bt_host/release/libbt_host.a and b/protocol/bluetooth/build/gcc/cortex-m33/bt_host/release/libbt_host.a differ diff --git a/protocol/bluetooth/build/iar/cortex-m33/bt_host/hal/release/libbt_hal_series2.a b/protocol/bluetooth/build/iar/cortex-m33/bt_host/hal/release/libbt_hal_series2.a index ae7dbe08a4..d70ac0e593 100644 Binary files a/protocol/bluetooth/build/iar/cortex-m33/bt_host/hal/release/libbt_hal_series2.a and b/protocol/bluetooth/build/iar/cortex-m33/bt_host/hal/release/libbt_hal_series2.a differ diff --git a/protocol/bluetooth/build/iar/cortex-m33/bt_host/hal/release/libbt_hal_series3.a b/protocol/bluetooth/build/iar/cortex-m33/bt_host/hal/release/libbt_hal_series3.a index 7da91438f4..83a441dac0 100644 Binary files a/protocol/bluetooth/build/iar/cortex-m33/bt_host/hal/release/libbt_hal_series3.a and b/protocol/bluetooth/build/iar/cortex-m33/bt_host/hal/release/libbt_hal_series3.a differ diff --git a/protocol/bluetooth/build/iar/cortex-m33/bt_host/release/libbt_host.a b/protocol/bluetooth/build/iar/cortex-m33/bt_host/release/libbt_host.a index 76a9d66b26..9373052b9b 100644 Binary files a/protocol/bluetooth/build/iar/cortex-m33/bt_host/release/libbt_host.a and b/protocol/bluetooth/build/iar/cortex-m33/bt_host/release/libbt_host.a differ diff --git a/protocol/openthread/libs/libsl_openthread_efr32mg2x_gcc.a b/protocol/openthread/libs/libsl_openthread_efr32mg2x_gcc.a index 63d327800b..6ba25e43df 100644 Binary files a/protocol/openthread/libs/libsl_openthread_efr32mg2x_gcc.a and b/protocol/openthread/libs/libsl_openthread_efr32mg2x_gcc.a differ diff --git a/protocol/openthread/platform-abstraction/efr32/radio.c b/protocol/openthread/platform-abstraction/efr32/radio.c new file mode 100644 index 0000000000..44ff3bcd8a --- /dev/null +++ b/protocol/openthread/platform-abstraction/efr32/radio.c @@ -0,0 +1,3486 @@ +/* + * Copyright (c) 2023, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements the OpenThread platform abstraction for radio communication. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE +#include +#endif + +#include "common/code_utils.hpp" +#include "common/debug.hpp" +#include "common/logging.hpp" +#include "utils/code_utils.h" +#include "utils/link_metrics.h" +#include "utils/mac_frame.h" + +#include "circular_queue.h" +#include "em_core.h" +#include "em_system.h" +#include "ieee802154mac.h" +#include "pa_conversions_efr32.h" +#include "platform-band.h" +#include "platform-efr32.h" +#include "radio_coex.h" +#include "radio_multi_channel.h" +#include "radio_power_manager.h" +#include "rail.h" +#include "rail_config.h" +#include "rail_ieee802154.h" +#include "sl_memory_manager.h" +#include "sl_multipan.h" +#include "sl_packet_utils.h" +#include "protocol/openthread/platform-abstraction/efr32/soft_source_match_table.h" // Full path to avoid ninja finding the wrong one first + +#ifdef SL_COMPONENT_CATALOG_PRESENT +#include "sl_component_catalog.h" +#endif // SL_COMPONENT_CATALOG_PRESENT + +#ifdef SL_CATALOG_RAIL_MULTIPLEXER_PRESENT +#include "sl_rail_mux_rename.h" +#endif + +#ifdef SL_CATALOG_RAIL_UTIL_ANT_DIV_PRESENT +#include "sl_rail_util_ant_div.h" +#include "sl_rail_util_ant_div_config.h" +#endif // SL_CATALOG_RAIL_UTIL_ANT_DIV_PRESENT + +#ifdef SL_CATALOG_RAIL_UTIL_COEX_PRESENT +#include "coexistence-802154.h" +#include "coexistence-ot.h" +#endif // SL_CATALOG_RAIL_UTIL_COEX_PRESENT + +#ifdef SL_CATALOG_RAIL_UTIL_IEEE802154_STACK_EVENT_PRESENT +#include "sl_rail_util_ieee802154_stack_event.h" +#endif // SL_CATALOG_RAIL_UTIL_IEEE802154_STACK_EVENT_PRESENT + +#ifdef SL_CATALOG_RAIL_UTIL_IEEE802154_PHY_SELECT_PRESENT +#include "sl_rail_util_ieee802154_phy_select.h" +#endif // #ifdef SL_CATALOG_RAIL_UTIL_IEEE802154_PHY_SELECT_PRESENT + +#include "sl_gp_interface.h" + +#ifdef SL_CATALOG_RAIL_UTIL_IEEE802154_FAST_CHANNEL_SWITCHING_PRESENT +#include "sl_rail_util_ieee802154_fast_channel_switching_config.h" +#endif // SL_CATALOG_RAIL_UTIL_IEEE802154_FAST_CHANNEL_SWITCHING_PRESENT + +//------------------------------------------------------------------------------ +// Enums, macros and static variables + +#ifndef LOW_BYTE +#define LOW_BYTE(n) ((uint8_t)((n) & 0xFF)) +#endif // LOW_BTE + +#ifndef HIGH_BYTE +#define HIGH_BYTE(n) ((uint8_t)(LOW_BYTE((n) >> 8))) +#endif // HIGH_BYTE + +// Intentionally maintaining separate groups for the different device series. +// This gives flexibility to add new elements to be read, like CCA Thresholds. +#if defined(_SILICON_LABS_32B_SERIES_2) +#define USERDATA_MFG_CUSTOM_EUI_64 (2) +#else +#error "UNSUPPORTED DEVICE" +#endif + +#ifndef USERDATA_END +#define USERDATA_END (USERDATA_BASE + FLASH_PAGE_SIZE) +#endif + +#if SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT > CIRCULAR_QUEUE_LEN_MAX +#error "Rx buffer count cannot be greater than max circular queue length." +#endif + +#define EFR32_RECEIVE_SENSITIVITY -100 // dBm +#define EFR32_RSSI_AVERAGING_TIME 16 // us +#define EFR32_RSSI_AVERAGING_TIMEOUT 300 // us + +// Internal flags +#define FLAG_RADIO_INIT_DONE 0x00000001 +#define FLAG_ONGOING_TX_DATA 0x00000002 +#define FLAG_ONGOING_TX_ACK 0x00000004 +#define FLAG_WAITING_FOR_ACK 0x00000008 +#define FLAG_CURRENT_TX_USE_CSMA 0x00000010 +#define FLAG_SCHEDULED_RX_PENDING 0x00000020 + +// Radio Events +#define EVENT_TX_SUCCESS 0x00000100 +#define EVENT_TX_CCA_FAILED 0x00000200 +#define EVENT_TX_NO_ACK 0x00000400 +#define EVENT_TX_SCHEDULER_ERROR 0x00000800 +#define EVENT_TX_FAILED 0x00001000 +#define EVENT_ACK_SENT_WITH_FP_SET 0x00002000 +#define EVENT_SECURED_ACK_SENT 0x00004000 +#define EVENT_SCHEDULED_RX_STARTED 0x00008000 + +#define TX_WAITING_FOR_ACK 0x00 +#define TX_NO_ACK 0x01 + +#define ONGOING_TX_FLAGS (FLAG_ONGOING_TX_DATA | FLAG_ONGOING_TX_ACK) +#define RADIO_TX_EVENTS \ + (EVENT_TX_SUCCESS | EVENT_TX_CCA_FAILED | EVENT_TX_NO_ACK | EVENT_TX_SCHEDULER_ERROR | EVENT_TX_FAILED) + +#define QUARTER_DBM_IN_DBM 4 +#define US_IN_MS 1000 + +/* FilterMask provided by RAIL is structured as follows: + * | Bit:7 | Bit:6 | Bit:5 | Bit:4 | Bit:3 | Bit:2 | Bit:1 | Bit:0 | + * | Addr2 | Addr1 | Addr0 | Bcast Addr | Pan Id2 | Pan Id1 | Pan Id0 | Bcast PanId | + * | Matched | Matched | Matched | Matched | Matched | Matched | Matched | Matched | + */ + +#define RADIO_BCAST_IID (0) +#define RADIO_GET_FILTER_MASK(iid) (1 << (iid)) +#define RADIO_PANID_FILTER_SHIFT (0) +#define RADIO_ADDR_FILTER_SHIFT (4) + +#define RADIO_BCAST_PANID_FILTER_MASK RADIO_GET_FILTER_MASK(0) +#define RADIO_INDEX0_PANID_FILTER_MASK RADIO_GET_FILTER_MASK(1) +#define RADIO_INDEX1_PANID_FILTER_MASK RADIO_GET_FILTER_MASK(2) +#define RADIO_INDEX2_PANID_FILTER_MASK RADIO_GET_FILTER_MASK(3) + +#define RADIO_GET_PANID_FILTER_MASK(filter) \ + (filter \ + & (RADIO_BCAST_PANID_FILTER_MASK | RADIO_INDEX0_PANID_FILTER_MASK | RADIO_INDEX1_PANID_FILTER_MASK \ + | RADIO_INDEX2_PANID_FILTER_MASK)) + +#define RADIO_BCAST_ADDR_FILTER_MASK (RADIO_GET_FILTER_MASK(0) << RADIO_ADDR_FILTER_SHIFT) +#define RADIO_INDEX0_ADDR_FILTER_MASK (RADIO_GET_FILTER_MASK(1) << RADIO_ADDR_FILTER_SHIFT) +#define RADIO_INDEX1_ADDR_FILTER_MASK (RADIO_GET_FILTER_MASK(2) << RADIO_ADDR_FILTER_SHIFT) +#define RADIO_INDEX2_ADDR_FILTER_MASK (RADIO_GET_FILTER_MASK(3) << RADIO_ADDR_FILTER_SHIFT) + +#define RADIO_GET_ADDR_FILTER_MASK(filter) \ + (filter \ + & (RADIO_BCAST_ADDR_FILTER_MASK | RADIO_INDEX0_ADDR_FILTER_MASK | RADIO_INDEX1_ADDR_FILTER_MASK \ + | RADIO_INDEX2_ADDR_FILTER_MASK)) + +#define RADIO_BCAST_PANID (0xFFFF) + +#define DEVICE_CAPABILITY_MCU_EN (DEVINFO->SWCAPA1 & _DEVINFO_SWCAPA1_RFMCUEN_MASK) + +static otRadioCaps sRadioCapabilities = + (OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_CSMA_BACKOFF | OT_RADIO_CAPS_ENERGY_SCAN | OT_RADIO_CAPS_SLEEP_TO_TX +#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) + | OT_RADIO_CAPS_TRANSMIT_SEC + // When scheduled tx is required, we support RAIL_StartScheduledCcaCsmaTx + // (delay is indicated in tx frame info set in MAC) + | OT_RADIO_CAPS_TRANSMIT_TIMING + // When scheduled rx is required, we support RAIL_ScheduleRx in our + // implementation of otPlatRadioReceiveAt + | OT_RADIO_CAPS_RECEIVE_TIMING +#endif + ); + +// Energy Scan +typedef enum { ENERGY_SCAN_STATUS_IDLE, ENERGY_SCAN_STATUS_IN_PROGRESS, ENERGY_SCAN_STATUS_COMPLETED } energyScanStatus; + +typedef enum { ENERGY_SCAN_MODE_SYNC, ENERGY_SCAN_MODE_ASYNC } energyScanMode; + +typedef struct { + uint8_t length; + uint8_t channel; + uint8_t lqi; + int8_t rssi; + uint8_t iid; + RAIL_Time_t timestamp; +} rxPacketDetails; + +typedef struct { + rxPacketDetails packetInfo; + uint8_t psdu[IEEE802154_MAX_LENGTH]; +} rxBuffer; + +typedef uint8_t rxBufferIndex_t; + +static volatile energyScanStatus sEnergyScanStatus; +static volatile int8_t sEnergyScanResultDbm; +static energyScanMode sEnergyScanMode; +// To track active interface the energy scan is being performed. +static uint8_t sEnergyScanActiveInterface = INVALID_INTERFACE_INDEX; + +static bool sIsSrcMatchEnabled = false; + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE +#define RADIO_EXT_ADDR_COUNT (RADIO_INTERFACE_COUNT - 1) +// To hold transmit/energy-scan requests from the hosts i.e. one per instance/host, +// if radio is busy. +#define RADIO_REQUEST_BUFFER_COUNT OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_NUM +#else +#define RADIO_EXT_ADDR_COUNT (RADIO_INTERFACE_COUNT) +#define RADIO_REQUEST_BUFFER_COUNT 1 +#endif + +typedef struct { + otRadioFrame frame; + uint8_t iid; +} radioFrame; + +// Receive +static Queue_t sRxPacketQueue; +static sl_memory_pool_t sRxPacketMemPoolHandle; +static uint8_t sReceiveAckPsdu[IEEE802154_MAX_LENGTH]; +static radioFrame sReceive; +static radioFrame sReceiveAck; +static otError sReceiveError; + +// Transmit +// One of the IID is reserved for broadcast hence we need RADIO_INTERFACE_COUNT - 1. +// IID zero is for broadcast, so request from host1 (i.e. iid = 1) will use tx buffer +// index 0 (i.e. iid - 1) and so on. +static radioFrame sTransmitBuffer[RADIO_REQUEST_BUFFER_COUNT]; +static uint8_t sTransmitPsdu[RADIO_REQUEST_BUFFER_COUNT][IEEE802154_MAX_LENGTH]; +static radioFrame *sCurrentTxPacket = NULL; +static uint8_t sLastLqi = 0; +static int8_t sLastRssi = 0; +static otExtAddress sExtAddress[RADIO_EXT_ADDR_COUNT]; + +// CSMA config: Should be globally scoped +RAIL_CsmaConfig_t csmaConfig = RAIL_CSMA_CONFIG_802_15_4_2003_2p4_GHz_OQPSK_CSMA; +RAIL_CsmaConfig_t cslCsmaConfig = RAIL_CSMA_CONFIG_SINGLE_CCA; + +#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT +static otRadioIeInfo sTransmitIeInfo[RADIO_REQUEST_BUFFER_COUNT]; +#endif + +// Radio +#define CCA_THRESHOLD_UNINIT 127 +#define CCA_THRESHOLD_DEFAULT -75 // dBm - default for 2.4GHz 802.15.4 + +#define UNINITIALIZED_CHANNEL 0xFF + +static bool sPromiscuous = false; +static efr32CommonConfig sCommonConfig; +static efr32BandConfig sBandConfig; +static efr32BandConfig *sCurrentBandConfig = NULL; + +static int8_t sCcaThresholdDbm = CCA_THRESHOLD_DEFAULT; + +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT +efr32RadioCounters railDebugCounters; + +// Create an alias for readability of RX debug tracking +#define rxDebugStep (railDebugCounters.mRadioDebugData.m8[RX_DEBUG_COUNTER0]) +#endif + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE +// Type of commands that can be added to the pending command buffer. +typedef enum { + kPendingCommandTypeTransmit, + kPendingCommandTypeEnergyScan, +} pendingCommandType; + +typedef struct { + // Energy scan channel. + uint8_t scanChannel; + // Energy scan duration. + uint16_t scanDuration; +} energyScanParams; + +// The structure representing pending transmit and energy-scan command requests. +typedef struct { + // The union of transmit and energy-scan requests parameters. + union { + // A pointer to the transmit radio frame. + otRadioFrame *txFrame; + // The structure of energy-scan request parameters. + energyScanParams energyScan; + } request; + // The pending command type. + pendingCommandType cmdType : 2; + // The interface iid of the pending command. + uint8_t iid : 2; +} pendingCommandEntry; + +static Queue_t sPendingCommandQueue; + +extern otInstance *sInstances[OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_NUM]; +static uint8_t sRailFilterMask = RADIO_BCAST_PANID_FILTER_MASK; +static bool isRadioTransmittingOrScanning(void); + +#if SL_RAIL_UTIL_IEEE802154_FAST_CHANNEL_SWITCHING_ENABLED +static RAIL_IEEE802154_RxChannelSwitchingCfg_t sChannelSwitchingCfg; +static RAIL_IEEE802154_RX_CHANNEL_SWITCHING_BUF_ALIGNMENT_TYPE + sChannelSwitchingBuffer[RAIL_IEEE802154_RX_CHANNEL_SWITCHING_BUF_BYTES + / RAIL_IEEE802154_RX_CHANNEL_SWITCHING_BUF_ALIGNMENT]; + +bool sl_is_multi_channel_enabled(void) +{ + uint8_t firstChannel = UNINITIALIZED_CHANNEL; + for (uint8_t i = 0U; i < RAIL_IEEE802154_RX_CHANNEL_SWITCHING_NUM_CHANNELS; i++) { + if (sChannelSwitchingCfg.channels[i] != UNINITIALIZED_CHANNEL) { + if (firstChannel == UNINITIALIZED_CHANNEL) { + firstChannel = sChannelSwitchingCfg.channels[i]; + } else if (firstChannel != sChannelSwitchingCfg.channels[i]) { + return true; + } + } + } + return false; +} + +otError sl_get_channel_switching_cfg(RAIL_IEEE802154_RxChannelSwitchingCfg_t *channelSwitchingCfg) +{ + otError error = OT_ERROR_NONE; + + otEXPECT_ACTION(channelSwitchingCfg != NULL, error = OT_ERROR_INVALID_ARGS); + + memcpy(channelSwitchingCfg, &sChannelSwitchingCfg, sizeof(sChannelSwitchingCfg)); + +exit: + return error; +} + +static uint8_t fastChannelIndex(uint8_t aChannel) +{ + for (uint8_t i = 0U; i < RAIL_IEEE802154_RX_CHANNEL_SWITCHING_NUM_CHANNELS; i++) { + if (sChannelSwitchingCfg.channels[i] == aChannel) { + return i; + } + } + return INVALID_INTERFACE_INDEX; +} + +#endif // SL_RAIL_UTIL_IEEE802154_FAST_CHANNEL_SWITCHING_ENABLED +#endif // OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + +// RAIL + +#ifdef SL_CATALOG_RAIL_MULTIPLEXER_PRESENT +RAIL_Handle_t gRailHandle; +#if SL_OPENTHREAD_COEX_COUNTER_ENABLE +static void sl_ot_coex_counter_on_event(sl_rail_util_coex_event_t event); +#endif // SL_OPENTHREAD_COEX_COUNTER_ENABLE +#else +RAIL_Handle_t emPhyRailHandle; +#endif // SL_CATALOG_RAIL_MULTIPLEXER_PRESENT + +static const RAIL_IEEE802154_Config_t sRailIeee802154Config = { + .addresses = NULL, + .ackConfig = + { + .enable = true, + .ackTimeout = 672, + .rxTransitions = + { + .success = RAIL_RF_STATE_RX, + .error = RAIL_RF_STATE_RX, + }, + .txTransitions = + { + .success = RAIL_RF_STATE_RX, + .error = RAIL_RF_STATE_RX, + }, + }, + .timings = + { + .idleToRx = 100, + .txToRx = 192 - 10, + .idleToTx = 100, +#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 + .rxToTx = 256, // accommodate enhanced ACKs +#else + .rxToTx = 192, +#endif + .rxSearchTimeout = 0, + .txToRxSearchTimeout = 0, + .txToTx = 0, + }, + .framesMask = RAIL_IEEE802154_ACCEPT_STANDARD_FRAMES, + .promiscuousMode = false, + .isPanCoordinator = false, + .defaultFramePendingInOutgoingAcks = false, +}; + +#if RADIO_CONFIG_SUBGHZ_SUPPORT +#define PHY_HEADER_SIZE 2 +// SHR: 4 bytes preamble, 2 bytes SFD +// 802.15.4 spec describes GFSK SHR to be the same format as SUN O-QPSK +// except preamble is 32 symbols (4 octets). +#define SHR_SIZE 6 +#else +#define PHY_HEADER_SIZE 1 +#define SHR_SIZE 5 // 4 bytes of preamble, 1 byte sync-word +#endif + +#define SHR_DURATION_US 160 // Duration of SHR in us. + +// Misc +static volatile uint32_t miscRadioState = 0; +static bool emPendingData = false; + +#ifdef SL_CATALOG_RAIL_UTIL_COEX_PRESENT +enum { + RHO_INACTIVE = 0, + RHO_EXT_ACTIVE, + RHO_INT_ACTIVE, // Not used + RHO_BOTH_ACTIVE, +}; + +static uint8_t rhoActive = RHO_INACTIVE; +static bool ptaGntEventReported; +static bool sRadioCoexEnabled = true; + +#if SL_OPENTHREAD_COEX_COUNTER_ENABLE +uint32_t efr32RadioCoexCounters[SL_RAIL_UTIL_COEX_EVENT_COUNT] = { 0 }; +#endif // SL_OPENTHREAD_COEX_COUNTER_ENABLE + +#endif // SL_CATALOG_RAIL_UTIL_COEX_PRESENT + +// Note: This callback can be called from ISR context. +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static bool rxPacketQueueOverflowCallback(const Queue_t *queue, void *data) +{ + OT_UNUSED_VARIABLE(queue); + OT_UNUSED_VARIABLE(data); + + // True to discard the queue item being considered for removal. + // False for nothing to be discarded from the queue. + // Do not discard the oldest entry from the queue, rather drop + // the new received packet, hence, return false. + return false; +} + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE +static bool pendingCommandQueueOverflowCallback(const Queue_t *queue, void *data) +{ + OT_UNUSED_VARIABLE(queue); + OT_UNUSED_VARIABLE(data); + + // We should never hit this callback because a host can only request + // one command at a time. Hence, added a assert if it happens. + OT_ASSERT(false); + + return false; +} +#endif + +#if RADIO_CONFIG_ENABLE_CUSTOM_EUI_SUPPORT +/* + * This API reads the UserData page on the given EFR device. + */ +static int readUserData(void *buffer, uint16_t index, int len, bool changeByteOrder) +{ + uint8_t *readLocation = (uint8_t *)USERDATA_BASE + index; + uint8_t *writeLocation = (uint8_t *)buffer; + + // Sanity check to verify if the ouput buffer is valid and the index and len are valid. + // If invalid, change the len to -1 and return. + otEXPECT_ACTION((writeLocation != NULL) && ((readLocation + len) <= (uint8_t *)USERDATA_END), len = -1); + + // Copy the contents of flash into output buffer. + + for (int idx = 0; idx < len; idx++) { + if (changeByteOrder) { + writeLocation[idx] = readLocation[(len - 1) - idx]; + } else { + writeLocation[idx] = readLocation[idx]; + } + } + +exit: + // Return len, len was changed to -1 to indicate failure. + return len; +} +#endif + +/* + * This API converts the FilterMask to appropriate IID. If there are any errors, it will fallback on bcast IID. + * + */ +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static inline uint8_t getIidFromFilterMask(uint8_t mask) +{ + uint8_t iid = INVALID_INTERFACE_INDEX; + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + // We need only the Pan Id masks here, as we are not matching the addresses. + // Also mask all the unused indices. + mask &= sRailFilterMask; + + // The only acceptable values for mask at this point are: + // 1 - BCAST PANID - IID(0) + // 2 - INDEX 0 - IID(1) + // 4 - INDEX 1 - IID(2) + // 8 - INDEX 2 - IID(3) + // + // The packet should either be directed to one of the PANs or Bcast. + // (mask & (mask -1) is a simplistic way of testing if the mask is a power of 2. + otEXPECT_ACTION(((mask != 0) && (mask & (mask - 1)) == 0), iid = 0); + + while (mask) { + iid++; + mask >>= 1; + } + +exit: +#else + (void)mask; + iid = RADIO_BCAST_IID; +#endif + return iid; +} + +/* + * This API validates the received FilterMask by checking if the destination address + * in the received packet corresponds to destination PanID. + */ +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static bool isFilterMaskValid(uint8_t mask) +{ + bool valid = false; + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + + /* Packet will be considered as a valid packet in 3 cases: + * Case 1: If the packet was directed towards bcast address or bcast panid + * + * Case 2: If the packet was directed to one of our valid address/PANID combos + * (Compare all non-bcast PANID filters against their corresponding + * address filters for same IID and see if any match) + * + * Case 3: We don't have either the destination addressing field or destination PanId + * in the received packet to determine if the dest address and dest pan match. + */ + if (((mask & RADIO_BCAST_PANID_FILTER_MASK) || (mask & RADIO_BCAST_ADDR_FILTER_MASK)) || // Case 1 + // Find any non-broadcast PAN ID match and get ready to compare it + ((((mask & (RADIO_INDEX0_PANID_FILTER_MASK | RADIO_INDEX1_PANID_FILTER_MASK | RADIO_INDEX2_PANID_FILTER_MASK)) + >> RADIO_PANID_FILTER_SHIFT) + & + // ...To see if it coincides with any address matches for same IID + (RADIO_GET_ADDR_FILTER_MASK(mask) >> RADIO_ADDR_FILTER_SHIFT)) + != 0) + || // Case 2 + (((RADIO_GET_PANID_FILTER_MASK(mask)) == 0) || ((RADIO_GET_ADDR_FILTER_MASK(mask)) == 0)) // Case 3 + ) { + valid = true; + } +#else + (void)mask; + valid = true; +#endif + + return valid; +} + +#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) + +enum { MAC_KEY_PREV, MAC_KEY_CURRENT, MAC_KEY_NEXT, MAC_KEY_COUNT }; + +typedef struct securityMaterial { + uint8_t ackKeyId; + uint8_t keyId; + uint32_t macFrameCounter; + uint32_t ackFrameCounter; + otMacKeyMaterial keys[MAC_KEY_COUNT]; +} securityMaterial; + +// Transmit Security +static securityMaterial sMacKeys[RADIO_INTERFACE_COUNT]; + +#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE + +// CSL parameters +static uint32_t sCslPeriod; +static uint32_t sCslSampleTime; + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static uint16_t getCslPhase(uint32_t shrTxTime) +{ + uint32_t cslPeriodInUs = sCslPeriod * OT_US_PER_TEN_SYMBOLS; + uint32_t diff; + + if (shrTxTime == 0U) { + shrTxTime = otPlatAlarmMicroGetNow(); + } + + diff = ((sCslSampleTime % cslPeriodInUs) - (shrTxTime % cslPeriodInUs) + cslPeriodInUs) % cslPeriodInUs; + + return (uint16_t)(diff / OT_US_PER_TEN_SYMBOLS); +} +#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE + +// Enhanced ACK IE data +static uint8_t sAckIeData[OT_ACK_IE_MAX_SIZE]; +static uint8_t sAckIeDataLength = 0; + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static uint8_t generateAckIeData(uint8_t *aLinkMetricsIeData, uint8_t aLinkMetricsIeDataLen) +{ + OT_UNUSED_VARIABLE(aLinkMetricsIeData); + OT_UNUSED_VARIABLE(aLinkMetricsIeDataLen); + + uint8_t offset = 0; + +#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE + if (sCslPeriod > 0) { + offset += otMacFrameGenerateCslIeTemplate(sAckIeData); + } +#endif + +#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE + if (aLinkMetricsIeData != NULL && aLinkMetricsIeDataLen > 0) { + offset += otMacFrameGenerateEnhAckProbingIe(sAckIeData, aLinkMetricsIeData, aLinkMetricsIeDataLen); + } +#endif + + return offset; +} + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static otError radioProcessTransmitSecurity(otRadioFrame *aFrame, uint8_t iid) +{ + otError error = OT_ERROR_NONE; + uint8_t keyId; + uint8_t keyToUse; + uint8_t panIndex = efr32GetPanIndexFromIid(iid); + + otEXPECT(otMacFrameIsSecurityEnabled(aFrame) && otMacFrameIsKeyIdMode1(aFrame) + && !aFrame->mInfo.mTxInfo.mIsSecurityProcessed); + + OT_ASSERT(panIndex != INVALID_INTERFACE_INDEX); + + if (otMacFrameIsAck(aFrame)) { + keyId = otMacFrameGetKeyId(aFrame); + + otEXPECT_ACTION(keyId != 0, error = OT_ERROR_FAILED); + + if (keyId == sMacKeys[iid].keyId - 1) { + keyToUse = MAC_KEY_PREV; + } else if (keyId == sMacKeys[iid].keyId) { + keyToUse = MAC_KEY_CURRENT; + } else if (keyId == sMacKeys[iid].keyId + 1) { + keyToUse = MAC_KEY_NEXT; + } else { + error = OT_ERROR_SECURITY; + otEXPECT(false); + } + } else { + keyId = sMacKeys[iid].keyId; + keyToUse = MAC_KEY_CURRENT; + } + + aFrame->mInfo.mTxInfo.mAesKey = &sMacKeys[iid].keys[keyToUse]; + + if (!aFrame->mInfo.mTxInfo.mIsHeaderUpdated) { + if (otMacFrameIsAck(aFrame)) { + // Store ack frame counter and ack key ID for receive frame + sMacKeys[iid].ackKeyId = keyId; + sMacKeys[iid].ackFrameCounter = sMacKeys[iid].macFrameCounter; + } + + otMacFrameSetKeyId(aFrame, keyId); + otMacFrameSetFrameCounter(aFrame, sMacKeys[iid].macFrameCounter++); + } + + efr32PlatProcessTransmitAesCcm(aFrame, &sExtAddress[panIndex]); + +exit: + return error; +} +#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static uint8_t readInitialPacketData(RAIL_RxPacketInfo_t *packetInfo, + uint8_t expected_data_bytes_max, + uint8_t expected_data_bytes_min, + uint8_t *buffer, + uint8_t buffer_len) +{ + uint8_t packetBytesRead = 0; + + // Check if we have enough buffer + OT_ASSERT((buffer_len >= expected_data_bytes_max) || (packetInfo != NULL)); + + // Read the packet info + RAIL_GetRxIncomingPacketInfo(gRailHandle, packetInfo); + + // We are trying to get the packet info of a packet before it is completely received. + // We do this to evaluate the FP bit in response and add IEs to ACK if needed. + // Check to see if we have received atleast minimum number of bytes requested. + otEXPECT_ACTION(packetInfo->packetBytes >= expected_data_bytes_min, packetBytesRead = 0); + + // Only extract what we care about + if (packetInfo->packetBytes > expected_data_bytes_max) { + packetInfo->packetBytes = expected_data_bytes_max; + // Check if the initial portion of the packet received so far exceeds the max value requested. + if (packetInfo->firstPortionBytes >= expected_data_bytes_max) { + // If we have received more, make sure to copy only the required bytes into the buffer. + packetInfo->firstPortionBytes = expected_data_bytes_max; + packetInfo->lastPortionData = NULL; + } + } + + // Copy number of bytes as indicated in `packetInfo->firstPortionBytes` into the buffer. + RAIL_CopyRxPacket(buffer, packetInfo); + packetBytesRead = packetInfo->packetBytes; + +exit: + return packetBytesRead; +} + +//------------------------------------------------------------------------------ +// Forward Declarations + +static void RAILCb_Generic(RAIL_Handle_t aRailHandle, RAIL_Events_t aEvents); + +static void efr32PhyStackInit(void); + +#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 +static void updateIeInfoTxFrame(uint32_t shrTxTime); +#endif + +#ifdef SL_CATALOG_RAIL_UTIL_COEX_PRESENT +static void efr32CoexInit(void); +// Try to transmit the current outgoing frame subject to MAC-level PTA +static void tryTxCurrentPacket(void); +#else +// Transmit the current outgoing frame. +void txCurrentPacket(void); +#define tryTxCurrentPacket txCurrentPacket +#endif // SL_CATALOG_RAIL_UTIL_COEX_PRESENT + +static void txFailedCallback(bool isAck, uint32_t status); + +static bool validatePacketDetails(RAIL_RxPacketHandle_t packetHandle, + RAIL_RxPacketDetails_t *pPacketDetails, + RAIL_RxPacketInfo_t *pPacketInfo, + uint16_t *packetLength); +static bool validatePacketTimestamp(RAIL_RxPacketDetails_t *pPacketDetails, uint16_t packetLength); + +static void updateRxFrameTimestamp(bool aIsAckFrame, RAIL_Time_t aTimestamp); + +static otError skipRxPacketLengthBytes(RAIL_RxPacketInfo_t *pPacketInfo); + +//------------------------------------------------------------------------------ +// Helper Functions + +#ifdef SL_CATALOG_RAIL_UTIL_IEEE802154_STACK_EVENT_PRESENT + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static bool phyStackEventIsEnabled(void) +{ + bool result = false; + +#if (defined(SL_CATALOG_RAIL_UTIL_ANT_DIV_PRESENT) && SL_RAIL_UTIL_ANT_DIV_RX_RUNTIME_PHY_SELECT) + result = true; +#endif // SL_CATALOG_RAIL_UTIL_ANT_DIV_PRESENT + +#ifdef SL_CATALOG_RAIL_UTIL_COEX_PRESENT + if (sRadioCoexEnabled) { + result |= sl_rail_util_coex_is_enabled(); +#ifdef SL_RAIL_UTIL_COEX_RUNTIME_PHY_SELECT + result |= SL_RAIL_UTIL_COEX_RUNTIME_PHY_SELECT; +#endif + } +#endif // SL_CATALOG_RAIL_UTIL_COEX_PRESENT + + return result; +} + +static RAIL_Events_t currentEventConfig = RAIL_EVENTS_NONE; +static void updateEvents(RAIL_Events_t mask, RAIL_Events_t values) +{ + RAIL_Status_t status; + RAIL_Events_t newEventConfig = (currentEventConfig & ~mask) | (values & mask); + if (newEventConfig != currentEventConfig) { + currentEventConfig = newEventConfig; + status = RAIL_ConfigEvents(gRailHandle, mask, values); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + } +} + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static sl_rail_util_ieee802154_stack_event_t handlePhyStackEvent(sl_rail_util_ieee802154_stack_event_t stackEvent, + uint32_t supplement) +{ + return (phyStackEventIsEnabled() +#ifdef SL_CATALOG_RAIL_MULTIPLEXER_PRESENT + ? sl_rail_mux_ieee802154_on_event(gRailHandle, stackEvent, supplement) +#else + ? sl_rail_util_ieee802154_on_event(stackEvent, supplement) +#endif + : 0); +} +#else +static void updateEvents(RAIL_Events_t mask, RAIL_Events_t values) +{ + RAIL_Status_t status; + status = RAIL_ConfigEvents(gRailHandle, mask, values); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); +} + +#define handlePhyStackEvent(event, supplement) 0 +#endif // SL_CATALOG_RAIL_UTIL_IEEE802154_STACK_EVENT_PRESENT + +// Set or clear the passed flag. +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static inline void setInternalFlag(uint16_t flag, bool val) +{ + CORE_DECLARE_IRQ_STATE; + CORE_ENTER_ATOMIC(); + miscRadioState = (val ? (miscRadioState | flag) : (miscRadioState & ~flag)); + CORE_EXIT_ATOMIC(); +} +// Returns true if the passed flag is set, false otherwise. +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static inline bool getInternalFlag(uint16_t flag) +{ + bool isFlagSet; + CORE_DECLARE_IRQ_STATE; + CORE_ENTER_ATOMIC(); + isFlagSet = (miscRadioState & flag) ? true : false; + CORE_EXIT_ATOMIC(); + + return isFlagSet; +} + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static inline bool txWaitingForAck(void) +{ + return (getInternalFlag(FLAG_ONGOING_TX_DATA) + && ((sCurrentTxPacket->frame.mPsdu[0] & IEEE802154_FRAME_FLAG_ACK_REQUIRED) != 0)); +} + +static inline bool isRadioTransmittingOrScanning(void) +{ + return ((sEnergyScanStatus != ENERGY_SCAN_STATUS_IDLE) || getInternalFlag(ONGOING_TX_FLAGS) + || getInternalFlag(FLAG_ONGOING_TX_ACK)); +} + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static bool txIsDataRequest(void) +{ + uint16_t fcf = sCurrentTxPacket->frame.mPsdu[IEEE802154_FCF_OFFSET] + | (sCurrentTxPacket->frame.mPsdu[IEEE802154_FCF_OFFSET + 1] << 8); + + return (getInternalFlag(FLAG_ONGOING_TX_DATA) && (fcf & IEEE802154_FRAME_TYPE_MASK) == IEEE802154_FRAME_TYPE_COMMAND); +} + +#ifdef SL_CATALOG_RAIL_UTIL_IEEE802154_STACK_EVENT_PRESENT +static inline bool isReceivingFrame(void) +{ + return (RAIL_GetRadioState(gRailHandle) & RAIL_RF_STATE_RX_ACTIVE) == RAIL_RF_STATE_RX_ACTIVE; +} +#endif + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static void radioSetIdle(void) +{ + if (RAIL_GetRadioState(gRailHandle) != RAIL_RF_STATE_IDLE) { + RAIL_Idle(gRailHandle, RAIL_IDLE, true); + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_TX_IDLED, 0U); + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_RX_IDLED, 0U); + } + RAIL_YieldRadio(gRailHandle); +} + +static otError radioSetRx(uint8_t aChannel) +{ + otError error = OT_ERROR_NONE; + RAIL_Status_t status; + + RAIL_SchedulerInfo_t bgRxSchedulerInfo = { + .priority = RADIO_SCHEDULER_BACKGROUND_RX_PRIORITY, + // sliptime/transaction time is not used for bg rx + }; + +#if SL_RAIL_UTIL_IEEE802154_FAST_CHANNEL_SWITCHING_ENABLED && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + if (sl_is_multi_channel_enabled()) { + // Calling RAIL_StartRx with a channel not listed in the channel + // switching config is a bug. + OT_ASSERT(fastChannelIndex(aChannel) != INVALID_INTERFACE_INDEX); + + radioSetIdle(); + status = RAIL_IEEE802154_ConfigRxChannelSwitching(gRailHandle, &sChannelSwitchingCfg); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + status = RAIL_ConfigRxOptions(gRailHandle, RAIL_RX_OPTION_CHANNEL_SWITCHING, RAIL_RX_OPTION_CHANNEL_SWITCHING); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + } else { + status = RAIL_ConfigRxOptions(gRailHandle, RAIL_RX_OPTION_CHANNEL_SWITCHING, RAIL_RX_OPTIONS_NONE); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + } +#endif + + status = RAIL_StartRx(gRailHandle, aChannel, &bgRxSchedulerInfo); + otEXPECT_ACTION(status == RAIL_STATUS_NO_ERROR, error = OT_ERROR_FAILED); + + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_RX_LISTEN, 0U); + + otLogInfoPlat("State=OT_RADIO_STATE_RECEIVE"); +exit: + return error; +} + +#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) +static otError radioScheduleRx(uint8_t aChannel, uint32_t aStart, uint32_t aDuration) +{ + otError error = OT_ERROR_NONE; + RAIL_Status_t status; + + RAIL_SchedulerInfo_t bgRxSchedulerInfo = { + .priority = RADIO_SCHEDULER_BACKGROUND_RX_PRIORITY, + // sliptime/transaction time is not used for bg rx + }; + + // Configure scheduled receive as requested + RAIL_ScheduleRxConfig_t rxCfg = { .start = aStart, + .startMode = RAIL_TIME_ABSOLUTE, + .end = aDuration, + .endMode = RAIL_TIME_DELAY, + .rxTransitionEndSchedule = 1, // This lets us idle after a scheduled-rx + .hardWindowEnd = 0 }; // This lets us receive a packet near a window-end-event + + status = RAIL_ScheduleRx(gRailHandle, aChannel, &rxCfg, &bgRxSchedulerInfo); + otEXPECT_ACTION(status == RAIL_STATUS_NO_ERROR, error = OT_ERROR_FAILED); + + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_RX_LISTEN, 0U); +exit: + return error; +} +#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) + +//------------------------------------------------------------------------------ +// Radio Initialization +static RAIL_Handle_t efr32RailInit(efr32CommonConfig *aCommonConfig) +{ + RAIL_Status_t status; + RAIL_Handle_t handle; + +#if !OPENTHREAD_RADIO + OT_ASSERT(DEVICE_CAPABILITY_MCU_EN); +#endif + + handle = RAIL_Init(&aCommonConfig->mRailConfig, NULL); + OT_ASSERT(handle != NULL); + +#if defined(SL_CATALOG_POWER_MANAGER_PRESENT) + status = RAIL_InitPowerManager(); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); +#endif // SL_CATALOG_POWER_MANAGER_PRESENT + + status = RAIL_ConfigCal(handle, RAIL_CAL_ALL); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + + status = RAIL_SetPtiProtocol(handle, RAIL_PTI_PROTOCOL_THREAD); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + + status = RAIL_IEEE802154_Init(handle, &sRailIeee802154Config); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + +#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) + // Enhanced Frame Pending + status = RAIL_IEEE802154_EnableEarlyFramePending(handle, true); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + + status = RAIL_IEEE802154_EnableDataFramePending(handle, true); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + + // Copies of MAC keys for encrypting at the radio layer + memset(sMacKeys, 0, sizeof(sMacKeys)); +#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) + + uint16_t actualLength = 0; + actualLength = RAIL_SetTxFifo(handle, aCommonConfig->mRailTxFifo.fifo, 0, sizeof(aCommonConfig->mRailTxFifo.fifo)); + OT_ASSERT(actualLength == sizeof(aCommonConfig->mRailTxFifo.fifo)); + + // Enable RAIL multi-timer + RAIL_ConfigMultiTimer(true); + + return handle; +} + +static void efr32RailConfigLoad(efr32BandConfig *aBandConfig, int8_t aTxPower) +{ + RAIL_Status_t status; + RAIL_TxPowerConfig_t txPowerConfig = { SL_RAIL_UTIL_PA_SELECTION_2P4GHZ, + SL_RAIL_UTIL_PA_VOLTAGE_MV, + SL_RAIL_UTIL_PA_RAMP_TIME_US }; + + if (aBandConfig->mChannelConfig != NULL) { + status = RAIL_IEEE802154_SetPtiRadioConfig(gRailHandle, RAIL_IEEE802154_PTI_RADIO_CONFIG_915MHZ_R23_NA_EXT); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + + uint16_t firstChannel = UNINITIALIZED_CHANNEL; + firstChannel = RAIL_ConfigChannels(gRailHandle, aBandConfig->mChannelConfig, NULL); + OT_ASSERT(firstChannel == aBandConfig->mChannelMin); + + txPowerConfig.mode = SL_RAIL_UTIL_PA_SELECTION_SUBGHZ; + status = + RAIL_IEEE802154_ConfigGOptions(gRailHandle, RAIL_IEEE802154_G_OPTION_GB868, RAIL_IEEE802154_G_OPTION_GB868); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + } else { +#if defined(SL_CATALOG_RAIL_UTIL_IEEE802154_PHY_SELECT_PRESENT) + status = sl_rail_util_ieee802154_config_radio(gRailHandle); +#else + status = RAIL_IEEE802154_Config2p4GHzRadio(gRailHandle); +#endif // SL_CATALOG_RAIL_UTIL_IEEE802154_PHY_SELECT_PRESENT + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + } + +#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) + // 802.15.4E support (only on platforms that support it, so error checking is disabled) + // Note: This has to be called after RAIL_IEEE802154_Config2p4GHzRadio due to a bug where this call + // can overwrite options set below. + RAIL_IEEE802154_ConfigEOptions(gRailHandle, + (RAIL_IEEE802154_E_OPTION_GB868 | RAIL_IEEE802154_E_OPTION_ENH_ACK), + (RAIL_IEEE802154_E_OPTION_GB868 | RAIL_IEEE802154_E_OPTION_ENH_ACK)); +#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) + + if (aTxPower != SL_INVALID_TX_POWER) { + sli_update_tx_power_after_config_update(&txPowerConfig, aTxPower); + } +} + +static efr32BandConfig *efr32RadioGetBandConfig(uint8_t aChannel) +{ + efr32BandConfig *config = NULL; + + if ((sBandConfig.mChannelMin <= aChannel) && (aChannel <= sBandConfig.mChannelMax)) { + config = &sBandConfig; + } + + return config; +} + +static void efr32ConfigInit(void (*aEventCallback)(RAIL_Handle_t railHandle, RAIL_Events_t events)) +{ + sCommonConfig.mRailConfig.eventsCallback = aEventCallback; + sCommonConfig.mRailConfig.protocol = NULL; // only used by Bluetooth stack +#if RADIO_CONFIG_DMP_SUPPORT + sCommonConfig.mRailConfig.scheduler = &(sCommonConfig.mRailSchedState); +#else + sCommonConfig.mRailConfig.scheduler = NULL; // only needed for DMP +#endif + +#if RADIO_CONFIG_2P4GHZ_OQPSK_SUPPORT + sBandConfig.mChannelConfig = NULL; +#else + sBandConfig.mChannelConfig = channelConfigs[0]; +#endif + sBandConfig.mChannelMin = SL_CHANNEL_MIN; + sBandConfig.mChannelMax = SL_CHANNEL_MAX; + +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + memset(&railDebugCounters, 0x00, sizeof(efr32RadioCounters)); +#endif + + sli_init_power_manager(); + + gRailHandle = efr32RailInit(&sCommonConfig); + OT_ASSERT(gRailHandle != NULL); + + updateEvents(RAIL_EVENTS_ALL, + (0 | RAIL_EVENT_RX_ACK_TIMEOUT | RAIL_EVENT_RX_PACKET_RECEIVED +#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 + | RAIL_EVENT_SCHEDULED_TX_STARTED | RAIL_EVENT_TX_SCHEDULED_TX_MISSED | RAIL_EVENT_SCHEDULED_RX_STARTED + | RAIL_EVENT_RX_SCHEDULED_RX_END | RAIL_EVENT_RX_SCHEDULED_RX_MISSED +#endif + | RAIL_EVENTS_TXACK_COMPLETION | RAIL_EVENTS_TX_COMPLETION | RAIL_EVENT_RSSI_AVERAGE_DONE + | RAIL_EVENT_IEEE802154_DATA_REQUEST_COMMAND +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT || RADIO_CONFIG_DMP_SUPPORT + | RAIL_EVENT_CONFIG_SCHEDULED | RAIL_EVENT_CONFIG_UNSCHEDULED | RAIL_EVENT_SCHEDULER_STATUS +#endif + | RAIL_EVENT_CAL_NEEDED)); + + efr32RailConfigLoad(&(sBandConfig), OPENTHREAD_CONFIG_DEFAULT_TRANSMIT_POWER); +} + +void efr32RadioInit(void) +{ + if (getInternalFlag(FLAG_RADIO_INIT_DONE)) { + return; + } + RAIL_Status_t status; + sl_status_t rxMemPoolStatus; + bool queueStatus; + + // check if RAIL_TX_FIFO_SIZE is power of two.. + OT_ASSERT((RAIL_TX_FIFO_SIZE & (RAIL_TX_FIFO_SIZE - 1)) == 0); + + // check the limits of the RAIL_TX_FIFO_SIZE. + OT_ASSERT((RAIL_TX_FIFO_SIZE >= 64) || (RAIL_TX_FIFO_SIZE <= 4096)); + + efr32ConfigInit(RAILCb_Generic); + setInternalFlag(FLAG_RADIO_INIT_DONE, true); + + status = RAIL_ConfigSleep(gRailHandle, RAIL_SLEEP_CONFIG_TIMERSYNC_ENABLED); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + + sReceive.frame.mLength = 0; + sReceive.frame.mPsdu = NULL; + + sReceiveAck.frame.mLength = 0; + sReceiveAck.frame.mPsdu = sReceiveAckPsdu; + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + // Initialize the queue for received packets. + queueStatus = queueInit(&sPendingCommandQueue, RADIO_REQUEST_BUFFER_COUNT); + OT_ASSERT(queueStatus); + + // Specify a callback to be called upon queue overflow. + queueStatus = queueOverflow(&sPendingCommandQueue, &pendingCommandQueueOverflowCallback); + OT_ASSERT(queueStatus); +#endif + + for (uint8_t i = 0; i < RADIO_REQUEST_BUFFER_COUNT; i++) { + // Initialize the tx buffer params. + sTransmitBuffer[i].iid = INVALID_INTERFACE_INDEX; + sTransmitBuffer[i].frame.mLength = 0; + sTransmitBuffer[i].frame.mPsdu = sTransmitPsdu[i]; + +#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT + sTransmitBuffer[i].frame.mInfo.mTxInfo.mIeInfo = &sTransmitIeInfo[i]; +#endif + } + +#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE + otLinkMetricsInit(EFR32_RECEIVE_SENSITIVITY); +#endif + sCurrentBandConfig = efr32RadioGetBandConfig(OPENTHREAD_CONFIG_DEFAULT_CHANNEL); + OT_ASSERT(sCurrentBandConfig != NULL); + + sl_rail_util_pa_init(); + sli_set_tx_power_in_rail(OPENTHREAD_CONFIG_DEFAULT_TRANSMIT_POWER); + + status = RAIL_ConfigRxOptions(gRailHandle, RAIL_RX_OPTION_TRACK_ABORTED_FRAMES, RAIL_RX_OPTION_TRACK_ABORTED_FRAMES); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + efr32PhyStackInit(); + efr32RadioSetCcaMode(SL_OPENTHREAD_RADIO_CCA_MODE); + + sEnergyScanStatus = ENERGY_SCAN_STATUS_IDLE; + +#if SL_RAIL_UTIL_IEEE802154_FAST_CHANNEL_SWITCHING_ENABLED && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + sChannelSwitchingCfg.bufferBytes = RAIL_IEEE802154_RX_CHANNEL_SWITCHING_BUF_BYTES; + sChannelSwitchingCfg.buffer = sChannelSwitchingBuffer; + for (uint8_t i = 0U; i < RAIL_IEEE802154_RX_CHANNEL_SWITCHING_NUM_CHANNELS; i++) { + sChannelSwitchingCfg.channels[i] = UNINITIALIZED_CHANNEL; + } +#endif + + // Initialize the queue for received packets. + queueStatus = queueInit(&sRxPacketQueue, SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT); + OT_ASSERT(queueStatus); + + // Specify a callback to be called upon queue overflow. + queueStatus = queueOverflow(&sRxPacketQueue, &rxPacketQueueOverflowCallback); + OT_ASSERT(queueStatus); + + // Initialize the memory pool for rx packets. + rxMemPoolStatus = + sl_memory_create_pool(sizeof(rxBuffer), SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT, &sRxPacketMemPoolHandle); + OT_ASSERT(rxMemPoolStatus == SL_STATUS_OK); + + otLogInfoPlat("Initialized"); +} + +void efr32RadioDeinit(void) +{ + RAIL_Status_t status; + + RAIL_Idle(gRailHandle, RAIL_IDLE_ABORT, true); + status = RAIL_ConfigEvents(gRailHandle, RAIL_EVENTS_ALL, 0); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + + sCurrentBandConfig = NULL; + + sl_memory_delete_pool(&sRxPacketMemPoolHandle); +} + +//------------------------------------------------------------------------------ +// Energy Scan support + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static void energyScanComplete(int8_t scanResultDbm) +{ + sEnergyScanResultDbm = scanResultDbm; + sEnergyScanStatus = ENERGY_SCAN_STATUS_COMPLETED; +} + +static otError efr32StartEnergyScan(energyScanMode aMode, uint16_t aChannel, RAIL_Time_t aAveragingTimeUs) +{ + RAIL_Status_t status = RAIL_STATUS_NO_ERROR; + otError error = OT_ERROR_NONE; + efr32BandConfig *config = NULL; + + otEXPECT_ACTION(sEnergyScanStatus == ENERGY_SCAN_STATUS_IDLE, error = OT_ERROR_BUSY); + + sEnergyScanStatus = ENERGY_SCAN_STATUS_IN_PROGRESS; + sEnergyScanMode = aMode; + + RAIL_Idle(gRailHandle, RAIL_IDLE, true); + + config = efr32RadioGetBandConfig(aChannel); + otEXPECT_ACTION(config != NULL, error = OT_ERROR_INVALID_ARGS); + + if (sCurrentBandConfig != config) { + efr32RailConfigLoad(config, SL_INVALID_TX_POWER); + sCurrentBandConfig = config; + } + + RAIL_SchedulerInfo_t scanSchedulerInfo = { .priority = RADIO_SCHEDULER_CHANNEL_SCAN_PRIORITY, + .slipTime = RADIO_SCHEDULER_CHANNEL_SLIP_TIME, + .transactionTime = aAveragingTimeUs }; + + status = RAIL_StartAverageRssi(gRailHandle, aChannel, aAveragingTimeUs, &scanSchedulerInfo); + otEXPECT_ACTION(status == RAIL_STATUS_NO_ERROR, error = OT_ERROR_FAILED); + +exit: + if (status != RAIL_STATUS_NO_ERROR) { + energyScanComplete(OT_RADIO_RSSI_INVALID); + } + return error; +} + +//------------------------------------------------------------------------------ +// Stack support + +uint64_t otPlatRadioGetNow(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + + return otPlatTimeGet(); +} + +void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64) +{ + OT_UNUSED_VARIABLE(aInstance); + +#if RADIO_CONFIG_ENABLE_CUSTOM_EUI_SUPPORT + // Invalid EUI + uint8_t nullEui[] = { 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }; + + // Read the Custom EUI and compare it to nullEui + if ((readUserData(aIeeeEui64, USERDATA_MFG_CUSTOM_EUI_64, OT_EXT_ADDRESS_SIZE, true) == -1) + || (memcmp(aIeeeEui64, nullEui, OT_EXT_ADDRESS_SIZE) == 0)) +#endif + { + uint64_t eui64; + uint8_t *eui64Ptr = NULL; + + eui64 = SYSTEM_GetUnique(); + eui64Ptr = (uint8_t *)&eui64; + + for (uint8_t i = 0; i < OT_EXT_ADDRESS_SIZE; i++) { + aIeeeEui64[i] = eui64Ptr[(OT_EXT_ADDRESS_SIZE - 1) - i]; + } + } +} + +void otPlatRadioSetPanId(otInstance *aInstance, uint16_t aPanId) +{ + RAIL_Status_t status; + uint8_t iid = efr32GetIidFromInstance(aInstance); + uint8_t panIndex = efr32GetPanIndexFromIid(iid); + + otEXPECT(sl_ot_rtos_task_can_access_pal()); + OT_ASSERT(panIndex != INVALID_INTERFACE_INDEX); + otLogInfoPlat("PANID=%X index=%u IID=%d", aPanId, panIndex, iid); + utilsSoftSrcMatchSetPanId(iid, aPanId); + + status = RAIL_IEEE802154_SetPanId(gRailHandle, aPanId, panIndex); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + // We already have IID 0 enabled in filtermask to track BCAST Packets, so + // track only unique PanIds. + if (aPanId != RADIO_BCAST_PANID) { + sRailFilterMask |= RADIO_GET_FILTER_MASK(iid); + } +#endif +exit: + return; +} + +void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aAddress) +{ + RAIL_Status_t status; + uint8_t iid = efr32GetIidFromInstance(aInstance); + uint8_t panIndex = efr32GetPanIndexFromIid(iid); + + otEXPECT(sl_ot_rtos_task_can_access_pal()); + OT_ASSERT(panIndex != INVALID_INTERFACE_INDEX); + + for (size_t i = 0; i < sizeof(*aAddress); i++) { + sExtAddress[panIndex].m8[i] = aAddress->m8[sizeof(*aAddress) - 1 - i]; + } + + otLogInfoPlat("ExtAddr=%X%X%X%X%X%X%X%X index=%u", + aAddress->m8[7], + aAddress->m8[6], + aAddress->m8[5], + aAddress->m8[4], + aAddress->m8[3], + aAddress->m8[2], + aAddress->m8[1], + aAddress->m8[0], + panIndex); + + status = RAIL_IEEE802154_SetLongAddress(gRailHandle, (uint8_t *)aAddress->m8, panIndex); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + +exit: + return; +} + +void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aAddress) +{ + RAIL_Status_t status; + uint8_t iid = efr32GetIidFromInstance(aInstance); + uint8_t panIndex = efr32GetPanIndexFromIid(iid); + + otEXPECT(sl_ot_rtos_task_can_access_pal()); + OT_ASSERT(panIndex != INVALID_INTERFACE_INDEX); + otLogInfoPlat("ShortAddr=%X index=%u", aAddress, panIndex); + + status = RAIL_IEEE802154_SetShortAddress(gRailHandle, aAddress, panIndex); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + +exit: + return; +} + +otRadioState otPlatRadioGetState(otInstance *aInstance) +{ + otRadioState radioState = OT_RADIO_STATE_INVALID; + + OT_UNUSED_VARIABLE(aInstance); + + switch (RAIL_GetRadioState(gRailHandle)) { + case RAIL_RF_STATE_RX_ACTIVE: + radioState = OT_RADIO_STATE_RECEIVE; + break; + + case RAIL_RF_STATE_TX_ACTIVE: + radioState = OT_RADIO_STATE_TRANSMIT; + break; + + case RAIL_RF_STATE_IDLE: + radioState = OT_RADIO_STATE_SLEEP; + break; + + case RAIL_RF_STATE_INACTIVE: + radioState = OT_RADIO_STATE_DISABLED; + break; + } + + return radioState; +} + +bool otPlatRadioIsEnabled(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + + return (getInternalFlag(FLAG_RADIO_INIT_DONE)); +} + +otError otPlatRadioEnable(otInstance *aInstance) +{ + otError error = OT_ERROR_NONE; + + otEXPECT(!otPlatRadioIsEnabled(aInstance)); + + otLogInfoPlat("State=OT_RADIO_STATE_SLEEP"); + +exit: + return error; +} + +otError otPlatRadioDisable(otInstance *aInstance) +{ + otError error = OT_ERROR_NONE; + + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), error = OT_ERROR_REJECTED); + otEXPECT_ACTION(otPlatRadioIsEnabled(aInstance), error = OT_ERROR_INVALID_STATE); + + otLogInfoPlat("State=OT_RADIO_STATE_DISABLED"); + +exit: + return error; +} + +otError otPlatRadioSleep(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + otError error = OT_ERROR_NONE; + + otEXPECT_ACTION(!getInternalFlag(ONGOING_TX_FLAGS), error = OT_ERROR_BUSY); + + otLogInfoPlat("State=OT_RADIO_STATE_SLEEP"); + setInternalFlag(FLAG_SCHEDULED_RX_PENDING, false); + radioSetIdle(); + +exit: + return error; +} + +otError efr32RadioLoadChannelConfig(uint8_t aChannel, int8_t aTxPower) +{ + otError error = OT_ERROR_NONE; + efr32BandConfig *config; + + config = efr32RadioGetBandConfig(aChannel); + otEXPECT_ACTION(config != NULL, error = OT_ERROR_INVALID_ARGS); + + if (sCurrentBandConfig != config) { + RAIL_Idle(gRailHandle, RAIL_IDLE, true); + efr32RailConfigLoad(config, aTxPower); + sCurrentBandConfig = config; + } else { + sli_set_tx_power_in_rail(aTxPower); + } + +exit: + return error; +} + +otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel) +{ + otError error = OT_ERROR_NONE; + RAIL_Status_t status; + int8_t txPower; + uint8_t iid = efr32GetIidFromInstance(aInstance); + + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), error = OT_ERROR_REJECTED); + otEXPECT_ACTION(!getInternalFlag(FLAG_ONGOING_TX_DATA) && sEnergyScanStatus != ENERGY_SCAN_STATUS_IN_PROGRESS, + error = OT_ERROR_INVALID_STATE); + + OT_UNUSED_VARIABLE(iid); +#if SL_RAIL_UTIL_IEEE802154_FAST_CHANNEL_SWITCHING_ENABLED && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + uint8_t index = efr32GetPanIndexFromIid(iid); + OT_ASSERT(index < RAIL_IEEE802154_RX_CHANNEL_SWITCHING_NUM_CHANNELS); + sChannelSwitchingCfg.channels[index] = aChannel; +#endif + + txPower = sl_get_tx_power_for_current_channel(aInstance); + error = efr32RadioLoadChannelConfig(aChannel, txPower); + otEXPECT(error == OT_ERROR_NONE); + + status = radioSetRx(aChannel); + otEXPECT_ACTION(status == RAIL_STATUS_NO_ERROR, error = OT_ERROR_FAILED); + setInternalFlag(FLAG_SCHEDULED_RX_PENDING, false); + + sReceive.frame.mChannel = aChannel; + sReceiveAck.frame.mChannel = aChannel; + +exit: + return error; +} + +#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) +otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, uint32_t aStart, uint32_t aDuration) +{ + otError error = OT_ERROR_NONE; + RAIL_Status_t status; + int8_t txPower = sl_get_tx_power_for_current_channel(aInstance); + + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), error = OT_ERROR_REJECTED); + OT_UNUSED_VARIABLE(aInstance); + + error = efr32RadioLoadChannelConfig(aChannel, txPower); + otEXPECT(error == OT_ERROR_NONE); + + status = radioScheduleRx(aChannel, aStart, aDuration); + otEXPECT_ACTION(status == RAIL_STATUS_NO_ERROR, error = OT_ERROR_FAILED); + setInternalFlag(FLAG_SCHEDULED_RX_PENDING, true); + + sReceive.frame.mChannel = aChannel; + sReceiveAck.frame.mChannel = aChannel; + +exit: + return error; +} +#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE +inline static void pushPendingCommand(pendingCommandType aCmdType, uint8_t aIid, void *aCmdParams) +{ + pendingCommandEntry *pendingCommand = (pendingCommandEntry *)sl_malloc(sizeof(pendingCommandEntry)); + OT_ASSERT(pendingCommand != NULL); + + pendingCommand->cmdType = aCmdType; + pendingCommand->iid = aIid; + + if (aCmdType == kPendingCommandTypeTransmit) { + otRadioFrame *txFrame = (otRadioFrame *)aCmdParams; + pendingCommand->request.txFrame = txFrame; + } else if (aCmdType == kPendingCommandTypeEnergyScan) { + energyScanParams *energyScanReq = (energyScanParams *)aCmdParams; + pendingCommand->request.energyScan.scanChannel = energyScanReq->scanChannel; + pendingCommand->request.energyScan.scanDuration = energyScanReq->scanDuration; + } + + if (!queueAdd(&sPendingCommandQueue, (void *)pendingCommand)) { + sl_free(pendingCommand); + } +} +#endif + +otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) +{ + otError error = OT_ERROR_NONE; + int8_t txPower = sl_get_tx_power_for_current_channel(aInstance); + uint8_t iid = efr32GetIidFromInstance(aInstance); + + // sTransmitBuffer's index 0 corresponds to host 1 i.e. iid 1 and reason is, + // iid zero is reserved for broadcast frames in multipan case. + uint8_t txBufIndex = iid ? (iid - 1) : 0; + + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), error = OT_ERROR_REJECTED); + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + // Accept GP packets even if radio is not in required state. + if ((sl_gp_intf_get_state() != SL_GP_STATE_SEND_RESPONSE) && sl_gp_intf_should_buffer_pkt(aInstance, aFrame, false)) { + sl_gp_intf_buffer_pkt(aInstance); + } else +#endif + { + OT_ASSERT(txBufIndex < RADIO_REQUEST_BUFFER_COUNT); + OT_ASSERT(aFrame == &sTransmitBuffer[txBufIndex].frame); + OT_ASSERT(aFrame->mPsdu == sTransmitPsdu[txBufIndex]); + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + OT_ASSERT((iid != RADIO_BCAST_IID) && (iid < RADIO_INTERFACE_COUNT)); + // Push pending transmit and exit if radio is busy. + if (isRadioTransmittingOrScanning()) { + pushPendingCommand(kPendingCommandTypeTransmit, iid, aFrame); + ExitNow(error = OT_ERROR_NONE); + } +#endif + error = efr32RadioLoadChannelConfig(aFrame->mChannel, txPower); + otEXPECT(error == OT_ERROR_NONE); + + OT_ASSERT(!getInternalFlag(FLAG_ONGOING_TX_DATA)); + + setInternalFlag(RADIO_TX_EVENTS, false); + sTransmitBuffer[txBufIndex].iid = iid; + sCurrentTxPacket = &sTransmitBuffer[txBufIndex]; + + setInternalFlag(FLAG_CURRENT_TX_USE_CSMA, aFrame->mInfo.mTxInfo.mCsmaCaEnabled); + +#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 +#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE + if (sCslPeriod > 0 && sCurrentTxPacket->frame.mInfo.mTxInfo.mTxDelay == 0) { + // Only called for CSL children (sCslPeriod > 0) + // Note: Our SSEDs "schedule" transmissions to their parent in order to know + // exactly when in the future the data packets go out so they can calculate + // the accurate CSL phase to send to their parent. + sCurrentTxPacket->frame.mInfo.mTxInfo.mTxDelayBaseTime = RAIL_GetTime(); + sCurrentTxPacket->frame.mInfo.mTxInfo.mTxDelay = 3000; // Chosen after internal certification testing + } +#endif + updateIeInfoTxFrame(sCurrentTxPacket->frame.mInfo.mTxInfo.mTxDelayBaseTime + + sCurrentTxPacket->frame.mInfo.mTxInfo.mTxDelay + SHR_DURATION_US); + // Note - we need to call this outside of txCurrentPacket as for Series 2, + // this results in calling the SE interface from a critical section which is not permitted. + radioProcessTransmitSecurity(&sCurrentTxPacket->frame, sCurrentTxPacket->iid); +#endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 + + CORE_DECLARE_IRQ_STATE; + CORE_ENTER_ATOMIC(); + setInternalFlag(FLAG_SCHEDULED_RX_PENDING, false); + setInternalFlag(FLAG_ONGOING_TX_DATA, true); + tryTxCurrentPacket(); + CORE_EXIT_ATOMIC(); + + if (getInternalFlag(EVENT_TX_FAILED)) { + otPlatRadioTxStarted(aInstance, aFrame); + } + } +exit: + return error; +} + +#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +void updateIeInfoTxFrame(uint32_t shrTxTime) +{ + OT_ASSERT(sCurrentTxPacket != NULL); + +#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_TIME_SYNC_ENABLE + // Seek the time sync offset and update the rendezvous time + if (sCurrentTxPacket->frame.mInfo.mTxInfo.mIeInfo->mTimeIeOffset != 0) { + uint8_t *timeIe = sCurrentTxPacket->frame.mPsdu + sCurrentTxPacket->frame.mInfo.mTxInfo.mIeInfo->mTimeIeOffset; + uint64_t time = otPlatTimeGet() + sCurrentTxPacket->frame.mInfo.mTxInfo.mIeInfo->mNetworkTimeOffset; + + *timeIe = sCurrentTxPacket->frame.mInfo.mTxInfo.mIeInfo->mTimeSyncSeq; + + *(++timeIe) = (uint8_t)(time & 0xff); + for (uint8_t i = 1; i < sizeof(uint64_t); i++) { + time = time >> 8; + *(++timeIe) = (uint8_t)(time & 0xff); + } + } +#endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_TIME_SYNC_ENABLE + +#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE + // Update IE data in the 802.15.4 header with the newest CSL period / phase + if (sCslPeriod > 0 && !sCurrentTxPacket->frame.mInfo.mTxInfo.mIsHeaderUpdated) { + otMacFrameSetCslIe(&sCurrentTxPacket->frame, (uint16_t)sCslPeriod, getCslPhase(shrTxTime)); + } +#else + OT_UNUSED_VARIABLE(shrTxTime); +#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE +} +#endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 + +void txCurrentPacket(void) +{ + OT_ASSERT(getInternalFlag(FLAG_ONGOING_TX_DATA)); + OT_ASSERT(sCurrentTxPacket != NULL); + + RAIL_TxOptions_t txOptions = RAIL_TX_OPTIONS_DEFAULT; + RAIL_Status_t status = RAIL_STATUS_INVALID_STATE; + uint8_t frameLength; + bool ackRequested; + +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + railDebugCounters.mRailPlatTxTriggered++; +#endif + // signalling this event earlier, as this event can OT_ASSERT REQ (expecially for a + // non-CSMA transmit) giving the Coex master a little more time to grant or deny. + if (getInternalFlag(FLAG_CURRENT_TX_USE_CSMA)) { + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_TX_PENDED_PHY, (uint32_t)true); + } else { + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_TX_PENDED_PHY, (uint32_t)false); + } + + frameLength = (uint8_t)sCurrentTxPacket->frame.mLength; + + if (PHY_HEADER_SIZE == 1) { + RAIL_WriteTxFifo(gRailHandle, &frameLength, sizeof frameLength, true); + } else { // 2 byte PHR for Sub-GHz + uint8_t PHRByte1 = (0x08U /*FCS=2byte*/ | 0x10U /*Whiten=enabled*/); + uint8_t PHRByte2 = (uint8_t)(__RBIT(frameLength) >> 24); + + RAIL_WriteTxFifo(gRailHandle, &PHRByte1, sizeof PHRByte1, true); + RAIL_WriteTxFifo(gRailHandle, &PHRByte2, sizeof PHRByte2, false); + } + RAIL_WriteTxFifo(gRailHandle, sCurrentTxPacket->frame.mPsdu, frameLength - 2, false); + + RAIL_SchedulerInfo_t txSchedulerInfo = { + .priority = RADIO_SCHEDULER_TX_PRIORITY, + .slipTime = RADIO_SCHEDULER_CHANNEL_SLIP_TIME, + .transactionTime = 0, // will be calculated later if DMP is used + }; + + ackRequested = (sCurrentTxPacket->frame.mPsdu[0] & IEEE802154_FRAME_FLAG_ACK_REQUIRED); + if (ackRequested) { + txOptions |= RAIL_TX_OPTION_WAIT_FOR_ACK; + +#if RADIO_CONFIG_DMP_SUPPORT + // time we wait for ACK + if (RAIL_GetSymbolRate(gRailHandle) > 0) { + txSchedulerInfo.transactionTime += 12 * 1e6 / RAIL_GetSymbolRate(gRailHandle); + } else { + txSchedulerInfo.transactionTime += 12 * RADIO_TIMING_DEFAULT_SYMBOLTIME_US; + } +#endif + } + +#ifdef SL_CATALOG_RAIL_UTIL_ANT_DIV_PRESENT + // Update Tx options to use currently-selected antenna. + // If antenna diverisity on Tx is disabled, leave both options 0 + // so Tx antenna tracks Rx antenna. + if (sl_rail_util_ant_div_get_tx_antenna_mode() != SL_RAIL_UTIL_ANT_DIV_DISABLED) { + txOptions |= ((sl_rail_util_ant_div_get_tx_antenna_selected() == SL_RAIL_UTIL_ANTENNA_SELECT_ANTENNA1) + ? RAIL_TX_OPTION_ANTENNA0 + : RAIL_TX_OPTION_ANTENNA1); + } +#endif // SL_CATALOG_RAIL_UTIL_ANT_DIV_PRESENT + +#if RADIO_CONFIG_DMP_SUPPORT + // time needed for the frame itself + // 4B preamble, 1B SFD, 1B PHR is not counted in frameLength + if (RAIL_GetBitRate(gRailHandle) > 0) { + txSchedulerInfo.transactionTime += (frameLength + 4 + 1 + 1) * 8 * 1e6 / RAIL_GetBitRate(gRailHandle); + } else { // assume 250kbps + txSchedulerInfo.transactionTime += (frameLength + 4 + 1 + 1) * RADIO_TIMING_DEFAULT_BYTETIME_US; + } +#endif + + if (sCurrentTxPacket->frame.mInfo.mTxInfo.mTxDelay == 0) { + if (getInternalFlag(FLAG_CURRENT_TX_USE_CSMA)) { +#if RADIO_CONFIG_DMP_SUPPORT + // time needed for CSMA/CA + txSchedulerInfo.transactionTime += RADIO_TIMING_CSMA_OVERHEAD_US; +#endif + csmaConfig.csmaTries = sCurrentTxPacket->frame.mInfo.mTxInfo.mMaxCsmaBackoffs; + csmaConfig.ccaThreshold = sCcaThresholdDbm; + + status = + RAIL_StartCcaCsmaTx(gRailHandle, sCurrentTxPacket->frame.mChannel, txOptions, &csmaConfig, &txSchedulerInfo); + } else { + status = RAIL_StartTx(gRailHandle, sCurrentTxPacket->frame.mChannel, txOptions, &txSchedulerInfo); + } + + if (status == RAIL_STATUS_NO_ERROR) { + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_TX_STARTED, 0U); + } + } else { + // For CSL transmitters (FTDs): + // mTxDelayBaseTime = rx-timestamp (end of sync word) when we received CSL-sync with IEs + // mTxDelay = Delay starting from mTxDelayBaseTime + // + // For CSL receivers (SSEDs): + // mTxDelayBaseTime = timestamp when otPlatRadioTransmit is called + // mTxDelay = Chosen value in the future where transmit is scheduled, so we know exactly + // when to calculate the phase (we can't do this on-the-fly as the packet is going out + // due to platform limitations. see radioScheduleRx) + // + // Note that both use single CCA config, overriding any CCA/CSMA configs from the stack + // +#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 + RAIL_ScheduleTxConfig_t scheduleTxOptions = { .when = sCurrentTxPacket->frame.mInfo.mTxInfo.mTxDelayBaseTime + + sCurrentTxPacket->frame.mInfo.mTxInfo.mTxDelay + - SHR_DURATION_US, + .mode = RAIL_TIME_ABSOLUTE, + .txDuringRx = RAIL_SCHEDULED_TX_DURING_RX_POSTPONE_TX }; + + // CSL transmissions don't use CSMA but MAC accounts for single CCA time. + // cslCsmaConfig is set to RAIL_CSMA_CONFIG_SINGLE_CCA above. + status = RAIL_StartScheduledCcaCsmaTx(gRailHandle, + sCurrentTxPacket->frame.mChannel, + txOptions, + &scheduleTxOptions, + &cslCsmaConfig, + &txSchedulerInfo); + + if (status == RAIL_STATUS_NO_ERROR) { +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + railDebugCounters.mRailEventsScheduledTxTriggeredCount++; +#endif + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_TX_STARTED, 0U); + } +#endif + } + if (status == RAIL_STATUS_NO_ERROR) { +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + railDebugCounters.mRailTxStarted++; +#endif + } else { +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + railDebugCounters.mRailTxStartFailed++; +#endif + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_TX_BLOCKED, (uint32_t)ackRequested); + txFailedCallback(false, EVENT_TX_FAILED); + + otSysEventSignalPending(); + } +} + +// This API gets called from init procedure so instance to IID mapping does not exist +// at that point. Also this api will get called sequentially so assign new transmit +// buffer if aInstance does not exist in sInstances. +otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + uint8_t index = 0; + otRadioFrame *aRadioFrame = NULL; + + otEXPECT(sl_ot_rtos_task_can_access_pal()); + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + for (index = 0; index < OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_NUM; index++) { + if (sInstances[index] == aInstance || sInstances[index] == NULL) { + break; + } + } +#endif // OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + + aRadioFrame = &sTransmitBuffer[index].frame; + +exit: + return aRadioFrame; +} + +int8_t otPlatRadioGetRssi(otInstance *aInstance) +{ + otError error; + uint32_t start; + int8_t rssi = OT_RADIO_RSSI_INVALID; + uint8_t aChannel = sReceive.frame.mChannel; + uint8_t iid = efr32GetIidFromInstance(aInstance); + + otEXPECT(sl_ot_rtos_task_can_access_pal()); + otEXPECT(!getInternalFlag(FLAG_ONGOING_TX_DATA)); + + OT_UNUSED_VARIABLE(iid); +#if SL_RAIL_UTIL_IEEE802154_FAST_CHANNEL_SWITCHING_ENABLED && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + uint8_t index = efr32GetPanIndexFromIid(iid); + OT_ASSERT(index < RAIL_IEEE802154_RX_CHANNEL_SWITCHING_NUM_CHANNELS); + if (sChannelSwitchingCfg.channels[index] != UNINITIALIZED_CHANNEL) { + aChannel = sChannelSwitchingCfg.channels[index]; + } +#endif + + error = efr32StartEnergyScan(ENERGY_SCAN_MODE_SYNC, aChannel, EFR32_RSSI_AVERAGING_TIME); + otEXPECT(error == OT_ERROR_NONE); + + start = RAIL_GetTime(); + + // waiting for the event RAIL_EVENT_RSSI_AVERAGE_DONE + while (sEnergyScanStatus == ENERGY_SCAN_STATUS_IN_PROGRESS + && ((RAIL_GetTime() - start) < EFR32_RSSI_AVERAGING_TIMEOUT)) + ; + + if (sEnergyScanStatus == ENERGY_SCAN_STATUS_COMPLETED) { + rssi = sEnergyScanResultDbm; + } + + sEnergyScanStatus = ENERGY_SCAN_STATUS_IDLE; +exit: + return rssi; +} + +otRadioCaps otPlatRadioGetCaps(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + + return sRadioCapabilities; +} + +bool otPlatRadioGetPromiscuous(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + + return sPromiscuous; +} + +void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable) +{ + OT_UNUSED_VARIABLE(aInstance); + + RAIL_Status_t status; + + otEXPECT(sl_ot_rtos_task_can_access_pal()); + sPromiscuous = aEnable; + + status = RAIL_IEEE802154_SetPromiscuousMode(gRailHandle, aEnable); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + +exit: + return; +} + +void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable) +{ + OT_UNUSED_VARIABLE(aInstance); + + otEXPECT(sl_ot_rtos_task_can_access_pal()); + // set Frame Pending bit for all outgoing ACKs if aEnable is false + sIsSrcMatchEnabled = aEnable; + +exit: + return; +} + +otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower) +{ + OT_UNUSED_VARIABLE(aInstance); + + otError error = OT_ERROR_NONE; + + otEXPECT_ACTION(aPower != NULL, error = OT_ERROR_INVALID_ARGS); + // RAIL_GetTxPowerDbm() returns power in deci-dBm (0.1dBm) + // Divide by 10 because aPower is supposed be in units dBm + *aPower = RAIL_GetTxPowerDbm(gRailHandle) / 10; + +exit: + return error; +} + +otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower) +{ + return sli_set_default_tx_power(aInstance, aPower); +} + +// Required for RCP error recovery +// See src/lib/spinel/radio_spinel.cpp::RestoreProperties() +otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aChannel, int8_t aMaxPower) +{ + return sli_set_channel_max_tx_power(aInstance, aChannel, aMaxPower); +} + +otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t *aThreshold) +{ + OT_UNUSED_VARIABLE(aInstance); + + otError error = OT_ERROR_NONE; + otEXPECT_ACTION(aThreshold != NULL, error = OT_ERROR_INVALID_ARGS); + + *aThreshold = sCcaThresholdDbm; + +exit: + return error; +} + +otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aThreshold) +{ + OT_UNUSED_VARIABLE(aInstance); + + otError error = OT_ERROR_NONE; + + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), error = OT_ERROR_REJECTED); + sCcaThresholdDbm = aThreshold; + +exit: + return error; +} + +int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + + return EFR32_RECEIVE_SENSITIVITY; +} + +otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration) +{ + otError error = OT_ERROR_NONE; + uint8_t iid = efr32GetIidFromInstance(aInstance); + + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), error = OT_ERROR_REJECTED); +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + OT_ASSERT((iid != RADIO_BCAST_IID) && (iid < RADIO_INTERFACE_COUNT)); + + // Push pending energy-scan and exit if radio is busy. + if (isRadioTransmittingOrScanning()) { + energyScanParams params = { aScanChannel, aScanDuration }; + pushPendingCommand(kPendingCommandTypeEnergyScan, iid, ¶ms); + ExitNow(error = OT_ERROR_NONE); + } +#endif + + sEnergyScanActiveInterface = iid; + error = efr32StartEnergyScan(ENERGY_SCAN_MODE_ASYNC, aScanChannel, (RAIL_Time_t)aScanDuration * US_IN_MS); + +exit: + return error; +} + +//------------------------------------------------------------------------------ +// Radio Config: Thread 1.2 transmit security support + +#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) +void otPlatRadioSetMacKey(otInstance *aInstance, + uint8_t aKeyIdMode, + uint8_t aKeyId, + const otMacKeyMaterial *aPrevKey, + const otMacKeyMaterial *aCurrKey, + const otMacKeyMaterial *aNextKey, + otRadioKeyType aKeyType) +{ + OT_UNUSED_VARIABLE(aKeyIdMode); + OT_UNUSED_VARIABLE(aKeyType); + + uint8_t iid = efr32GetIidFromInstance(aInstance); + + otEXPECT(sl_ot_rtos_task_can_access_pal()); + OT_ASSERT(aPrevKey != NULL && aCurrKey != NULL && aNextKey != NULL); + + sMacKeys[iid].keyId = aKeyId; + memcpy(&sMacKeys[iid].keys[MAC_KEY_PREV], aPrevKey, sizeof(otMacKeyMaterial)); + memcpy(&sMacKeys[iid].keys[MAC_KEY_CURRENT], aCurrKey, sizeof(otMacKeyMaterial)); + memcpy(&sMacKeys[iid].keys[MAC_KEY_NEXT], aNextKey, sizeof(otMacKeyMaterial)); + +#if defined(_SILICON_LABS_32B_SERIES_2) && (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) + size_t aKeyLen = 0; + otError error = OT_ERROR_NONE; + + error = otPlatCryptoExportKey(sMacKeys[iid].keys[MAC_KEY_PREV].mKeyMaterial.mKeyRef, + sMacKeys[iid].keys[MAC_KEY_PREV].mKeyMaterial.mKey.m8, + sizeof(sMacKeys[iid].keys[MAC_KEY_PREV]), + &aKeyLen); + OT_ASSERT(error == OT_ERROR_NONE); + + error = otPlatCryptoExportKey(sMacKeys[iid].keys[MAC_KEY_CURRENT].mKeyMaterial.mKeyRef, + sMacKeys[iid].keys[MAC_KEY_CURRENT].mKeyMaterial.mKey.m8, + sizeof(sMacKeys[iid].keys[MAC_KEY_CURRENT]), + &aKeyLen); + OT_ASSERT(error == OT_ERROR_NONE); + + error = otPlatCryptoExportKey(sMacKeys[iid].keys[MAC_KEY_NEXT].mKeyMaterial.mKeyRef, + sMacKeys[iid].keys[MAC_KEY_NEXT].mKeyMaterial.mKey.m8, + sizeof(sMacKeys[iid].keys[MAC_KEY_NEXT]), + &aKeyLen); + OT_ASSERT(error == OT_ERROR_NONE); +#endif + +exit: + return; +} + +void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCounter) +{ + uint8_t iid = efr32GetIidFromInstance(aInstance); + + otEXPECT(sl_ot_rtos_task_can_access_pal()); + + CORE_DECLARE_IRQ_STATE; + CORE_ENTER_ATOMIC(); + + sMacKeys[iid].macFrameCounter = aMacFrameCounter; + + CORE_EXIT_ATOMIC(); + +exit: + return; +} + +void otPlatRadioSetMacFrameCounterIfLarger(otInstance *aInstance, uint32_t aMacFrameCounter) +{ + uint8_t iid = efr32GetIidFromInstance(aInstance); + + otEXPECT(sl_ot_rtos_task_can_access_pal()); + + CORE_DECLARE_IRQ_STATE; + CORE_ENTER_ATOMIC(); + + if (aMacFrameCounter > sMacKeys[iid].macFrameCounter) { + sMacKeys[iid].macFrameCounter = aMacFrameCounter; + } + + CORE_EXIT_ATOMIC(); + +exit: + return; +} + +//------------------------------------------------------------------------------ +// Radio Config: Enhanced Acks, CSL + +#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE +otError otPlatRadioEnableCsl(otInstance *aInstance, + uint32_t aCslPeriod, + otShortAddress aShortAddr, + const otExtAddress *aExtAddr) +{ + otError error = OT_ERROR_NONE; + + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aShortAddr); + OT_UNUSED_VARIABLE(aExtAddr); + + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), error = OT_ERROR_REJECTED); + + sCslPeriod = aCslPeriod; + +exit: + return error; +} + +void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTime) +{ + OT_UNUSED_VARIABLE(aInstance); + + otEXPECT(sl_ot_rtos_task_can_access_pal()); + sCslSampleTime = aCslSampleTime; +exit: + return; +} + +#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE + +uint8_t otPlatRadioGetCslAccuracy(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + + return otPlatTimeGetXtalAccuracy(); +} + +uint8_t otPlatRadioGetCslUncertainty(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + + return SL_OPENTHREAD_CSL_TX_UNCERTAINTY; +} + +//------------------------------------------------------------------------------ +// Radio Config: Link Metrics + +#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE +otError otPlatRadioConfigureEnhAckProbing(otInstance *aInstance, + otLinkMetrics aLinkMetrics, + const otShortAddress aShortAddress, + const otExtAddress *aExtAddress) +{ + otError error; + + OT_UNUSED_VARIABLE(aInstance); + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), error = OT_ERROR_REJECTED); + + error = otLinkMetricsConfigureEnhAckProbing(aShortAddress, aExtAddress, aLinkMetrics); + +exit: + return error; +} +#endif +#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) + +#if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE +otError otPlatRadioSetCoexEnabled(otInstance *aInstance, bool aEnabled) +{ + otError error; + + OT_UNUSED_VARIABLE(aInstance); + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), error = OT_ERROR_REJECTED); + + sl_status_t status = sl_rail_util_coex_set_enable(aEnabled); + if (aEnabled && !sl_rail_util_coex_is_enabled()) { + otLogInfoPlat("Coexistence GPIO configurations not set"); + return OT_ERROR_FAILED; + } + sRadioCoexEnabled = aEnabled; + + error = (status != SL_STATUS_OK) ? OT_ERROR_FAILED : OT_ERROR_NONE; + +exit: + return error; +} + +bool otPlatRadioIsCoexEnabled(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return (sRadioCoexEnabled && sl_rail_util_coex_is_enabled()); +} + +#endif // OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE + +#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) +//------------------------------------------------------------------------------ +// Radio implementation: Enhanced ACKs, CSL + +// Return false if we should generate an immediate ACK +// Return true otherwise +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static bool writeIeee802154EnhancedAck(RAIL_Handle_t aRailHandle, + RAIL_RxPacketInfo_t *packetInfoForEnhAck, + uint8_t *initialPktReadBytes, + uint8_t *receivedPsdu) +{ + // RAIL will generate an Immediate ACK for us. + // For an Enhanced ACK, we need to generate the whole packet ourselves. + + // An 802.15.4 packet from RAIL should look like: + // 1/2 | 1/2 | 0/1 | 0/2 | 0/2/8 | 0/2 | 0/2/8 | 14 + // PHR | MacFCF | Seq# | DstPan | DstAdr | SrcPan | SrcAdr | SecHdr + + // With RAIL_IEEE802154_EnableEarlyFramePending(), RAIL_EVENT_IEEE802154_DATA_REQUEST_COMMAND + // is triggered after receiving through the SrcAdr field of Version 0/1 packets, + // and after receiving through the SecHdr for Version 2 packets. + + otRadioFrame receivedFrame, enhAckFrame; + uint8_t enhAckPsdu[IEEE802154_MAX_LENGTH]; + +#define EARLY_FRAME_PENDING_EXPECTED_BYTES (2U + 2U + 1U + 2U + 8U + 2U + 8U + 14U) +#define FINAL_PACKET_LENGTH_WITH_IE (EARLY_FRAME_PENDING_EXPECTED_BYTES + OT_ACK_IE_MAX_SIZE) + + otEXPECT((packetInfoForEnhAck != NULL) && (initialPktReadBytes != NULL) && (receivedPsdu != NULL)); + + *initialPktReadBytes = readInitialPacketData(packetInfoForEnhAck, + EARLY_FRAME_PENDING_EXPECTED_BYTES, + (PHY_HEADER_SIZE + 2), + receivedPsdu, + FINAL_PACKET_LENGTH_WITH_IE); + + uint8_t iid = INVALID_INTERFACE_INDEX; + + if (*initialPktReadBytes == 0U) { + return true; // Nothing to read, which means generating an immediate ACK is also pointless + } + + receivedFrame.mPsdu = receivedPsdu + PHY_HEADER_SIZE; + receivedFrame.mLength = *initialPktReadBytes - PHY_HEADER_SIZE; + enhAckFrame.mPsdu = enhAckPsdu + PHY_HEADER_SIZE; + + if (!otMacFrameIsVersion2015(&receivedFrame)) { + return false; + } + + otMacAddress aSrcAddress; + uint8_t linkMetricsDataLen = 0; + uint8_t *dataPtr = NULL; + bool setFramePending = false; + + iid = getIidFromFilterMask(packetInfoForEnhAck->filterMask); + + otMacFrameGetSrcAddr(&receivedFrame, &aSrcAddress); + + if (sIsSrcMatchEnabled && (aSrcAddress.mType != OT_MAC_ADDRESS_TYPE_NONE)) { + setFramePending = (aSrcAddress.mType == OT_MAC_ADDRESS_TYPE_EXTENDED + ? (utilsSoftSrcMatchExtFindEntry(iid, &aSrcAddress.mAddress.mExtAddress) >= 0) + : (utilsSoftSrcMatchShortFindEntry(iid, aSrcAddress.mAddress.mShortAddress) >= 0)); + } + + // Generate our IE header. + // Write IE data for enhanced ACK (link metrics + allocate bytes for CSL) + +#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE + uint8_t linkMetricsData[OT_ENH_PROBING_IE_DATA_MAX_SIZE]; + + linkMetricsDataLen = otLinkMetricsEnhAckGenData(&aSrcAddress, sLastLqi, sLastRssi, linkMetricsData); + + if (linkMetricsDataLen > 0) { + dataPtr = linkMetricsData; + } +#endif + + sAckIeDataLength = generateAckIeData(dataPtr, linkMetricsDataLen); + + otEXPECT(otMacFrameGenerateEnhAck(&receivedFrame, setFramePending, sAckIeData, sAckIeDataLength, &enhAckFrame) + == OT_ERROR_NONE); + +#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE + if (sCslPeriod > 0) { + // Calculate time in the future where the SHR is done being sent out + uint32_t ackShrDoneTime = // Currently partially received packet's SHR time + (otPlatAlarmMicroGetNow() + - (packetInfoForEnhAck->packetBytes * OT_RADIO_SYMBOL_TIME * 2) + // PHR of this packet + + (PHY_HEADER_SIZE * OT_RADIO_SYMBOL_TIME * 2) + // Received frame's expected time in the PHR + + (receivedFrame.mLength * OT_RADIO_SYMBOL_TIME * 2) + // rxToTx turnaround time + + sRailIeee802154Config.timings.rxToTx + // PHR time of the ACK + + (PHY_HEADER_SIZE * OT_RADIO_SYMBOL_TIME * 2) + // SHR time of the ACK + + (SHR_SIZE * OT_RADIO_SYMBOL_TIME * 2)); + + // Update IE data in the 802.15.4 header with the newest CSL period / phase + otMacFrameSetCslIe(&enhAckFrame, (uint16_t)sCslPeriod, getCslPhase(ackShrDoneTime)); + } +#endif + + if (otMacFrameIsSecurityEnabled(&enhAckFrame)) { + otEXPECT(radioProcessTransmitSecurity(&enhAckFrame, iid) == OT_ERROR_NONE); + } + + // Before we're done, store some important info in reserved bits in the + // MAC header (cleared later) + // Check whether frame pending is set. + // Check whether enhanced ACK is secured. + otEXPECT((skipRxPacketLengthBytes(packetInfoForEnhAck)) == OT_ERROR_NONE); + uint8_t *macFcfPointer = ((packetInfoForEnhAck->firstPortionBytes == 0) + ? (uint8_t *)packetInfoForEnhAck->lastPortionData + : (uint8_t *)packetInfoForEnhAck->firstPortionData); + + if (otMacFrameIsSecurityEnabled(&enhAckFrame)) { + *macFcfPointer |= IEEE802154_SECURED_OUTGOING_ENHANCED_ACK; + } + + if (setFramePending) { + *macFcfPointer |= IEEE802154_FRAME_PENDING_SET_IN_OUTGOING_ACK; + } + + // Fill in PHR now that we know Enh-ACK's length + if (PHY_HEADER_SIZE == 2U) // Not true till SubGhz implementation is in place + { + enhAckPsdu[0] = (0x08U /*FCS=2byte*/ | 0x10U /*Whiten=enabled*/); + enhAckPsdu[1] = (uint8_t)(__RBIT(enhAckFrame.mLength) >> 24); + } else { + enhAckPsdu[0] = enhAckFrame.mLength; + } + + RAIL_Status_t enhAckStatus = RAIL_IEEE802154_WriteEnhAck(aRailHandle, enhAckPsdu, enhAckFrame.mLength); +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + otEXPECT_ACTION(enhAckStatus == RAIL_STATUS_NO_ERROR, railDebugCounters.mRailEventsEnhAckTxFailed++); +#else + otEXPECT(enhAckStatus == RAIL_STATUS_NO_ERROR); +#endif + +exit: + return true; +} +#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) + +//------------------------------------------------------------------------------ +// RAIL callbacks + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static void dataRequestCommandCallback(RAIL_Handle_t aRailHandle) +{ +#define MAX_EXPECTED_BYTES (2U + 2U + 1U) // PHR + FCF + DSN + + uint8_t receivedPsdu[IEEE802154_MAX_LENGTH]; + uint8_t pktOffset = PHY_HEADER_SIZE; + uint8_t initialPktReadBytes; + RAIL_RxPacketInfo_t packetInfo; + + // This callback occurs after the address fields of an incoming + // ACK-requesting CMD or DATA frame have been received and we + // can do a frame pending check. We must also figure out what + // kind of ACK is being requested -- Immediate or Enhanced. + +#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) + if (writeIeee802154EnhancedAck(aRailHandle, &packetInfo, &initialPktReadBytes, receivedPsdu)) { + // We also return true above if there were failures in + // generating an enhanced ACK. + return; + } +#else + initialPktReadBytes = + readInitialPacketData(&packetInfo, MAX_EXPECTED_BYTES, pktOffset + 2, receivedPsdu, MAX_EXPECTED_BYTES); +#endif + + // Calculate frame pending for immediate-ACK + // If not, RAIL will send an immediate ACK, but we need to do FP lookup. + RAIL_Status_t status = RAIL_STATUS_NO_ERROR; + + // Check if we read the FCF, if not, set macFcf to 0 + uint16_t macFcf = (initialPktReadBytes <= pktOffset) ? 0U : receivedPsdu[pktOffset]; + + bool framePendingSet = false; + + if (sIsSrcMatchEnabled) { + RAIL_IEEE802154_Address_t sourceAddress; + + status = RAIL_IEEE802154_GetAddress(aRailHandle, &sourceAddress); + otEXPECT(status == RAIL_STATUS_NO_ERROR); + + uint8_t iid = getIidFromFilterMask(packetInfo.filterMask); + if ((sourceAddress.length == RAIL_IEEE802154_LongAddress + && utilsSoftSrcMatchExtFindEntry(iid, (otExtAddress *)sourceAddress.longAddress) >= 0) + || (sourceAddress.length == RAIL_IEEE802154_ShortAddress + && utilsSoftSrcMatchShortFindEntry(iid, sourceAddress.shortAddress) >= 0)) { + status = RAIL_IEEE802154_SetFramePending(aRailHandle); + otEXPECT(status == RAIL_STATUS_NO_ERROR); + framePendingSet = true; + } + } else if ((macFcf & IEEE802154_FRAME_TYPE_MASK) != IEEE802154_FRAME_TYPE_DATA) { + status = RAIL_IEEE802154_SetFramePending(aRailHandle); + otEXPECT(status == RAIL_STATUS_NO_ERROR); + framePendingSet = true; + } + + if (framePendingSet) { + // Store whether frame pending was set in the outgoing ACK in a reserved + // bit of the MAC header (cleared later) + + otEXPECT((skipRxPacketLengthBytes(&packetInfo)) == OT_ERROR_NONE); + uint8_t *macFcfPointer = ((packetInfo.firstPortionBytes == 0) ? (uint8_t *)packetInfo.lastPortionData + : (uint8_t *)packetInfo.firstPortionData); + *macFcfPointer |= IEEE802154_FRAME_PENDING_SET_IN_OUTGOING_ACK; + } + +exit: + if (status == RAIL_STATUS_INVALID_STATE) { + otLogWarnPlat("Too late to modify outgoing FP"); + } else { + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + } +} + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static void packetReceivedCallback(void) +{ + RAIL_RxPacketInfo_t packetInfo; + RAIL_RxPacketDetails_t packetDetails; + uint16_t length = 0; + bool framePendingInAck = false; + bool dropPacket = false; + uint8_t iid = 0; + sl_status_t status; + bool isRxPacketQueued; + rxBuffer *rxPacketBuf = NULL; + + RAIL_RxPacketHandle_t packetHandle = RAIL_GetRxPacketInfo(gRailHandle, RAIL_RX_PACKET_HANDLE_NEWEST, &packetInfo); + otEXPECT_ACTION( + (packetHandle != RAIL_RX_PACKET_HANDLE_INVALID && packetInfo.packetStatus == RAIL_RX_PACKET_READY_SUCCESS), + dropPacket = true); + + otEXPECT_ACTION(validatePacketDetails(packetHandle, &packetDetails, &packetInfo, &length), dropPacket = true); + + otEXPECT_ACTION((skipRxPacketLengthBytes(&packetInfo)) == OT_ERROR_NONE, dropPacket = true); + + uint8_t macFcf = + ((packetInfo.firstPortionBytes == 0) ? packetInfo.lastPortionData[0] : packetInfo.firstPortionData[0]); + + iid = getIidFromFilterMask(packetInfo.filterMask); + + if (packetDetails.isAck) { + otEXPECT_ACTION( + (length >= IEEE802154_MIN_LENGTH && (macFcf & IEEE802154_FRAME_TYPE_MASK) == IEEE802154_FRAME_TYPE_ACK), + dropPacket = true); + + // read packet + RAIL_CopyRxPacket(sReceiveAck.frame.mPsdu, &packetInfo); + +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + railDebugCounters.mRailEventAcksReceived++; +#endif + sReceiveAck.frame.mLength = length; + + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_RX_ENDED, (uint32_t)isReceivingFrame()); + + if (txWaitingForAck() + && (sReceiveAck.frame.mPsdu[IEEE802154_DSN_OFFSET] == sCurrentTxPacket->frame.mPsdu[IEEE802154_DSN_OFFSET])) { + otEXPECT_ACTION(validatePacketTimestamp(&packetDetails, length), dropPacket = true); + + sReceiveAck.frame.mInfo.mRxInfo.mRssi = packetDetails.rssi; + sReceiveAck.frame.mInfo.mRxInfo.mLqi = packetDetails.lqi; + sReceiveAck.iid = iid; + updateRxFrameTimestamp(true, packetDetails.timeReceived.packetTime); + + // Processing the ACK frame in ISR context avoids the Tx state to be messed up, + // in case the Rx FIFO queue gets wiped out in a DMP situation. + setInternalFlag(EVENT_TX_SUCCESS, true); + setInternalFlag(FLAG_WAITING_FOR_ACK | FLAG_ONGOING_TX_DATA, false); + + framePendingInAck = ((macFcf & IEEE802154_FRAME_FLAG_FRAME_PENDING) != 0); + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_TX_ACK_RECEIVED, (uint32_t)framePendingInAck); + + if (txIsDataRequest() && framePendingInAck) { + emPendingData = true; + } + } + // Yield the radio upon receiving an ACK as long as it is not related to + // a data request. + if (!txIsDataRequest()) { + RAIL_YieldRadio(gRailHandle); + } + } else { + otEXPECT_ACTION(sPromiscuous || (length >= IEEE802154_MIN_DATA_LENGTH), dropPacket = true); + + otEXPECT_ACTION(validatePacketTimestamp(&packetDetails, length), dropPacket = true); + + // Drop the packet if queue is full. + otEXPECT_ACTION(!queueIsFull(&sRxPacketQueue), dropPacket = true); + // Allocate a block from memory pool for the received packet. + status = sl_memory_pool_alloc(&sRxPacketMemPoolHandle, (void **)&rxPacketBuf); + // Drop the packet if no more memory block present in the pool to store it. + otEXPECT_ACTION(status == SL_STATUS_OK && rxPacketBuf != NULL, dropPacket = true); + + // read packet + RAIL_CopyRxPacket(rxPacketBuf->psdu, &packetInfo); + + rxPacketBuf->packetInfo.length = (uint8_t)length; + rxPacketBuf->packetInfo.channel = (uint8_t)packetDetails.channel; + rxPacketBuf->packetInfo.rssi = packetDetails.rssi; + rxPacketBuf->packetInfo.lqi = packetDetails.lqi; + rxPacketBuf->packetInfo.timestamp = packetDetails.timeReceived.packetTime; + rxPacketBuf->packetInfo.iid = iid; + + // Queue the rx packet or drop it if queueing fails and free the memory block. + isRxPacketQueued = queueAdd(&sRxPacketQueue, (void *)rxPacketBuf); + otEXPECT_ACTION(isRxPacketQueued, dropPacket = true); + +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + railDebugCounters.mRailPlatRadioReceiveProcessedCount++; +#endif + + if (macFcf & IEEE802154_FRAME_FLAG_ACK_REQUIRED) { + (void)handlePhyStackEvent( + (RAIL_IsRxAutoAckPaused(gRailHandle) ? SL_RAIL_UTIL_IEEE802154_STACK_EVENT_RX_ACK_BLOCKED + : SL_RAIL_UTIL_IEEE802154_STACK_EVENT_RX_ACKING), + (uint32_t)isReceivingFrame()); + setInternalFlag(FLAG_ONGOING_TX_ACK, true); + } else { + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_RX_ENDED, (uint32_t)isReceivingFrame()); + // We received a frame that does not require an ACK as result of a data + // poll: we yield the radio here. + if (emPendingData) { + RAIL_YieldRadio(gRailHandle); + emPendingData = false; + } + } + } +exit: + if (dropPacket) { + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_RX_CORRUPTED, (uint32_t)isReceivingFrame()); + + IgnoreError(sl_memory_pool_free(&sRxPacketMemPoolHandle, rxPacketBuf)); + } +} + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static void packetSentCallback(bool isAck) +{ + if (isAck) { + // We successfully sent out an ACK. + setInternalFlag(FLAG_ONGOING_TX_ACK, false); + // We acked the packet we received after a poll: we can yield now. + if (emPendingData) { + RAIL_YieldRadio(gRailHandle); + emPendingData = false; + } + } else if (getInternalFlag(FLAG_ONGOING_TX_DATA)) { + setInternalFlag(FLAG_CURRENT_TX_USE_CSMA, false); + + if (txWaitingForAck()) { + setInternalFlag(FLAG_WAITING_FOR_ACK, true); + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_TX_ACK_WAITING, 0U); + } else { + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_TX_ENDED, 0U); + RAIL_YieldRadio(gRailHandle); + setInternalFlag(EVENT_TX_SUCCESS, true); + // Broadcast packet clear the ONGOING flag here. + setInternalFlag(FLAG_ONGOING_TX_DATA, false); + } +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + railDebugCounters.mRailEventPacketSent++; +#endif + } +} + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static void txFailedCallback(bool isAck, uint32_t status) +{ + if (isAck) { + setInternalFlag(FLAG_ONGOING_TX_ACK, false); + } else if (getInternalFlag(FLAG_ONGOING_TX_DATA)) { + if (status == EVENT_TX_CCA_FAILED) { + setInternalFlag(EVENT_TX_CCA_FAILED, true); + setInternalFlag(FLAG_CURRENT_TX_USE_CSMA, false); +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + railDebugCounters.mRailEventChannelBusy++; +#endif + } else { + setInternalFlag(EVENT_TX_FAILED, true); +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + railDebugCounters.mRailEventTxAbort++; +#endif + } + setInternalFlag((FLAG_ONGOING_TX_DATA | FLAG_WAITING_FOR_ACK), false); + RAIL_YieldRadio(gRailHandle); + } +} + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static void ackTimeoutCallback(void) +{ + OT_ASSERT(txWaitingForAck()); + OT_ASSERT(getInternalFlag(FLAG_WAITING_FOR_ACK)); + + setInternalFlag(EVENT_TX_NO_ACK, true); + setInternalFlag(FLAG_ONGOING_TX_DATA, false); + +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + railDebugCounters.mRailEventNoAck++; +#endif + +#ifdef SL_CATALOG_RAIL_UTIL_ANT_DIV_PRESENT + // If antenna diversity is enabled toggle the selected antenna. + sl_rail_util_ant_div_toggle_tx_antenna(); +#endif // SL_CATALOG_RAIL_UTIL_ANT_DIV_PRESENT + // TO DO: Check if we have an OT function that + // provides the number of mac retry attempts left + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_TX_ACK_TIMEDOUT, 0); + + setInternalFlag(FLAG_WAITING_FOR_ACK, false); + RAIL_YieldRadio(gRailHandle); + emPendingData = false; +} + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static void schedulerEventCallback(RAIL_Handle_t aRailHandle) +{ + RAIL_SchedulerStatus_t status = RAIL_GetSchedulerStatus(aRailHandle); + bool transmitBusy = getInternalFlag(FLAG_ONGOING_TX_DATA); + + OT_ASSERT(status != RAIL_SCHEDULER_STATUS_INTERNAL_ERROR); + + if (status == RAIL_SCHEDULER_STATUS_CCA_CSMA_TX_FAIL || status == RAIL_SCHEDULER_STATUS_SINGLE_TX_FAIL + || status == RAIL_SCHEDULER_STATUS_SCHEDULED_TX_FAIL + || (status == RAIL_SCHEDULER_STATUS_SCHEDULE_FAIL && transmitBusy) + || (status == RAIL_SCHEDULER_STATUS_EVENT_INTERRUPTED && transmitBusy)) { + if (getInternalFlag(FLAG_ONGOING_TX_ACK)) { + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_RX_ACK_ABORTED, (uint32_t)isReceivingFrame()); + txFailedCallback(true, EVENT_TX_FAILED); + } + // We were in the process of TXing a data frame, treat it as a CCA_FAIL. + if (getInternalFlag(FLAG_ONGOING_TX_DATA)) { + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_TX_BLOCKED, (uint32_t)txWaitingForAck()); + txFailedCallback(false, EVENT_TX_CCA_FAILED); + } + +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + railDebugCounters.mRailEventSchedulerStatusError++; +#endif + } else if (status == RAIL_SCHEDULER_STATUS_AVERAGE_RSSI_FAIL + || (status == RAIL_SCHEDULER_STATUS_SCHEDULE_FAIL + && sEnergyScanStatus == ENERGY_SCAN_STATUS_IN_PROGRESS)) { + energyScanComplete(OT_RADIO_RSSI_INVALID); + } +} + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static void configUnscheduledCallback(void) +{ + // We are waiting for an ACK: we will never get the ACK we were waiting for. + // We want to call ackTimeoutCallback() only if the PACKET_SENT event + // already fired (which would clear the FLAG_ONGOING_TX_DATA flag). + if (getInternalFlag(FLAG_WAITING_FOR_ACK)) { + ackTimeoutCallback(); + } + + // We are about to send an ACK, which it won't happen. + if (getInternalFlag(FLAG_ONGOING_TX_ACK)) { + txFailedCallback(true, EVENT_TX_FAILED); + } +} + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static void RAILCb_Generic(RAIL_Handle_t aRailHandle, RAIL_Events_t aEvents) +{ +#ifdef SL_CATALOG_RAIL_UTIL_IEEE802154_STACK_EVENT_PRESENT + if (aEvents & (RAIL_EVENT_RX_SYNC1_DETECT | RAIL_EVENT_RX_SYNC2_DETECT)) { + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_RX_STARTED, (uint32_t)isReceivingFrame()); + } +#endif // SL_CATALOG_RAIL_UTIL_IEEE802154_STACK_EVENT_PRESENT + +#ifdef SL_CATALOG_RAIL_UTIL_COEX_PRESENT + if (aEvents & RAIL_EVENT_SIGNAL_DETECTED) { + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_SIGNAL_DETECTED, 0U); + } +#endif // SL_CATALOG_RAIL_UTIL_COEX_PRESENT + + if ((aEvents & RAIL_EVENT_IEEE802154_DATA_REQUEST_COMMAND) +#ifdef SL_CATALOG_RAIL_UTIL_COEX_PRESENT + && !RAIL_IsRxAutoAckPaused(aRailHandle) +#endif // SL_CATALOG_RAIL_UTIL_COEX_PRESENT + ) { + dataRequestCommandCallback(aRailHandle); + } + +#ifdef SL_CATALOG_RAIL_UTIL_IEEE802154_STACK_EVENT_PRESENT + if (aEvents & RAIL_EVENT_RX_FILTER_PASSED) { + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_RX_ACCEPTED, (uint32_t)isReceivingFrame()); + } +#endif // SL_CATALOG_RAIL_UTIL_IEEE802154_STACK_EVENT_PRESENT + + if (aEvents & RAIL_EVENT_TX_PACKET_SENT) { + packetSentCallback(false); + } else if (aEvents & RAIL_EVENT_TX_CHANNEL_BUSY) { + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_TX_BLOCKED, (uint32_t)txWaitingForAck()); + txFailedCallback(false, EVENT_TX_CCA_FAILED); + } else if (aEvents & RAIL_EVENT_TX_BLOCKED) { + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_TX_BLOCKED, (uint32_t)txWaitingForAck()); + txFailedCallback(false, EVENT_TX_FAILED); + } else if (aEvents & (RAIL_EVENT_TX_UNDERFLOW | RAIL_EVENT_TX_ABORTED)) { + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_TX_ABORTED, (uint32_t)txWaitingForAck()); + txFailedCallback(false, EVENT_TX_FAILED); + } else { + // Pre-completion aEvents are processed in their logical order: +#ifdef SL_CATALOG_RAIL_UTIL_IEEE802154_STACK_EVENT_PRESENT + if (aEvents & RAIL_EVENT_TX_START_CCA) { + // We are starting RXWARM for a CCA check + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_TX_CCA_SOON, 0U); + } + if (aEvents & RAIL_EVENT_TX_CCA_RETRY) { + // We failed a CCA check and need to retry + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_TX_CCA_BUSY, 0U); + } + if (aEvents & RAIL_EVENT_TX_CHANNEL_CLEAR) { + // We're going on-air + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_TX_STARTED, 0U); + } +#endif // SL_CATALOG_RAIL_UTIL_IEEE802154_STACK_EVENT_PRESENT + } + +#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 + + // Note: RAIL_EVENT_SCHEDULED_TX_STARTED and RAIL_EVENT_SCHEDULED_RX_STARTED have the + // same numerical value because one cannot schedule both RX and TX simultaneously. + // Have to take due care to check for these statuses depending on whether we're + // scheduling a transmit or receive. Therefore, we're using an internal flag + // 'FLAG_SCHEDULED_RX_PENDING' to track our scheduled-receive state. + + if (getInternalFlag(FLAG_SCHEDULED_RX_PENDING)) { + if (aEvents & RAIL_EVENT_SCHEDULED_RX_STARTED) { + setInternalFlag(EVENT_SCHEDULED_RX_STARTED, true); + } + + // Once done with scheduled receive, clear internal scheduled-rx flag and idle. + // If we miss a scheduled receive, let application schedule another. + if (aEvents & RAIL_EVENT_RX_SCHEDULED_RX_END || aEvents & RAIL_EVENT_RX_SCHEDULED_RX_MISSED) { + setInternalFlag(FLAG_SCHEDULED_RX_PENDING, false); + setInternalFlag(EVENT_SCHEDULED_RX_STARTED, false); + radioSetIdle(); + } + } else { + if (aEvents & RAIL_EVENT_SCHEDULED_TX_STARTED) { +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + railDebugCounters.mRailEventsScheduledTxStartedCount++; +#endif + } else if (aEvents & RAIL_EVENT_TX_SCHEDULED_TX_MISSED) { + txFailedCallback(false, EVENT_TX_SCHEDULER_ERROR); + } + } +#endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 + + if (aEvents & RAIL_EVENT_RX_PACKET_RECEIVED) { + packetReceivedCallback(); +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + railDebugCounters.mRailEventPacketReceived++; +#endif + } + +#ifdef SL_CATALOG_RAIL_UTIL_IEEE802154_STACK_EVENT_PRESENT + if (aEvents & RAIL_EVENT_RX_FRAME_ERROR) { + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_RX_CORRUPTED, (uint32_t)isReceivingFrame()); + } + // The following 3 events cause us to not receive a packet + if (aEvents & (RAIL_EVENT_RX_PACKET_ABORTED | RAIL_EVENT_RX_ADDRESS_FILTERED | RAIL_EVENT_RX_FIFO_OVERFLOW)) { + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_RX_FILTERED, (uint32_t)isReceivingFrame()); + } +#endif // SL_CATALOG_RAIL_UTIL_IEEE802154_STACK_EVENT_PRESENT + + if (aEvents & RAIL_EVENT_TXACK_PACKET_SENT) { + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_RX_ACK_SENT, (uint32_t)isReceivingFrame()); + packetSentCallback(true); + } + if (aEvents & (RAIL_EVENT_TXACK_ABORTED | RAIL_EVENT_TXACK_UNDERFLOW)) { + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_RX_ACK_ABORTED, (uint32_t)isReceivingFrame()); + txFailedCallback(true, 0xFF); + } + if (aEvents & RAIL_EVENT_TXACK_BLOCKED) { + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_RX_ACK_BLOCKED, (uint32_t)isReceivingFrame()); + txFailedCallback(true, 0xFF); + } + // Deal with ACK timeout after possible RX completion in case RAIL + // notifies us of the ACK and the timeout simultaneously -- we want + // the ACK to win over the timeout. + if (aEvents & RAIL_EVENT_RX_ACK_TIMEOUT) { + if (getInternalFlag(FLAG_WAITING_FOR_ACK)) { + ackTimeoutCallback(); + } + } + + if (aEvents & RAIL_EVENT_CONFIG_UNSCHEDULED) { + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_RX_IDLED, 0U); + configUnscheduledCallback(); +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + railDebugCounters.mRailEventConfigUnScheduled++; +#endif + } + + if (aEvents & RAIL_EVENT_CONFIG_SCHEDULED) { +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + railDebugCounters.mRailEventConfigScheduled++; +#endif + } + + if (aEvents & RAIL_EVENT_SCHEDULER_STATUS) { + schedulerEventCallback(aRailHandle); + } + + if (aEvents & RAIL_EVENT_CAL_NEEDED) { + // -Werror=unused-but-set-variable Workaround + // RAIL_Status_t status; + /* status = */ RAIL_Calibrate(aRailHandle, NULL, RAIL_CAL_ALL_PENDING); + + // TODO: Non-RTOS DMP case fails +#if (!defined(SL_CATALOG_BLUETOOTH_PRESENT) || defined(SL_CATALOG_KERNEL_PRESENT)) + // TEMPORARY - this asserts on Mux - OT_ASSERT(status == RAIL_STATUS_NO_ERROR); +#else + OT_UNUSED_VARIABLE(status); +#endif + +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + railDebugCounters.mRailEventCalNeeded++; +#endif + } + + if (aEvents & RAIL_EVENT_RSSI_AVERAGE_DONE) { + const int16_t energyScanResultQuarterDbm = RAIL_GetAverageRssi(aRailHandle); + RAIL_YieldRadio(aRailHandle); + + energyScanComplete(energyScanResultQuarterDbm == RAIL_RSSI_INVALID + ? OT_RADIO_RSSI_INVALID + : (energyScanResultQuarterDbm / QUARTER_DBM_IN_DBM)); +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + railDebugCounters.mRailPlatRadioEnergyScanDoneCbCount++; +#endif + } + // scheduled and unscheduled config events happen very often, + // especially in a DMP situation where there is an active BLE connection. + // Waking up the OT RTOS task on every one of these occurrences causes + // a lower priority CLI task to starve and makes it appear like a code lockup + // There is no reason to wake the OT task for these events! + if (!(aEvents & RAIL_EVENT_CONFIG_SCHEDULED) && !(aEvents & RAIL_EVENT_CONFIG_UNSCHEDULED)) { + otSysEventSignalPending(); + } +} + +//------------------------------------------------------------------------------ +// Main thread packet handling + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static bool validatePacketDetails(RAIL_RxPacketHandle_t packetHandle, + RAIL_RxPacketDetails_t *pPacketDetails, + RAIL_RxPacketInfo_t *pPacketInfo, + uint16_t *packetLength) +{ + bool pktValid = true; + RAIL_Status_t rStatus; +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + rxDebugStep = 0; +#endif + + rStatus = RAIL_GetRxPacketDetailsAlt(gRailHandle, packetHandle, pPacketDetails); + otEXPECT_ACTION(rStatus == RAIL_STATUS_NO_ERROR, pktValid = false); +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + rxDebugStep++; +#endif + + otEXPECT_ACTION(isFilterMaskValid(pPacketInfo->filterMask), pktValid = false); +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + rxDebugStep++; +#endif + + // RAIL's packetBytes includes the (1 or 2 byte) PHY header but not the 2-byte CRC. + // We want *packetLength to match the PHY header length so we add 2 for CRC + // and subtract the PHY header size. + *packetLength = pPacketInfo->packetBytes + 2U - PHY_HEADER_SIZE; + + if (PHY_HEADER_SIZE == 1) { + otEXPECT_ACTION(*packetLength == pPacketInfo->firstPortionData[0], pktValid = false); + } else { + uint8_t lengthByte = + ((pPacketInfo->firstPortionBytes > 1) ? pPacketInfo->firstPortionData[1] : pPacketInfo->lastPortionData[0]); + otEXPECT_ACTION(*packetLength == (uint16_t)(__RBIT(lengthByte) >> 24), pktValid = false); + } +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + rxDebugStep++; +#endif + + // check the length validity of recv packet; RAIL should take care of this. + otEXPECT_ACTION((*packetLength >= IEEE802154_MIN_LENGTH && *packetLength <= IEEE802154_MAX_LENGTH), pktValid = false); +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + rxDebugStep++; +#endif + +exit: +#if (OPENTHREAD_CONFIG_LOG_LEVEL == OT_LOG_LEVEL_DEBG) + if (!pktValid) { + otLogDebgPlat("RX Pkt Invalid: rStatus=0x%X, filterMask=0x%2X, pktLen=%i", + rStatus, + pPacketInfo->filterMask, + *packetLength); +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + otLogDebgPlat("RX debug step=%i", rxDebugStep); +#endif + } +#endif + return pktValid; +} + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static bool validatePacketTimestamp(RAIL_RxPacketDetails_t *pPacketDetails, uint16_t packetLength) +{ + bool rxTimestampValid = true; + + // Get the timestamp when the SFD was received + otEXPECT_ACTION(pPacketDetails->timeReceived.timePosition != RAIL_PACKET_TIME_INVALID, rxTimestampValid = false); + + // + PHY HEADER SIZE for PHY header + // We would not need this if PHR is not included and we want the MHR + pPacketDetails->timeReceived.totalPacketBytes = packetLength + PHY_HEADER_SIZE; + + otEXPECT_ACTION((RAIL_GetRxTimeSyncWordEndAlt(gRailHandle, pPacketDetails) == RAIL_STATUS_NO_ERROR), + rxTimestampValid = false); +exit: + return rxTimestampValid; +} + +otError otPlatMultipanGetActiveInstance(otInstance **aInstance) +{ + otError error = OT_ERROR_NOT_IMPLEMENTED; + OT_UNUSED_VARIABLE(aInstance); + + return error; +} + +otError otPlatMultipanSetActiveInstance(otInstance *aInstance, bool aCompletePending) +{ + otError error = OT_ERROR_NOT_IMPLEMENTED; + + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aCompletePending); + + return error; +} + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static void updateRxFrameTimestamp(bool aIsAckFrame, RAIL_Time_t aTimestamp) +{ + // Current time > sync-receive timestamp + // Therefore lower 32 bits of current time should always be greater than lower 32 bits + // of sync-rx timestamp unless there is a overflow. In such cases, we do not want to + // take overflow into consideration for sync-rx timestamp. + uint64_t railUsTimeNow = otPlatTimeGet(); + uint32_t railUsTimerWraps = railUsTimeNow >> 32; + + // Address multiple overflows, such as what would happen if the current time overflows + // from 0x00000001FFFFFFFF to 0x0000000200000000 (leave the higher 32 bits as 0) + if ((railUsTimeNow & 0xFFFFFFFF) <= aTimestamp) { + railUsTimerWraps--; + } + + if (aIsAckFrame) { + sReceiveAck.frame.mInfo.mRxInfo.mTimestamp = aTimestamp + ((uint64_t)railUsTimerWraps << 32); + } else { + sReceive.frame.mInfo.mRxInfo.mTimestamp = aTimestamp + ((uint64_t)railUsTimerWraps << 32); + } +} + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static otError skipRxPacketLengthBytes(RAIL_RxPacketInfo_t *pPacketInfo) +{ + otError error = OT_ERROR_NONE; + otEXPECT_ACTION(pPacketInfo->firstPortionBytes > 0, error = OT_ERROR_FAILED); + + pPacketInfo->firstPortionData += PHY_HEADER_SIZE; + pPacketInfo->packetBytes -= PHY_HEADER_SIZE; + + if (PHY_HEADER_SIZE == 1 || pPacketInfo->firstPortionBytes > 1) { + pPacketInfo->firstPortionBytes -= PHY_HEADER_SIZE; + } else { + pPacketInfo->firstPortionBytes = 0U; + // Increment lastPortionData to skip the second byte of the PHY header + otEXPECT_ACTION(pPacketInfo->lastPortionData != NULL, error = OT_ERROR_FAILED); + pPacketInfo->lastPortionData++; + } + +exit: + return error; +} + +// This function dequeues the rx-queue, move the content to sReceive buffer +// and return the memory block which was used to store the received packet. +// So that memory block can be freed after submitting the receiveDone Callback. +static rxBuffer *prepareNextRxPacketforCb(void) +{ + rxBuffer *rxPacketBuf = (rxBuffer *)queueRemove(&sRxPacketQueue); + OT_ASSERT(rxPacketBuf != NULL); + uint8_t *psdu = rxPacketBuf->psdu; + + // Check the reserved bits in the MAC header, then clear them. + // If we sent an enhanced ACK, check if it was secured. + // Set this flag only when the packet is really acknowledged with a secured enhanced ACK. + sReceive.frame.mInfo.mRxInfo.mAckedWithSecEnhAck = ((*psdu & IEEE802154_SECURED_OUTGOING_ENHANCED_ACK) != 0); + *psdu &= ~IEEE802154_SECURED_OUTGOING_ENHANCED_ACK; + + // Check whether frame pendinng bit was set in the outgoing ACK. + // Set this flag only when the packet is really acknowledged with frame pending set. + sReceive.frame.mInfo.mRxInfo.mAckedWithFramePending = ((*psdu & IEEE802154_FRAME_PENDING_SET_IN_OUTGOING_ACK) != 0); + *psdu &= ~IEEE802154_FRAME_PENDING_SET_IN_OUTGOING_ACK; + + sReceive.frame.mChannel = rxPacketBuf->packetInfo.channel; + sReceive.frame.mLength = rxPacketBuf->packetInfo.length; + sReceive.frame.mPsdu = rxPacketBuf->psdu; + + sReceive.frame.mInfo.mRxInfo.mRssi = rxPacketBuf->packetInfo.rssi; + sLastRssi = rxPacketBuf->packetInfo.rssi; + + sReceive.frame.mInfo.mRxInfo.mLqi = rxPacketBuf->packetInfo.lqi; + sLastLqi = rxPacketBuf->packetInfo.rssi; + + sReceive.iid = rxPacketBuf->packetInfo.iid; + +#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 + // Use stored values for these + sReceive.frame.mInfo.mRxInfo.mAckKeyId = sMacKeys[sReceive.iid].ackKeyId; + sReceive.frame.mInfo.mRxInfo.mAckFrameCounter = sMacKeys[sReceive.iid].ackFrameCounter; +#endif + + updateRxFrameTimestamp(false, rxPacketBuf->packetInfo.timestamp); + return rxPacketBuf; +} + +static void processNextRxPacket(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + sReceiveError = OT_ERROR_NONE; + uint8_t interfaceId = INVALID_INTERFACE_INDEX; + otInstance *instance = NULL; + rxBuffer *rxPacketBuf = NULL; + + rxPacketBuf = prepareNextRxPacketforCb(); + + // sReceive buffer gets populated from prepareNextRxPacketforCb. + interfaceId = sReceive.iid; + + // Submit broadcast packet to all initilized instances. + do { +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + instance = otPlatMultipanIidToInstance(interfaceId); +#else + instance = aInstance; +#endif + interfaceId++; + if (instance == NULL) { + continue; + } +#if OPENTHREAD_CONFIG_DIAG_ENABLE + if (otPlatDiagModeGet()) { + otPlatDiagRadioReceiveDone(instance, &sReceive.frame, sReceiveError); + } else +#endif // OPENTHREAD_CONFIG_DIAG_ENABLE + { + bool isGpPacket = sl_gp_intf_is_gp_pkt(&sReceive.frame); +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + // For multipan RCP, continue normal processing. + OT_UNUSED_VARIABLE(isGpPacket); +#else + // Else, we should not receive GP packets. + otEXPECT(!isGpPacket); +#endif + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + (void)sl_gp_intf_should_buffer_pkt(instance, &sReceive.frame, true); +#endif + otPlatRadioReceiveDone(instance, &sReceive.frame, sReceiveError); + } + } while (sReceive.iid == RADIO_BCAST_IID && interfaceId < RADIO_INTERFACE_COUNT); + +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + railDebugCounters.mRailPlatRadioReceiveDoneCbCount++; +#endif + +#if !OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE +exit: +#endif + IgnoreError(sl_memory_pool_free(&sRxPacketMemPoolHandle, rxPacketBuf)); + otSysEventSignalPending(); +} + +static void processRxPackets(otInstance *aInstance) +{ + while (!queueIsEmpty(&sRxPacketQueue)) { + processNextRxPacket(aInstance); + } +} + +static void processTxComplete(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + otError txStatus; + otRadioFrame *ackFrame = NULL; + + if (getInternalFlag(RADIO_TX_EVENTS)) { + if (getInternalFlag(EVENT_TX_SUCCESS)) { + txStatus = OT_ERROR_NONE; + + if (sCurrentTxPacket->frame.mPsdu[0] & IEEE802154_FRAME_FLAG_ACK_REQUIRED) { + ackFrame = &sReceiveAck.frame; + } + + setInternalFlag(EVENT_TX_SUCCESS, false); + } else if (getInternalFlag(EVENT_TX_CCA_FAILED)) { + txStatus = OT_ERROR_CHANNEL_ACCESS_FAILURE; + setInternalFlag(EVENT_TX_CCA_FAILED, false); + } else if (getInternalFlag(EVENT_TX_NO_ACK)) { + txStatus = OT_ERROR_NO_ACK; + setInternalFlag(EVENT_TX_NO_ACK, false); + } else { + txStatus = OT_ERROR_ABORT; + setInternalFlag(EVENT_TX_FAILED, false); + } + + if (txStatus != OT_ERROR_NONE) { + otLogDebgPlat("Transmit failed ErrorCode=%d", txStatus); + } + +#if OPENTHREAD_CONFIG_DIAG_ENABLE + if (otPlatDiagModeGet()) { +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + otPlatDiagRadioTransmitDone(otPlatMultipanIidToInstance(sCurrentTxPacket->iid), + &sCurrentTxPacket->frame, + txStatus); +#else + otPlatDiagRadioTransmitDone(aInstance, &sCurrentTxPacket->frame, txStatus); +#endif + } else +#endif + { + // Clear any internally-set txDelays so future transmits are not affected. + sCurrentTxPacket->frame.mInfo.mTxInfo.mTxDelayBaseTime = 0; + sCurrentTxPacket->frame.mInfo.mTxInfo.mTxDelay = 0; +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + otPlatRadioTxDone(otPlatMultipanIidToInstance(sCurrentTxPacket->iid), + &sCurrentTxPacket->frame, + ackFrame, + txStatus); +#else + otPlatRadioTxDone(aInstance, &sCurrentTxPacket->frame, ackFrame, txStatus); +#endif + } + +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + railDebugCounters.mRailPlatRadioTxDoneCbCount++; +#endif + otSysEventSignalPending(); + } +} + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE +static inline void processPendingCommands(void) +{ + // Check and process pending transmit and energy scan commands if radio is not busy. + if (!queueIsEmpty(&sPendingCommandQueue) && (!isRadioTransmittingOrScanning())) { + // Dequeue the pending command + pendingCommandEntry *pendingCommand = (pendingCommandEntry *)queueRemove(&sPendingCommandQueue); + OT_ASSERT(pendingCommand != NULL); + uint8_t iid = pendingCommand->iid; + + switch (pendingCommand->cmdType) { + case kPendingCommandTypeTransmit: + otPlatRadioTransmit(otPlatMultipanIidToInstance(iid), pendingCommand->request.txFrame); + break; + + case kPendingCommandTypeEnergyScan: + otPlatRadioEnergyScan(otPlatMultipanIidToInstance(iid), + pendingCommand->request.energyScan.scanChannel, + pendingCommand->request.energyScan.scanDuration); + break; + + default: + OT_ASSERT(false); + break; + } + + // Free the allocated memory. + sl_free(pendingCommand); + } +} +#endif // OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + +void efr32RadioProcess(otInstance *aInstance) +{ + (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_TICK, 0U); + + // We should process the received packet first. Adding it at the end of this function, + // will delay the stack notification until the next call to efr32RadioProcess() + processRxPackets(aInstance); + processTxComplete(aInstance); + + if (sEnergyScanMode == ENERGY_SCAN_MODE_ASYNC && sEnergyScanStatus == ENERGY_SCAN_STATUS_COMPLETED) { + sEnergyScanStatus = ENERGY_SCAN_STATUS_IDLE; + OT_ASSERT(sEnergyScanActiveInterface != INVALID_INTERFACE_INDEX); +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + otPlatRadioEnergyScanDone(otPlatMultipanIidToInstance(sEnergyScanActiveInterface), sEnergyScanResultDbm); +#else + otPlatRadioEnergyScanDone(aInstance, sEnergyScanResultDbm); +#endif + sEnergyScanActiveInterface = INVALID_INTERFACE_INDEX; + otSysEventSignalPending(); + +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + railDebugCounters.mRailEventEnergyScanCompleted++; +#endif + } + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + processPendingCommands(); +#endif // OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE +} + +//------------------------------------------------------------------------------ +// Antenna Diversity, Wifi coexistence and Runtime PHY select support + +RAIL_Status_t efr32RadioSetCcaMode(uint8_t aMode) +{ + return RAIL_IEEE802154_ConfigCcaMode(gRailHandle, aMode); +} + +RAIL_IEEE802154_PtiRadioConfig_t efr32GetPtiRadioConfig(void) +{ + return (RAIL_IEEE802154_GetPtiRadioConfig(gRailHandle)); +} + +#ifdef SL_CATALOG_RAIL_UTIL_IEEE802154_PHY_SELECT_PRESENT + +otError setRadioState(otRadioState state) +{ + otError error = OT_ERROR_NONE; + + // Defer idling the radio if we have an ongoing TX task + otEXPECT_ACTION(!getInternalFlag(ONGOING_TX_FLAGS), error = OT_ERROR_FAILED); + + switch (state) { + case OT_RADIO_STATE_RECEIVE: + otEXPECT_ACTION(radioSetRx(sReceive.frame.mChannel) == OT_ERROR_NONE, error = OT_ERROR_FAILED); + break; + case OT_RADIO_STATE_SLEEP: + radioSetIdle(); + break; + default: + error = OT_ERROR_FAILED; + } +exit: + return error; +} + +void sl_ot_update_active_radio_config(void) +{ + CORE_DECLARE_IRQ_STATE; + CORE_ENTER_ATOMIC(); + + // Proceed with PHY selection only if 2.4 GHz band is used + otEXPECT(sBandConfig.mChannelConfig == NULL); + + otRadioState currentState = otPlatRadioGetState(NULL); + otEXPECT(setRadioState(OT_RADIO_STATE_SLEEP) == OT_ERROR_NONE); + sl_rail_util_ieee802154_config_radio(gRailHandle); + otEXPECT(setRadioState(currentState) == OT_ERROR_NONE); + +exit: + CORE_EXIT_ATOMIC(); + return; +} +#endif // SL_CATALOG_RAIL_UTIL_IEEE802154_PHY_SELECT_PRESENT + +#ifdef SL_CATALOG_RAIL_UTIL_ANT_DIV_PRESENT +void efr32AntennaConfigInit(void) +{ + RAIL_Status_t status; + sl_rail_util_ant_div_init(); + status = sl_rail_util_ant_div_update_antenna_config(); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); +} +#endif // SL_CATALOG_RAIL_UTIL_ANT_DIV_PRESENT + +#ifdef SL_CATALOG_RAIL_UTIL_IEEE802154_STACK_EVENT_PRESENT + +static void changeDynamicEvents(void) +{ + /* clang-format off */ + const RAIL_Events_t eventMask = RAIL_EVENTS_NONE + | RAIL_EVENT_RX_SYNC1_DETECT + | RAIL_EVENT_RX_SYNC2_DETECT + | RAIL_EVENT_RX_FRAME_ERROR + | RAIL_EVENT_RX_FIFO_OVERFLOW + | RAIL_EVENT_RX_ADDRESS_FILTERED + | RAIL_EVENT_RX_PACKET_ABORTED + | RAIL_EVENT_RX_FILTER_PASSED + | RAIL_EVENT_TX_CHANNEL_CLEAR + | RAIL_EVENT_TX_CCA_RETRY + | RAIL_EVENT_TX_START_CCA + | RAIL_EVENT_SIGNAL_DETECTED; + /* clang-format on */ + RAIL_Events_t eventValues = RAIL_EVENTS_NONE; + + if (phyStackEventIsEnabled()) { + eventValues |= eventMask; + } + updateEvents(eventMask, eventValues); +} +#endif // SL_CATALOG_RAIL_UTIL_IEEE802154_STACK_EVENT_PRESENT + +static void efr32PhyStackInit(void) +{ +#ifdef SL_CATALOG_RAIL_UTIL_ANT_DIV_PRESENT + efr32AntennaConfigInit(); +#endif // SL_CATALOG_RAIL_UTIL_ANT_DIV_PRESENT + +#ifdef SL_CATALOG_RAIL_UTIL_COEX_PRESENT + efr32CoexInit(); +#endif // SL_CATALOG_RAIL_UTIL_COEX_PRESENT + +#ifdef SL_CATALOG_RAIL_UTIL_IEEE802154_STACK_EVENT_PRESENT + changeDynamicEvents(); +#endif +} + +#ifdef SL_CATALOG_RAIL_UTIL_COEX_PRESENT + +static void emRadioEnableAutoAck(void) +{ + CORE_DECLARE_IRQ_STATE; + CORE_ENTER_ATOMIC(); + + if (getInternalFlag(FLAG_RADIO_INIT_DONE)) { + if ((rhoActive >= RHO_INT_ACTIVE) // Internal always holds ACKs + || ((rhoActive > RHO_INACTIVE) + && ((sl_rail_util_coex_get_options() & SL_RAIL_UTIL_COEX_OPT_ACK_HOLDOFF) + != SL_RAIL_UTIL_COEX_OPT_DISABLED))) { + RAIL_PauseRxAutoAck(gRailHandle, true); + } else { + RAIL_PauseRxAutoAck(gRailHandle, false); + } + } + CORE_EXIT_ATOMIC(); +} + +static void emRadioEnablePta(bool enable) +{ + halInternalInitPta(); + + // When PTA is enabled, we want to negate PTA_REQ as soon as an incoming + // frame is aborted, e.g. due to filtering. To do that we must turn off + // the TRACKABFRAME feature that's normally on to benefit sniffing on PTI. + RAIL_Status_t status = RAIL_ConfigRxOptions(gRailHandle, + RAIL_RX_OPTION_TRACK_ABORTED_FRAMES, + (enable ? RAIL_RX_OPTIONS_NONE : RAIL_RX_OPTION_TRACK_ABORTED_FRAMES)); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); +} + +static void efr32CoexInit(void) +{ +#if SL_OPENTHREAD_COEX_COUNTER_ENABLE && defined(SL_CATALOG_RAIL_MULTIPLEXER_PRESENT) + sl_rail_mux_set_coex_counter_handler(gRailHandle, &sl_ot_coex_counter_on_event); +#else + sli_radio_coex_reset(); +#endif // SL_OPENTHREAD_COEX_COUNTER_ENABLE && defined(SL_CATALOG_RAIL_MULTIPLEXER_PRESENT) + +#if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE +#if defined(SL_RAIL_UTIL_COEX_REQ_GPIO) || defined(SL_RAIL_UTIL_COEX_REQ_PORT) || defined(SL_RAIL_UTIL_COEX_GNT_GPIO) \ + || defined(SL_RAIL_UTIL_COEX_GNT_PORT) || SL_RAIL_UTIL_COEX_RUNTIME_PHY_SELECT + sl_rail_util_ot_enable_coex_state_event_filter(); +#endif +#endif // OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE + + sl_rail_util_coex_options_t coexOptions = sl_rail_util_coex_get_options(); + +#if SL_OPENTHREAD_COEX_MAC_HOLDOFF_ENABLE + coexOptions |= SL_RAIL_UTIL_COEX_OPT_MAC_HOLDOFF; +#else + if (sl_rail_util_coex_get_radio_holdoff()) { + coexOptions |= SL_RAIL_UTIL_COEX_OPT_MAC_HOLDOFF; + } +#endif // SL_OPENTHREAD_COEX_MAC_HOLDOFF_ENABLE + + sl_rail_util_coex_set_options(coexOptions); + + emRadioEnableAutoAck(); // Might suspend AutoACK if RHO already in effect + emRadioEnablePta(sl_rail_util_coex_is_enabled()); +} + +// Managing radio transmission +static void onPtaGrantTx(sl_rail_util_coex_req_t ptaStatus) +{ + // Only pay attention to first PTA Grant callback, ignore any further ones + if (ptaGntEventReported) { + return; + } + ptaGntEventReported = true; + + OT_ASSERT(ptaStatus == SL_RAIL_UTIL_COEX_REQCB_GRANTED); + // PTA is telling us we've gotten GRANT and should send ASAP *without* CSMA + setInternalFlag(FLAG_CURRENT_TX_USE_CSMA, false); + txCurrentPacket(); +} + +static void tryTxCurrentPacket(void) +{ + OT_ASSERT(getInternalFlag(FLAG_ONGOING_TX_DATA)); + + ptaGntEventReported = false; + sl_rail_util_ieee802154_stack_event_t ptaStatus = + handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_TX_PENDED_MAC, (uint32_t)&onPtaGrantTx); + if (ptaStatus == SL_RAIL_UTIL_IEEE802154_STACK_STATUS_SUCCESS) { + // Normal case where PTA allows us to start the (CSMA) transmit below + txCurrentPacket(); + } else if (ptaStatus == SL_RAIL_UTIL_IEEE802154_STACK_STATUS_CB_PENDING) { + // onPtaGrantTx() callback will take over (and might already have) + } else if (ptaStatus == SL_RAIL_UTIL_IEEE802154_STACK_STATUS_HOLDOFF) { + txFailedCallback(false, EVENT_TX_FAILED); + } +} + +// Managing CCA Threshold +static void setCcaThreshold(void) +{ + if (sCcaThresholdDbm == CCA_THRESHOLD_UNINIT) { + sCcaThresholdDbm = CCA_THRESHOLD_DEFAULT; + } + CORE_DECLARE_IRQ_STATE; + CORE_ENTER_ATOMIC(); + int8_t thresholddBm = sCcaThresholdDbm; + + if (getInternalFlag(FLAG_RADIO_INIT_DONE)) { + if (rhoActive > RHO_INACTIVE) { + thresholddBm = RAIL_RSSI_INVALID_DBM; + } + RAIL_Status_t status = RAIL_SetCcaThreshold(gRailHandle, thresholddBm); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + } + CORE_EXIT_ATOMIC(); +} + +static void emRadioHoldOffInternalIsr(uint8_t active) +{ + if (active != rhoActive) { + rhoActive = active; // Update rhoActive early + if (getInternalFlag(FLAG_RADIO_INIT_DONE)) { + setCcaThreshold(); + emRadioEnableAutoAck(); + } + } +} + +// External API used by Coex Component +SL_WEAK void emRadioHoldOffIsr(bool active) +{ + emRadioHoldOffInternalIsr((uint8_t)active | (rhoActive & ~RHO_EXT_ACTIVE)); +} + +#if SL_OPENTHREAD_COEX_COUNTER_ENABLE + +#ifdef SL_CATALOG_RAIL_MULTIPLEXER_PRESENT +static void sl_ot_coex_counter_on_event(sl_rail_util_coex_event_t event) +#else +void sl_rail_util_coex_counter_on_event(sl_rail_util_coex_event_t event) +#endif +{ + otEXPECT(event < SL_RAIL_UTIL_COEX_EVENT_COUNT); + efr32RadioCoexCounters[event] += 1; +exit: + return; +} + +void efr32RadioClearCoexCounters(void) +{ + memset((void *)efr32RadioCoexCounters, 0, sizeof(efr32RadioCoexCounters)); +} + +#endif // SL_OPENTHREAD_COEX_COUNTER_ENABLE + +#endif // SL_CATALOG_RAIL_UTIL_COEX_PRESENT + +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT +void efr32ClearRadioCounters(void) +{ + memset(&railDebugCounters, 0, sizeof(railDebugCounters)); +} +#endif // RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT diff --git a/scripts/copy_librairies.py b/scripts/copy_librairies.py new file mode 100755 index 0000000000..82feb74eee --- /dev/null +++ b/scripts/copy_librairies.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 + +import os +import shutil +import argparse + +def list_files_in_directories(directories, exclude_paths): + """ + Generates a list of files in the given directories with their relative paths, + including the parent directory name, excluding specified files and directories. + + Parameters: + directories (list): A list of directories to list files from. + exclude_paths (list): A list of file and directory paths to exclude from the list. + + Returns: + list: A list of file paths relative to the given directories, including the parent directory name. + """ + file_list = [] + for directory in directories: + parent_dir_name = os.path.basename(directory) + for root, _, files in os.walk(directory): + for file in files: + relative_path = os.path.relpath(os.path.join(root, file), directory) + full_path = os.path.join(parent_dir_name, relative_path) + if not any(os.path.commonpath([full_path, exclude]) == exclude for exclude in exclude_paths): + file_list.append(full_path) + return file_list + +def copy_files(source_dir, dest_dir, file_list): + """ + Copies a list of files from the source directory to the destination directory. + + Parameters: + source_dir (str): The directory to copy files from. + dest_dir (str): The directory to copy files to. + file_list (list): A list of filenames to copy. + """ + # Create the destination directory if it doesn't exist + if not os.path.exists(dest_dir): + os.makedirs(dest_dir) + + # Iterate over the list of files to copy + for file_name in file_list: + full_file_name = os.path.join(source_dir, file_name) + # Check if the file exists in the source directory + if os.path.isfile(full_file_name): + # Create the destination directory structure if it doesn't exist + dest_file_path = os.path.join(dest_dir, file_name) + dest_file_dir = os.path.dirname(dest_file_path) + if not os.path.exists(dest_file_dir): + os.makedirs(dest_file_dir) + # Copy the file to the destination directory + shutil.copy(full_file_name, dest_file_path) + else: + # Print a message if the file is not found + print(f"File {file_name} not found in {source_dir}") + +def main(): + """ + Parses command line arguments and calls the copy_files function. + """ + # Set up argument parser + parser = argparse.ArgumentParser(description='Copy files from source directories to a destination directory.') + parser.add_argument('--sdk', metavar='si_sdk_path', required=False, default='../simplicity_sdk', + help='Path to Si SDK to use to take the libraries from.') + parser.add_argument('--sdk-support', metavar='sdk_support_path', required=False, default='./', + help='Path to SDK support directory.') + args = parser.parse_args() + + # List of directories to look for child files + directories_to_copy = ['platform', 'protocol'] + + # List of files and directories to exclude from copying + exclude_paths = ['platform/security/sl_component'] + + # Generate the list of files to copy from the specified directories + directories_to_copy_full_path = [os.path.join(args.sdk_support, d) for d in directories_to_copy] + files_to_copy = list_files_in_directories(directories_to_copy_full_path, exclude_paths) + + # Call the copy_files function with the parsed arguments + copy_files(args.sdk, args.sdk_support, files_to_copy) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/generate_boards.py b/scripts/generate_boards.py old mode 100644 new mode 100755 similarity index 100% rename from generate_boards.py rename to scripts/generate_boards.py diff --git a/src/core/ipv6/mld6.c b/src/core/ipv6/mld6.c deleted file mode 100644 index 091c5ad3b1..0000000000 --- a/src/core/ipv6/mld6.c +++ /dev/null @@ -1,638 +0,0 @@ -/** - * @file - * Multicast listener discovery - * - * @defgroup mld6 MLD6 - * @ingroup ip6 - * Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710. - * No support for MLDv2.\n - * Note: The allnodes (ff01::1, ff02::1) group is assumed be received by your - * netif since it must always be received for correct IPv6 operation (e.g. - * SLAAC). Ensure the netif filters are configured accordingly!\n The netif - * flags also need NETIF_FLAG_MLD6 flag set to enable MLD6 on a netif - * ("netif->flags |= NETIF_FLAG_MLD6;").\n To be called from TCPIP thread. - */ - -/* - * Copyright (c) 2010 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * - * Please coordinate changes and requests with Ivan Delamer - * - */ - -/* Based on igmp.c implementation of igmp v2 protocol */ - -#include "lwip/opt.h" - -#if LWIP_IPV6 && \ - LWIP_IPV6_MLD /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/icmp6.h" -#include "lwip/inet_chksum.h" -#include "lwip/ip.h" -#include "lwip/ip6.h" -#include "lwip/ip6_addr.h" -#include "lwip/memp.h" -#include "lwip/mld6.h" -#include "lwip/netif.h" -#include "lwip/pbuf.h" -#include "lwip/prot/mld6.h" -#include "lwip/stats.h" - -#include - -/* - * MLD constants - */ -#define MLD6_HL 1 -#define MLD6_JOIN_DELAYING_MEMBER_TMR_MS (500) - -#define MLD6_GROUP_NON_MEMBER 0 -#define MLD6_GROUP_DELAYING_MEMBER 1 -#define MLD6_GROUP_IDLE_MEMBER 2 - -/* Forward declarations. */ -static struct mld_group *mld6_new_group(struct netif *ifp, - const ip6_addr_t *addr); -static err_t mld6_remove_group(struct netif *netif, struct mld_group *group); -static void mld6_delayed_report(struct mld_group *group, u16_t maxresp); -static void mld6_send(struct netif *netif, struct mld_group *group, u8_t type); - -#if SL_LWIP_MLD6_TIMERS_ONDEMAND -#include "lwip/timeouts.h" -#include "stdbool.h" -static bool is_tmr_start = false; -#endif /* SL_LWIP_MLD6_TIMERS_ONDEMAND */ - -/** - * Stop MLD processing on interface - * - * @param netif network interface on which stop MLD processing - */ -err_t mld6_stop(struct netif *netif) { - struct mld_group *group = netif_mld6_data(netif); - - netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, NULL); - - while (group != NULL) { - struct mld_group *next = group->next; /* avoid use-after-free below */ - - /* disable the group at the MAC level */ - if (netif->mld_mac_filter != NULL) { - netif->mld_mac_filter(netif, &(group->group_address), - NETIF_DEL_MAC_FILTER); - } - - /* free group */ - memp_free(MEMP_MLD6_GROUP, group); - - /* move to "next" */ - group = next; - } - return ERR_OK; -} - -/** - * Report MLD memberships for this interface - * - * @param netif network interface on which report MLD memberships - */ -void mld6_report_groups(struct netif *netif) { - struct mld_group *group = netif_mld6_data(netif); - - while (group != NULL) { - mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS); - group = group->next; - } -} - -/** - * Search for a group that is joined on a netif - * - * @param ifp the network interface for which to look - * @param addr the group ipv6 address to search for - * @return a struct mld_group* if the group has been found, - * NULL if the group wasn't found. - */ -struct mld_group *mld6_lookfor_group(struct netif *ifp, - const ip6_addr_t *addr) { - struct mld_group *group = netif_mld6_data(ifp); - - while (group != NULL) { - if (ip6_addr_cmp(&(group->group_address), addr)) { - return group; - } - group = group->next; - } - - return NULL; -} - -/** - * create a new group - * - * @param ifp the network interface for which to create - * @param addr the new group ipv6 - * @return a struct mld_group*, - * NULL on memory error. - */ -static struct mld_group *mld6_new_group(struct netif *ifp, - const ip6_addr_t *addr) { - struct mld_group *group; - - group = (struct mld_group *)memp_malloc(MEMP_MLD6_GROUP); - if (group != NULL) { - ip6_addr_set(&(group->group_address), addr); - group->timer = 0; /* Not running */ - group->group_state = MLD6_GROUP_IDLE_MEMBER; - group->last_reporter_flag = 0; - group->use = 0; - group->next = netif_mld6_data(ifp); - - netif_set_client_data(ifp, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, group); - } - - return group; -} - -/** - * Remove a group from the mld_group_list, but do not free it yet - * - * @param group the group to remove - * @return ERR_OK if group was removed from the list, an err_t otherwise - */ -static err_t mld6_remove_group(struct netif *netif, struct mld_group *group) { - err_t err = ERR_OK; - - /* Is it the first group? */ - if (netif_mld6_data(netif) == group) { - netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MLD6, - group->next); - } else { - /* look for group further down the list */ - struct mld_group *tmpGroup; - for (tmpGroup = netif_mld6_data(netif); tmpGroup != NULL; - tmpGroup = tmpGroup->next) { - if (tmpGroup->next == group) { - tmpGroup->next = group->next; - break; - } - } - /* Group not find group */ - if (tmpGroup == NULL) { - err = ERR_ARG; - } - } - - return err; -} - -/** - * Process an input MLD message. Called by icmp6_input. - * - * @param p the mld packet, p->payload pointing to the icmpv6 header - * @param inp the netif on which this packet was received - */ -void mld6_input(struct pbuf *p, struct netif *inp) { - struct mld_header *mld_hdr; - struct mld_group *group; - - MLD6_STATS_INC(mld6.recv); - - /* Check that mld header fits in packet. */ - if (p->len < sizeof(struct mld_header)) { - /* @todo debug message */ - pbuf_free(p); - MLD6_STATS_INC(mld6.lenerr); - MLD6_STATS_INC(mld6.drop); - return; - } - - mld_hdr = (struct mld_header *)p->payload; - - switch (mld_hdr->type) { - case ICMP6_TYPE_MLQ: /* Multicast listener query. */ - /* Is it a general query? */ - if (ip6_addr_isallnodes_linklocal(ip6_current_dest_addr()) && - ip6_addr_isany(&(mld_hdr->multicast_address))) { - MLD6_STATS_INC(mld6.rx_general); - /* Report all groups, except all nodes group, and if-local groups. */ - group = netif_mld6_data(inp); - while (group != NULL) { - if ((!(ip6_addr_ismulticast_iflocal(&(group->group_address)))) && - (!(ip6_addr_isallnodes_linklocal(&(group->group_address))))) { - mld6_delayed_report(group, mld_hdr->max_resp_delay); - } - group = group->next; - } - } else { - /* Have we joined this group? - * We use IP6 destination address to have a memory aligned copy. - * mld_hdr->multicast_address should be the same. */ - MLD6_STATS_INC(mld6.rx_group); - group = mld6_lookfor_group(inp, ip6_current_dest_addr()); - if (group != NULL) { - /* Schedule a report. */ - mld6_delayed_report(group, mld_hdr->max_resp_delay); - } - } - break; /* ICMP6_TYPE_MLQ */ - case ICMP6_TYPE_MLR: /* Multicast listener report. */ - /* Have we joined this group? - * We use IP6 destination address to have a memory aligned copy. - * mld_hdr->multicast_address should be the same. */ - MLD6_STATS_INC(mld6.rx_report); - group = mld6_lookfor_group(inp, ip6_current_dest_addr()); - if (group != NULL) { - /* If we are waiting to report, cancel it. */ - if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) { - group->timer = 0; /* stopped */ - group->group_state = MLD6_GROUP_IDLE_MEMBER; - group->last_reporter_flag = 0; - } - } - break; /* ICMP6_TYPE_MLR */ - case ICMP6_TYPE_MLD: /* Multicast listener done. */ - /* Do nothing, router will query us. */ - break; /* ICMP6_TYPE_MLD */ - default: - MLD6_STATS_INC(mld6.proterr); - MLD6_STATS_INC(mld6.drop); - break; - } - - pbuf_free(p); -} - -/** - * @ingroup mld6 - * Join a group on one or all network interfaces. - * - * If the group is to be joined on all interfaces, the given group address must - * not have a zone set (i.e., it must have its zone index set to IP6_NO_ZONE). - * If the group is to be joined on one particular interface, the given group - * address may or may not have a zone set. - * - * @param srcaddr ipv6 address (zoned) of the network interface which should - * join a new group. If IP6_ADDR_ANY6, join on all netifs - * @param groupaddr the ipv6 address of the group to join (possibly but not - * necessarily zoned) - * @return ERR_OK if group was joined on the netif(s), an err_t otherwise - */ -err_t mld6_joingroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr) { - err_t err = ERR_VAL; /* no matching interface */ - struct netif *netif; - - LWIP_ASSERT_CORE_LOCKED(); - - /* loop through netif's */ - NETIF_FOREACH(netif) { - /* Should we join this interface ? */ - if (ip6_addr_isany(srcaddr) || - netif_get_ip6_addr_match(netif, srcaddr) >= 0) { - err = mld6_joingroup_netif(netif, groupaddr); - if (err != ERR_OK) { - return err; - } - } - } - - return err; -} - -/** - * @ingroup mld6 - * Join a group on a network interface. - * - * @param netif the network interface which should join a new group. - * @param groupaddr the ipv6 address of the group to join (possibly but not - * necessarily zoned) - * @return ERR_OK if group was joined on the netif, an err_t otherwise - */ -err_t mld6_joingroup_netif(struct netif *netif, const ip6_addr_t *groupaddr) { - struct mld_group *group; -#if LWIP_IPV6_SCOPES - ip6_addr_t ip6addr; - - /* If the address has a particular scope but no zone set, use the netif to - * set one now. Within the mld6 module, all addresses are properly zoned. */ - if (ip6_addr_lacks_zone(groupaddr, IP6_MULTICAST)) { - ip6_addr_set(&ip6addr, groupaddr); - ip6_addr_assign_zone(&ip6addr, IP6_MULTICAST, netif); - groupaddr = &ip6addr; - } - IP6_ADDR_ZONECHECK_NETIF(groupaddr, netif); -#endif /* LWIP_IPV6_SCOPES */ - - LWIP_ASSERT_CORE_LOCKED(); - - /* find group or create a new one if not found */ - group = mld6_lookfor_group(netif, groupaddr); - - if (group == NULL) { - /* Joining a new group. Create a new group entry. */ - group = mld6_new_group(netif, groupaddr); - if (group == NULL) { - return ERR_MEM; - } - - /* Activate this address on the MAC layer. */ - if (netif->mld_mac_filter != NULL) { - netif->mld_mac_filter(netif, groupaddr, NETIF_ADD_MAC_FILTER); - } - - /* Report our membership. */ - MLD6_STATS_INC(mld6.tx_report); - mld6_send(netif, group, ICMP6_TYPE_MLR); - mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS); - } - - /* Increment group use */ - group->use++; - return ERR_OK; -} - -/** - * @ingroup mld6 - * Leave a group on a network interface. - * - * Zoning of address follows the same rules as @ref mld6_joingroup. - * - * @param srcaddr ipv6 address (zoned) of the network interface which should - * leave the group. If IP6_ADDR_ANY6, leave on all netifs - * @param groupaddr the ipv6 address of the group to leave (possibly, but not - * necessarily zoned) - * @return ERR_OK if group was left on the netif(s), an err_t otherwise - */ -err_t mld6_leavegroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr) { - err_t err = ERR_VAL; /* no matching interface */ - struct netif *netif; - - LWIP_ASSERT_CORE_LOCKED(); - - /* loop through netif's */ - NETIF_FOREACH(netif) { - /* Should we leave this interface ? */ - if (ip6_addr_isany(srcaddr) || - netif_get_ip6_addr_match(netif, srcaddr) >= 0) { - err_t res = mld6_leavegroup_netif(netif, groupaddr); - if (err != ERR_OK) { - /* Store this result if we have not yet gotten a success */ - err = res; - } - } - } - - return err; -} - -/** - * @ingroup mld6 - * Leave a group on a network interface. - * - * @param netif the network interface which should leave the group. - * @param groupaddr the ipv6 address of the group to leave (possibly, but not - * necessarily zoned) - * @return ERR_OK if group was left on the netif, an err_t otherwise - */ -err_t mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr) { - struct mld_group *group; -#if LWIP_IPV6_SCOPES - ip6_addr_t ip6addr; - - if (ip6_addr_lacks_zone(groupaddr, IP6_MULTICAST)) { - ip6_addr_set(&ip6addr, groupaddr); - ip6_addr_assign_zone(&ip6addr, IP6_MULTICAST, netif); - groupaddr = &ip6addr; - } - IP6_ADDR_ZONECHECK_NETIF(groupaddr, netif); -#endif /* LWIP_IPV6_SCOPES */ - - LWIP_ASSERT_CORE_LOCKED(); - - /* find group */ - group = mld6_lookfor_group(netif, groupaddr); - - if (group != NULL) { - /* Leave if there is no other use of the group */ - if (group->use <= 1) { - /* Remove the group from the list */ - mld6_remove_group(netif, group); - - /* If we are the last reporter for this group */ - if (group->last_reporter_flag) { - MLD6_STATS_INC(mld6.tx_leave); - mld6_send(netif, group, ICMP6_TYPE_MLD); - } - - /* Disable the group at the MAC level */ - if (netif->mld_mac_filter != NULL) { - netif->mld_mac_filter(netif, groupaddr, NETIF_DEL_MAC_FILTER); - } - - /* free group struct */ - memp_free(MEMP_MLD6_GROUP, group); - } else { - /* Decrement group use */ - group->use--; - } - - /* Left group */ - return ERR_OK; - } - - /* Group not found */ - return ERR_VAL; -} - -#if SL_LWIP_MLD6_TIMERS_ONDEMAND -static void mld6_timeout_cb(void *arg) { - LWIP_UNUSED_ARG(arg); - - mld6_tmr(); -} -#endif /* SL_LWIP_MLD6_TIMERS_ONDEMAND */ -/** - * Periodic timer for mld processing. Must be called every - * MLD6_TMR_INTERVAL milliseconds (100). - * - * When a delaying member expires, a membership report is sent. - */ -void mld6_tmr(void) { - struct netif *netif; -#if SL_LWIP_MLD6_TIMERS_ONDEMAND - bool tmr_restart = false; -#endif /* SL_LWIP_MLD6_TIMERS_ONDEMAND */ - - NETIF_FOREACH(netif) { - struct mld_group *group = netif_mld6_data(netif); - - while (group != NULL) { - if (group->timer > 0) { - group->timer--; - if (group->timer == 0) { - /* If the state is MLD6_GROUP_DELAYING_MEMBER then we send a report - * for this group */ - if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) { - MLD6_STATS_INC(mld6.tx_report); - mld6_send(netif, group, ICMP6_TYPE_MLR); - group->group_state = MLD6_GROUP_IDLE_MEMBER; - } - } -#if SL_LWIP_MLD6_TIMERS_ONDEMAND - else { - tmr_restart = true; - } -#endif /* SL_LWIP_MLD6_TIMERS_ONDEMAND */ - } - group = group->next; - } - } -#if SL_LWIP_MLD6_TIMERS_ONDEMAND - if (tmr_restart) { - sys_timeout(MLD6_TMR_INTERVAL, mld6_timeout_cb, NULL); - } else { - sys_untimeout(mld6_timeout_cb, NULL); - is_tmr_start = false; - } -#endif /* SL_LWIP_MLD6_TIMERS_ONDEMAND */ -} - -/** - * Schedule a delayed membership report for a group - * - * @param group the mld_group for which "delaying" membership report - * should be sent - * @param maxresp_in the max resp delay provided in the query - */ -static void mld6_delayed_report(struct mld_group *group, u16_t maxresp_in) { - /* Convert maxresp from milliseconds to tmr ticks */ - u16_t maxresp = maxresp_in / MLD6_TMR_INTERVAL; - if (maxresp == 0) { - maxresp = 1; - } - -#ifdef LWIP_RAND - /* Randomize maxresp. (if LWIP_RAND is supported) */ - maxresp = (u16_t)(LWIP_RAND() % maxresp); - if (maxresp == 0) { - maxresp = 1; - } -#endif /* LWIP_RAND */ - - /* Apply timer value if no report has been scheduled already. */ - if ((group->group_state == MLD6_GROUP_IDLE_MEMBER) || - ((group->group_state == MLD6_GROUP_DELAYING_MEMBER) && - ((group->timer == 0) || (maxresp < group->timer)))) { - group->timer = maxresp; - group->group_state = MLD6_GROUP_DELAYING_MEMBER; -#if SL_LWIP_MLD6_TIMERS_ONDEMAND - if (!is_tmr_start) { - sys_timeout(MLD6_TMR_INTERVAL, mld6_timeout_cb, NULL); - is_tmr_start = true; - } -#endif /* SL_LWIP_MLD6_TIMERS_ONDEMAND */ - } -} - -/** - * Send a MLD message (report or done). - * - * An IPv6 hop-by-hop options header with a router alert option - * is prepended. - * - * @param group the group to report or quit - * @param type ICMP6_TYPE_MLR (report) or ICMP6_TYPE_MLD (done) - */ -static void mld6_send(struct netif *netif, struct mld_group *group, u8_t type) { - struct mld_header *mld_hdr; - struct pbuf *p; - const ip6_addr_t *src_addr; - - /* Allocate a packet. Size is MLD header + IPv6 Hop-by-hop options header. */ - p = pbuf_alloc(PBUF_IP, sizeof(struct mld_header) + MLD6_HBH_HLEN, PBUF_RAM); - if (p == NULL) { - MLD6_STATS_INC(mld6.memerr); - return; - } - - /* Move to make room for Hop-by-hop options header. */ - if (pbuf_remove_header(p, MLD6_HBH_HLEN)) { - pbuf_free(p); - MLD6_STATS_INC(mld6.lenerr); - return; - } - - /* Select our source address. */ - if (!ip6_addr_isvalid(netif_ip6_addr_state(netif, 0))) { - /* This is a special case, when we are performing duplicate address - * detection. We must join the multicast group, but we don't have a valid - * address yet. */ - src_addr = IP6_ADDR_ANY6; - } else { - /* Use link-local address as source address. */ - src_addr = netif_ip6_addr(netif, 0); - } - - /* MLD message header pointer. */ - mld_hdr = (struct mld_header *)p->payload; - - /* Set fields. */ - mld_hdr->type = type; - mld_hdr->code = 0; - mld_hdr->chksum = 0; - mld_hdr->max_resp_delay = 0; - mld_hdr->reserved = 0; - ip6_addr_copy_to_packed(mld_hdr->multicast_address, group->group_address); - -#if CHECKSUM_GEN_ICMP6 - IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { - mld_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, - &(group->group_address)); - } -#endif /* CHECKSUM_GEN_ICMP6 */ - - /* Add hop-by-hop headers options: router alert with MLD value. */ - ip6_options_add_hbh_ra(p, IP6_NEXTH_ICMP6, IP6_ROUTER_ALERT_VALUE_MLD); - - if (type == ICMP6_TYPE_MLR) { - /* Remember we were the last to report */ - group->last_reporter_flag = 1; - } - - /* Send the packet out. */ - MLD6_STATS_INC(mld6.xmit); - ip6_output_if(p, (ip6_addr_isany(src_addr)) ? NULL : src_addr, - &(group->group_address), MLD6_HL, 0, IP6_NEXTH_HOPBYHOP, netif); - pbuf_free(p); -} - -#endif /* LWIP_IPV6 */