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 */