From c9013d85d46070f976ec0059554aa84c81da0022 Mon Sep 17 00:00:00 2001 From: liquidraver <504870+liquidraver@users.noreply.github.com> Date: Mon, 23 Mar 2026 08:56:21 +0100 Subject: [PATCH] update zephyr --- zephcore/CMakeLists.txt | 5 + .../adapters/datastore/ZephyrDataStore.cpp | 19 +- zephcore/app/CompanionMesh.cpp | 3 +- zephcore/app/RepeaterMesh.cpp | 2 + zephcore/boards/common/zephcore_common.conf | 11 +- zephcore/helpers/CommonCLI.cpp | 171 +++++++++++------- zephcore/helpers/NodePrefs.h | 4 + zephcore/helpers/TransportKeyStore.cpp | 38 ++-- .../espressif/0001-mcuboot-config.patch | 26 +-- zephcore/src/Utils.cpp | 150 ++++++++------- zephcore/src/main_companion.cpp | 2 + zephcore/west.yml | 6 +- 12 files changed, 266 insertions(+), 171 deletions(-) diff --git a/zephcore/CMakeLists.txt b/zephcore/CMakeLists.txt index ee1d2e1..c445d83 100644 --- a/zephcore/CMakeLists.txt +++ b/zephcore/CMakeLists.txt @@ -347,6 +347,11 @@ message(STATUS " Board overlay: ${ZEPHCORE_BOARD_OVERLAY}") message(STATUS " EXTRA_CONF_FILE: ${EXTRA_CONF_FILE}") message(STATUS " EXTRA_DTC_OVERLAY_FILE: ${EXTRA_DTC_OVERLAY_FILE}") +# Upstream mbedTLS 4.x has unused-parameter warnings in ssl_misc.h / md.c that +# fail with -Werror. Disable fatal warnings for the vendored mbedtls build. +set(MBEDTLS_FATAL_WARNINGS OFF CACHE BOOL "" FORCE) +set(TF_PSA_CRYPTO_FATAL_WARNINGS OFF CACHE BOOL "" FORCE) + find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(zephcore) diff --git a/zephcore/adapters/datastore/ZephyrDataStore.cpp b/zephcore/adapters/datastore/ZephyrDataStore.cpp index cc78e04..61fd334 100644 --- a/zephcore/adapters/datastore/ZephyrDataStore.cpp +++ b/zephcore/adapters/datastore/ZephyrDataStore.cpp @@ -412,6 +412,19 @@ void ZephyrDataStore::loadPrefs(NodePrefs &prefs) } else { prefs.leds_disabled = 0; /* Default: LEDs on */ } + + /* Offset 94: apc_enabled (ZephCore extension) */ + if (off < len) { + prefs.apc_enabled = buf[off++]; + } + + /* Offset 95: apc_margin (ZephCore extension) */ + if (off < len) { + prefs.apc_margin = buf[off++]; + if (prefs.apc_margin < 6 || prefs.apc_margin > 30) { + prefs.apc_margin = 20; /* companion default */ + } + } } void ZephyrDataStore::savePrefs(const NodePrefs &prefs) @@ -462,7 +475,11 @@ void ZephyrDataStore::savePrefs(const NodePrefs &prefs) buf[off++] = prefs.rx_boost; /* Offset 93: leds_disabled (ZephCore extension) */ buf[off++] = prefs.leds_disabled; - /* Total: 94 bytes (Arduino reads 92, ZephCore reads 94) */ + /* Offset 94: apc_enabled (ZephCore extension) */ + buf[off++] = prefs.apc_enabled; + /* Offset 95: apc_margin (ZephCore extension) */ + buf[off++] = prefs.apc_margin; + /* Total: 96 bytes (Arduino reads 92, ZephCore reads 96) */ bool ok = openWrite(PREFS_FILE, buf, off); LOG_INF("savePrefs: wrote %s, ok=%d (%d bytes), name='%.16s'", diff --git a/zephcore/app/CompanionMesh.cpp b/zephcore/app/CompanionMesh.cpp index e397507..7e88854 100644 --- a/zephcore/app/CompanionMesh.cpp +++ b/zephcore/app/CompanionMesh.cpp @@ -185,7 +185,8 @@ void CompanionMesh::begin() BaseChatMesh::begin(); #ifdef CONFIG_ZEPHCORE_APC _power_ctrl.setSF(prefs.sf); - _power_ctrl.setTargetMargin(20); /* companions are mobile — more conservative */ + _power_ctrl.setTargetMargin(prefs.apc_margin); + _power_ctrl.setEnabled(prefs.apc_enabled != 0); #endif } diff --git a/zephcore/app/RepeaterMesh.cpp b/zephcore/app/RepeaterMesh.cpp index 2462dc5..75237c4 100644 --- a/zephcore/app/RepeaterMesh.cpp +++ b/zephcore/app/RepeaterMesh.cpp @@ -809,6 +809,8 @@ void RepeaterMesh::begin(RepeaterDataStore* store) { _contention.setBackoffMultiplier(_prefs.backoff_multiplier); #ifdef CONFIG_ZEPHCORE_APC _power_ctrl.setSF(_prefs.sf); + _power_ctrl.setTargetMargin(_prefs.apc_margin); + _power_ctrl.setEnabled(_prefs.apc_enabled != 0); #endif acl.load(_store->getAclPath(), self_id); region_map.load(_store->getRegionsPath()); diff --git a/zephcore/boards/common/zephcore_common.conf b/zephcore/boards/common/zephcore_common.conf index 81152ca..d7e6965 100644 --- a/zephcore/boards/common/zephcore_common.conf +++ b/zephcore/boards/common/zephcore_common.conf @@ -17,12 +17,15 @@ CONFIG_STD_CPP17=y # Enable floating point support in printf/sprintf (required for CLI) CONFIG_CBPRINTF_FP_SUPPORT=y -# ========== Crypto (mbedTLS) ========== +# ========== Crypto (PSA) ========== # Required for mesh encryption (AES-ECB, SHA256, HMAC) CONFIG_MBEDTLS=y -CONFIG_MBEDTLS_CIPHER_AES_ENABLED=y -CONFIG_MBEDTLS_SHA256=y -CONFIG_MBEDTLS_MD_C=y +CONFIG_MBEDTLS_PSA_CRYPTO_C=y +CONFIG_PSA_WANT_ALG_SHA_256=y +CONFIG_PSA_WANT_ALG_ECB_NO_PADDING=y +CONFIG_PSA_WANT_KEY_TYPE_AES=y +CONFIG_PSA_WANT_ALG_HMAC=y +CONFIG_PSA_WANT_KEY_TYPE_HMAC=y # ========== Stack Protection ========== CONFIG_HW_STACK_PROTECTION=y diff --git a/zephcore/helpers/CommonCLI.cpp b/zephcore/helpers/CommonCLI.cpp index 79b798c..e5cadfc 100644 --- a/zephcore/helpers/CommonCLI.cpp +++ b/zephcore/helpers/CommonCLI.cpp @@ -111,6 +111,8 @@ void CommonCLI::loadPrefs(const char* path) { ok = ok && prefs_read(&file, _prefs->owner_info, sizeof(_prefs->owner_info)); // 170 ok = ok && prefs_read(&file, &_prefs->rx_boost, sizeof(_prefs->rx_boost)); // 290 ok = ok && prefs_read(&file, &_prefs->rx_duty_cycle, sizeof(_prefs->rx_duty_cycle)); // 291 + ok = ok && prefs_read(&file, &_prefs->apc_enabled, sizeof(_prefs->apc_enabled)); // 292 + ok = ok && prefs_read(&file, &_prefs->apc_margin, sizeof(_prefs->apc_margin)); // 293 if (!ok) { LOG_WRN("Prefs file %s truncated, some fields use defaults", path); @@ -153,6 +155,8 @@ void CommonCLI::loadPrefs(const char* path) { _prefs->advert_loc_policy = constrain(_prefs->advert_loc_policy, (uint8_t)0, (uint8_t)2); _prefs->rx_boost = constrain(_prefs->rx_boost, (uint8_t)0, (uint8_t)1); _prefs->rx_duty_cycle = constrain(_prefs->rx_duty_cycle, (uint8_t)0, (uint8_t)1); + _prefs->apc_enabled = constrain(_prefs->apc_enabled, (uint8_t)0, (uint8_t)1); + _prefs->apc_margin = constrain(_prefs->apc_margin, (uint8_t)6, (uint8_t)30); LOG_INF("Loaded prefs from %s", path); } @@ -216,6 +220,8 @@ void CommonCLI::savePrefs(const char* path) { fs_write(&file, _prefs->owner_info, sizeof(_prefs->owner_info)); fs_write(&file, &_prefs->rx_boost, sizeof(_prefs->rx_boost)); fs_write(&file, &_prefs->rx_duty_cycle, sizeof(_prefs->rx_duty_cycle)); + fs_write(&file, &_prefs->apc_enabled, sizeof(_prefs->apc_enabled)); + fs_write(&file, &_prefs->apc_margin, sizeof(_prefs->apc_margin)); fs_close(&file); LOG_INF("Saved prefs to %s", path); @@ -376,7 +382,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch _callbacks->applyTempRadioParams(freq, bw, sf, cr, temp_timeout_mins); snprintf(reply, CLI_REPLY_SIZE, "OK - temp params for %d mins", temp_timeout_mins); } else { - strcpy(reply, "Error, invalid params"); + strcpy(reply, "Error: freq 300-2500, bw 7-500, sf 5-12, cr 5-8, timeout>0"); } } else if (memcmp(command, "password ", 9) == 0) { StrHelper::strncpy(_prefs->password, &command[9], sizeof(_prefs->password)); @@ -433,18 +439,6 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch (double)est, (double)ff); } else if (memcmp(config, "apc.margin", 10) == 0) { snprintf(reply, CLI_REPLY_SIZE, "> %d dB", (int)_callbacks->getAPCTargetMargin()); - } else if (memcmp(config, "txpower", 7) == 0) { - if (_callbacks->isAPCEnabled()) { - int8_t apc = _callbacks->getAPCReduction(); - float margin = _callbacks->getAPCMargin(); - int effective = (int)_prefs->tx_power_dbm - (int)apc; - snprintf(reply, CLI_REPLY_SIZE, "> %ddBm (max=%d apc=-%d margin=%.1f target=%d)", - effective, (int)_prefs->tx_power_dbm, (int)apc, (double)margin, - (int)_callbacks->getAPCTargetMargin()); - } else { - snprintf(reply, CLI_REPLY_SIZE, "> %ddBm (apc=off)", - (int)_prefs->tx_power_dbm); - } } else if (memcmp(config, "flood.max", 9) == 0) { snprintf(reply, CLI_REPLY_SIZE, "> %u", (uint32_t)_prefs->flood_max); } else if (memcmp(config, "direct.txdelay", 14) == 0) { @@ -473,7 +467,17 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch strcpy(reply, "> strict"); } } else if (memcmp(config, "tx", 2) == 0 && (config[2] == 0 || config[2] == ' ')) { - snprintf(reply, CLI_REPLY_SIZE, "> %d", (int)_prefs->tx_power_dbm); + if (_callbacks->isAPCEnabled()) { + int8_t apc = _callbacks->getAPCReduction(); + float margin = _callbacks->getAPCMargin(); + int effective = (int)_prefs->tx_power_dbm - (int)apc; + snprintf(reply, CLI_REPLY_SIZE, "> %ddBm (max=%d apc=-%d margin=%.1f target=%d)", + effective, (int)_prefs->tx_power_dbm, (int)apc, (double)margin, + (int)_callbacks->getAPCTargetMargin()); + } else { + snprintf(reply, CLI_REPLY_SIZE, "> %ddBm (apc=off)", + (int)_prefs->tx_power_dbm); + } } else if (memcmp(config, "freq", 4) == 0) { snprintf(reply, CLI_REPLY_SIZE, "> %.3f", (double)_prefs->freq); } else if (memcmp(config, "public.key", 10) == 0) { @@ -495,6 +499,10 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch } else { snprintf(reply, CLI_REPLY_SIZE, "> %.3f", (double)adc_mult); } + } else if (memcmp(config, "rxboost", 7) == 0) { + snprintf(reply, CLI_REPLY_SIZE, "> %d", (int)_prefs->rx_boost); + } else if (memcmp(config, "rxduty", 6) == 0) { + snprintf(reply, CLI_REPLY_SIZE, "> %d", (int)_prefs->rx_duty_cycle); } else { snprintf(reply, CLI_REPLY_SIZE, "??: %s", config); } @@ -505,14 +513,17 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch const char* config = &command[4]; if (memcmp(config, "af ", 3) == 0) { int val = atoi(&config[3]); - if (val <= 0 || val >= 100) { + if (val < 0 || val > 99) { + strcpy(reply, "Error: range 0-99 (0=unlimited)"); + } else if (val == 0) { _prefs->airtime_factor = 0.0f; + savePrefs(); + strcpy(reply, "Duty Cycle set: 100% (unlimited)"); } else { _prefs->airtime_factor = (float)val; + savePrefs(); + snprintf(reply, CLI_REPLY_SIZE, "Duty Cycle set: %d%%", val); } - savePrefs(); - int dc = (_prefs->airtime_factor == 0.0f) ? 100 : (int)_prefs->airtime_factor; - snprintf(reply, CLI_REPLY_SIZE, "Duty Cycle set: %d%%", dc); } else if (memcmp(config, "int.thresh ", 11) == 0) { _prefs->interference_threshold = atoi(&config[11]); savePrefs(); @@ -522,13 +533,26 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch savePrefs(); snprintf(reply, CLI_REPLY_SIZE, "OK - interval rounded to %u", ((uint32_t)_prefs->agc_reset_interval) * 4); } else if (memcmp(config, "multi.acks ", 11) == 0) { - _prefs->multi_acks = atoi(&config[11]); - savePrefs(); - strcpy(reply, "OK"); + int val = atoi(&config[11]); + if (val == 0 || val == 1) { + _prefs->multi_acks = (uint8_t)val; + savePrefs(); + strcpy(reply, "OK"); + } else { + strcpy(reply, "Error: must be 0 or 1"); + } } else if (memcmp(config, "allow.read.only ", 16) == 0) { - _prefs->allow_read_only = memcmp(&config[16], "on", 2) == 0; - savePrefs(); - strcpy(reply, "OK"); + if (memcmp(&config[16], "on", 2) == 0) { + _prefs->allow_read_only = 1; + savePrefs(); + strcpy(reply, "OK"); + } else if (memcmp(&config[16], "off", 3) == 0) { + _prefs->allow_read_only = 0; + savePrefs(); + strcpy(reply, "OK"); + } else { + strcpy(reply, "Error: must be on or off"); + } } else if (memcmp(config, "flood.advert.interval ", 22) == 0) { int hours = _atoi(&config[22]); if ((hours > 0 && hours < 3) || (hours > 168)) { @@ -571,12 +595,20 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch savePrefs(); strcpy(reply, "OK"); } else { - strcpy(reply, "Error, bad chars"); + strcpy(reply, "Error: name cannot contain [ ] \\ : , ? *"); } } else if (memcmp(config, "repeat ", 7) == 0) { - _prefs->disable_fwd = memcmp(&config[7], "off", 3) == 0; - savePrefs(); - strcpy(reply, _prefs->disable_fwd ? "OK - repeat is now OFF" : "OK - repeat is now ON"); + if (memcmp(&config[7], "on", 2) == 0) { + _prefs->disable_fwd = 0; + savePrefs(); + strcpy(reply, "OK - repeat is now ON"); + } else if (memcmp(&config[7], "off", 3) == 0) { + _prefs->disable_fwd = 1; + savePrefs(); + strcpy(reply, "OK - repeat is now OFF"); + } else { + strcpy(reply, "Error: must be on or off"); + } } else if (memcmp(config, "radio ", 6) == 0) { strcpy(tmp, &config[6]); const char* parts[4]; @@ -594,7 +626,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch _callbacks->savePrefs(); strcpy(reply, "OK - reboot to apply"); } else { - strcpy(reply, "Error, invalid radio params"); + strcpy(reply, "Error: freq 300-2500, bw 7-500, sf 5-12, cr 5-8"); } } else if (memcmp(config, "lat ", 4) == 0) { _prefs->node_lat = atof(&config[4]); @@ -613,13 +645,13 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch savePrefs(); strcpy(reply, "OK (ignored: txdelay is now adaptive)"); } else if (memcmp(config, "flood.max ", 10) == 0) { - uint8_t m = atoi(&config[10]); - if (m <= 64) { - _prefs->flood_max = m; + int m = atoi(&config[10]); + if (m >= 0 && m <= 64) { + _prefs->flood_max = (uint8_t)m; savePrefs(); strcpy(reply, "OK"); } else { - strcpy(reply, "Error, max 64"); + strcpy(reply, "Error: range 0-64"); } } else if (memcmp(config, "direct.txdelay ", 15) == 0) { _prefs->direct_tx_delay_factor = atof(&config[15]); @@ -678,34 +710,47 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch } else if (memcmp(config, "apc.margin ", 11) == 0) { int val = atoi(&config[11]); if (val >= 6 && val <= 30) { + _prefs->apc_margin = (uint8_t)val; _callbacks->setAPCTargetMargin((uint8_t)val); + savePrefs(); snprintf(reply, CLI_REPLY_SIZE, "OK - APC target margin=%d dB", val); } else { - strcpy(reply, "Error, range 6-30 dB"); + strcpy(reply, "Error: range 6-30 dB"); } } else if (memcmp(config, "tx ", 3) == 0) { if (memcmp(&config[3], "apc", 3) == 0) { + _prefs->apc_enabled = 1; _callbacks->setAPCEnabled(true); + savePrefs(); snprintf(reply, CLI_REPLY_SIZE, "OK - tx power=%d dBm (apc=on)", (int)_prefs->tx_power_dbm); } else { int val = atoi(&config[3]); + int max_tx = 30; #ifdef CONFIG_ZEPHCORE_MAX_TX_POWER_DBM - if (val > CONFIG_ZEPHCORE_MAX_TX_POWER_DBM) { - val = CONFIG_ZEPHCORE_MAX_TX_POWER_DBM; - } + max_tx = CONFIG_ZEPHCORE_MAX_TX_POWER_DBM; #endif - _prefs->tx_power_dbm = (int8_t)val; - savePrefs(); - _callbacks->setAPCEnabled(false); - _callbacks->setTxPower(_prefs->tx_power_dbm); - snprintf(reply, CLI_REPLY_SIZE, "OK - tx power=%d dBm (apc=off)", - (int)_prefs->tx_power_dbm); + if (val < -9 || val > max_tx) { + snprintf(reply, CLI_REPLY_SIZE, "Error: range -9 to %d dBm, or 'apc'", max_tx); + } else { + _prefs->apc_enabled = 0; + _prefs->tx_power_dbm = (int8_t)val; + savePrefs(); + _callbacks->setAPCEnabled(false); + _callbacks->setTxPower(_prefs->tx_power_dbm); + snprintf(reply, CLI_REPLY_SIZE, "OK - tx power=%d dBm (apc=off)", + (int)_prefs->tx_power_dbm); + } } } else if (sender_timestamp == 0 && memcmp(config, "freq ", 5) == 0) { - _prefs->freq = atof(&config[5]); - savePrefs(); - strcpy(reply, "OK - reboot to apply"); + float f = atof(&config[5]); + if (f >= 400.0f && f <= 2500.0f) { + _prefs->freq = f; + savePrefs(); + strcpy(reply, "OK - reboot to apply"); + } else { + strcpy(reply, "Error: range 400-2500 MHz"); + } } else if (memcmp(config, "adc.multiplier ", 15) == 0) { _prefs->adc_multiplier = atof(&config[15]); if (_board->setAdcMultiplier(_prefs->adc_multiplier)) { @@ -720,13 +765,23 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch strcpy(reply, "Error: unsupported by this board"); } } else if (memcmp(config, "rxboost ", 8) == 0) { - _prefs->rx_boost = atoi(&config[8]) ? 1 : 0; - savePrefs(); - snprintf(reply, CLI_REPLY_SIZE, "OK - rxboost=%d (reboot to apply)", _prefs->rx_boost); - } else if (memcmp(config, "rxboost", 7) == 0 && (config[7] == 0 || config[7] == ' ')) { - snprintf(reply, CLI_REPLY_SIZE, "> %d", _prefs->rx_boost); - } else if (memcmp(config, "rxduty", 6) == 0) { - snprintf(reply, CLI_REPLY_SIZE, "RX duty cycle disabled (continuous RX)"); + int val = atoi(&config[8]); + if (val == 0 || val == 1) { + _prefs->rx_boost = (uint8_t)val; + savePrefs(); + snprintf(reply, CLI_REPLY_SIZE, "OK - rxboost=%d (reboot to apply)", _prefs->rx_boost); + } else { + strcpy(reply, "Error: must be 0 or 1"); + } + } else if (memcmp(config, "rxduty ", 7) == 0) { + int val = atoi(&config[7]); + if (val == 0 || val == 1) { + _prefs->rx_duty_cycle = (uint8_t)val; + savePrefs(); + snprintf(reply, CLI_REPLY_SIZE, "OK - rxduty=%d (reboot to apply)", _prefs->rx_duty_cycle); + } else { + strcpy(reply, "Error: must be 0 or 1"); + } } else { snprintf(reply, CLI_REPLY_SIZE, "unknown config: %s", config); } @@ -831,16 +886,8 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch } else { strcpy(reply, "off"); } - } else if (memcmp(command, "powersaving on", 14) == 0) { - _prefs->powersaving_enabled = 1; - savePrefs(); - strcpy(reply, "ok"); - } else if (memcmp(command, "powersaving off", 15) == 0) { - _prefs->powersaving_enabled = 0; - savePrefs(); - strcpy(reply, "ok"); } else if (memcmp(command, "powersaving", 11) == 0) { - strcpy(reply, _prefs->powersaving_enabled ? "on" : "off"); + strcpy(reply, "Not implemented"); } else if (memcmp(command, "log start", 9) == 0) { _callbacks->setLoggingOn(true); strcpy(reply, " logging on"); diff --git a/zephcore/helpers/NodePrefs.h b/zephcore/helpers/NodePrefs.h index 190c639..d977c73 100644 --- a/zephcore/helpers/NodePrefs.h +++ b/zephcore/helpers/NodePrefs.h @@ -64,6 +64,8 @@ struct NodePrefs { char owner_info[120]; uint8_t rx_boost; // 1 = boosted RX gain (+3dB, +2mA), 0 = power save uint8_t rx_duty_cycle; // 1 = RX duty cycle (power save), 0 = continuous RX + uint8_t apc_enabled; // 1 = adaptive power control on, 0 = fixed TX power + uint8_t apc_margin; // APC target link margin in dB (6-30, default 16) /* ---- Companion-only fields (Zephyr additions, not in Arduino) ---- */ uint8_t manual_add_contacts; @@ -124,4 +126,6 @@ static inline void initNodePrefs(NodePrefs* prefs) { prefs->adc_multiplier = 0.0f; prefs->rx_boost = 1; // Default to boosted RX for better sensitivity prefs->rx_duty_cycle = 0; // Default OFF — continuous RX for best reliability + prefs->apc_enabled = 0; // Default OFF — fixed TX power + prefs->apc_margin = 16; // Default 16 dB target link margin } diff --git a/zephcore/helpers/TransportKeyStore.cpp b/zephcore/helpers/TransportKeyStore.cpp index d37eccb..91e3303 100644 --- a/zephcore/helpers/TransportKeyStore.cpp +++ b/zephcore/helpers/TransportKeyStore.cpp @@ -5,11 +5,10 @@ #include "TransportKeyStore.h" #include -#include -#include +#include uint16_t TransportKey::calcTransportCode(const mesh::Packet* packet) const { - /* HMAC-SHA256 using mbedTLS */ + /* HMAC-SHA256 using PSA Crypto */ uint8_t hmac[32]; uint8_t type = packet->getPayloadType(); @@ -19,14 +18,27 @@ uint16_t TransportKey::calcTransportCode(const mesh::Packet* packet) const { memcpy(&msg[1], packet->payload, packet->payload_len); size_t msg_len = 1 + packet->payload_len; - /* Calculate HMAC-SHA256 */ - mbedtls_md_context_t ctx; - mbedtls_md_init(&ctx); - mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1); - mbedtls_md_hmac_starts(&ctx, key, sizeof(key)); - mbedtls_md_hmac_update(&ctx, msg, msg_len); - mbedtls_md_hmac_finish(&ctx, hmac); - mbedtls_md_free(&ctx); + /* Import HMAC key */ + psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; + psa_set_key_type(&attr, PSA_KEY_TYPE_HMAC); + psa_set_key_bits(&attr, sizeof(key) * 8); + psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_SIGN_MESSAGE); + psa_set_key_algorithm(&attr, PSA_ALG_HMAC(PSA_ALG_SHA_256)); + + psa_key_id_t key_id; + psa_status_t status = psa_import_key(&attr, key, sizeof(key), &key_id); + if (status != PSA_SUCCESS) { + return 0; + } + + size_t out_len; + status = psa_mac_compute(key_id, PSA_ALG_HMAC(PSA_ALG_SHA_256), + msg, msg_len, hmac, sizeof(hmac), &out_len); + psa_destroy_key(key_id); + + if (status != PSA_SUCCESS) { + return 0; + } /* Extract first 2 bytes as transport code (little-endian, matching Arduino SHA256 finalizeHMAC behavior) */ uint16_t code = (uint16_t)hmac[0] | ((uint16_t)hmac[1] << 8); @@ -66,7 +78,9 @@ void TransportKeyStore::getAutoKeyFor(uint16_t id, const char* name, TransportKe // calc key for publicly-known hashtag region name (SHA256 hash, first 16 bytes) uint8_t hash[32]; - mbedtls_sha256((const unsigned char*)name, strlen(name), hash, 0); + size_t out_len; + psa_hash_compute(PSA_ALG_SHA_256, (const uint8_t*)name, strlen(name), + hash, sizeof(hash), &out_len); memcpy(dest.key, hash, sizeof(dest.key)); putCache(id, dest); diff --git a/zephcore/patches/espressif/0001-mcuboot-config.patch b/zephcore/patches/espressif/0001-mcuboot-config.patch index f0035e9..1733412 100644 --- a/zephcore/patches/espressif/0001-mcuboot-config.patch +++ b/zephcore/patches/espressif/0001-mcuboot-config.patch @@ -1,19 +1,18 @@ diff --git a/zephyr/port/include/boot/mcuboot_config/mcuboot_config.h b/zephyr/port/include/boot/mcuboot_config/mcuboot_config.h -index 472ebbc5ab..9cec9f7e12 100644 +index 07aab9d15b..1338dedfdf 100644 --- a/zephyr/port/include/boot/mcuboot_config/mcuboot_config.h +++ b/zephyr/port/include/boot/mcuboot_config/mcuboot_config.h -@@ -2,6 +2,10 @@ +@@ -2,6 +2,9 @@ * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. * * SPDX-License-Identifier: Apache-2.0 + * -+ * ZephCore patch: Added #ifndef guards for MCUBOOT_MAX_IMG_SECTORS, -+ * fixed mbedTLS detection (also check CONFIG_BOOT_USE_MBEDTLS), and -+ * made MCUBOOT_VALIDATE_PRIMARY_SLOT conditional on Kconfig. ++ * ZephCore patch: fixed mbedTLS detection (also check CONFIG_BOOT_USE_MBEDTLS), ++ * and made MCUBOOT_VALIDATE_PRIMARY_SLOT conditional on Kconfig. */ #ifndef __MCUBOOT_CONFIG_H__ -@@ -76,8 +80,8 @@ +@@ -76,8 +79,8 @@ * available. */ @@ -24,7 +23,7 @@ index 472ebbc5ab..9cec9f7e12 100644 #define MCUBOOT_USE_MBED_TLS #else /* MCUboot requires the definition of a crypto lib, -@@ -90,7 +94,11 @@ +@@ -90,7 +93,11 @@ * even if no upgrade was performed. This is recommended if the boot * time penalty is acceptable. */ @@ -36,16 +35,3 @@ index 472ebbc5ab..9cec9f7e12 100644 #ifdef CONFIG_ESP_DOWNGRADE_PREVENTION #define MCUBOOT_DOWNGRADE_PREVENTION 1 -@@ -114,7 +122,12 @@ - - /* Default maximum number of flash sectors per image slot; change - * as desirable. */ -+/* ZephCore patch: allow override via -D or MIN_SECTOR_COUNT from AUTO mode */ -+#if defined(MIN_SECTOR_COUNT) -+#define MCUBOOT_MAX_IMG_SECTORS MIN_SECTOR_COUNT -+#elif !defined(MCUBOOT_MAX_IMG_SECTORS) - #define MCUBOOT_MAX_IMG_SECTORS 512 -+#endif - - /* Default number of separately updateable images; change in case of - * multiple images. */ diff --git a/zephcore/src/Utils.cpp b/zephcore/src/Utils.cpp index 2f14f75..c59b55d 100644 --- a/zephcore/src/Utils.cpp +++ b/zephcore/src/Utils.cpp @@ -1,12 +1,10 @@ /* * SPDX-License-Identifier: Apache-2.0 - * ZephCore Utils - mbedTLS backend for AES-ECB, SHA256, HMAC + * ZephCore Utils - PSA Crypto backend for AES-ECB, SHA256, HMAC */ #include -#include -#include -#include +#include #include #include @@ -25,86 +23,87 @@ static uint8_t hexVal(char c) void Utils::sha256(uint8_t *hash, size_t hash_len, const uint8_t *msg, int msg_len) { uint8_t full_hash[32]; - mbedtls_sha256(msg, (size_t)msg_len, full_hash, 0); + size_t out_len; + psa_status_t status = psa_hash_compute(PSA_ALG_SHA_256, msg, (size_t)msg_len, + full_hash, sizeof(full_hash), &out_len); + if (status != PSA_SUCCESS) { + LOG_ERR("psa_hash_compute failed: %d", (int)status); + memset(hash, 0, hash_len); + return; + } size_t copy_len = (hash_len < 32) ? hash_len : 32; memcpy(hash, full_hash, copy_len); } void Utils::sha256(uint8_t *hash, size_t hash_len, const uint8_t *frag1, int frag1_len, const uint8_t *frag2, int frag2_len) { - mbedtls_sha256_context ctx; - mbedtls_sha256_init(&ctx); - mbedtls_sha256_starts(&ctx, 0); - mbedtls_sha256_update(&ctx, frag1, (size_t)frag1_len); - mbedtls_sha256_update(&ctx, frag2, (size_t)frag2_len); - uint8_t full_hash[32]; - mbedtls_sha256_finish(&ctx, full_hash); - mbedtls_sha256_free(&ctx); - size_t copy_len = (hash_len < 32) ? hash_len : 32; - memcpy(hash, full_hash, copy_len); + psa_hash_operation_t op = PSA_HASH_OPERATION_INIT; + psa_status_t status; + + status = psa_hash_setup(&op, PSA_ALG_SHA_256); + if (status != PSA_SUCCESS) goto fail; + + status = psa_hash_update(&op, frag1, (size_t)frag1_len); + if (status != PSA_SUCCESS) goto fail; + + status = psa_hash_update(&op, frag2, (size_t)frag2_len); + if (status != PSA_SUCCESS) goto fail; + + { + uint8_t full_hash[32]; + size_t out_len; + status = psa_hash_finish(&op, full_hash, sizeof(full_hash), &out_len); + if (status != PSA_SUCCESS) goto fail; + size_t copy_len = (hash_len < 32) ? hash_len : 32; + memcpy(hash, full_hash, copy_len); + } + return; + +fail: + LOG_ERR("sha256 (2-frag) failed: %d", (int)status); + psa_hash_abort(&op); + memset(hash, 0, hash_len); } -/* AES-ECB using mbedTLS low-level API (PSA doesn't support ECB mode) */ -static int aes_ecb_encrypt(const uint8_t *key, size_t key_len, const uint8_t *src, int src_len, uint8_t *dest) +/* AES-ECB using PSA Crypto (ECB_NO_PADDING) */ +static int aes_ecb_crypt(const uint8_t *key, size_t key_len, const uint8_t *src, int src_len, + uint8_t *dest, bool encrypt) { if (src_len % 16 != 0) { LOG_ERR("src_len=%d not multiple of 16", src_len); return -1; } - mbedtls_aes_context ctx; - mbedtls_aes_init(&ctx); + psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; + psa_set_key_type(&attr, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attr, key_len * 8); + psa_set_key_usage_flags(&attr, encrypt ? PSA_KEY_USAGE_ENCRYPT : PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&attr, PSA_ALG_ECB_NO_PADDING); - int ret = mbedtls_aes_setkey_enc(&ctx, key, key_len * 8); - if (ret != 0) { - LOG_ERR("setkey failed: %d", ret); - mbedtls_aes_free(&ctx); + psa_key_id_t key_id; + psa_status_t status = psa_import_key(&attr, key, key_len, &key_id); + if (status != PSA_SUCCESS) { + LOG_ERR("psa_import_key failed: %d", (int)status); return -1; } - /* Encrypt each 16-byte block */ - for (int i = 0; i < src_len; i += 16) { - ret = mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, src + i, dest + i); - if (ret != 0) { - LOG_ERR("crypt_ecb failed at block %d: %d", i/16, ret); - mbedtls_aes_free(&ctx); - return -1; - } + size_t out_len; + if (encrypt) { + status = psa_cipher_encrypt(key_id, PSA_ALG_ECB_NO_PADDING, + src, (size_t)src_len, dest, (size_t)src_len, &out_len); + } else { + status = psa_cipher_decrypt(key_id, PSA_ALG_ECB_NO_PADDING, + src, (size_t)src_len, dest, (size_t)src_len, &out_len); } - mbedtls_aes_free(&ctx); - return src_len; -} + psa_destroy_key(key_id); -static int aes_ecb_decrypt(const uint8_t *key, size_t key_len, const uint8_t *src, int src_len, uint8_t *dest) -{ - if (src_len % 16 != 0) { - LOG_ERR("src_len=%d not multiple of 16", src_len); + if (status != PSA_SUCCESS) { + LOG_ERR("psa_cipher_%s failed: %d", encrypt ? "encrypt" : "decrypt", (int)status); return -1; } - mbedtls_aes_context ctx; - mbedtls_aes_init(&ctx); - - int ret = mbedtls_aes_setkey_dec(&ctx, key, key_len * 8); - if (ret != 0) { - LOG_ERR("setkey failed: %d", ret); - mbedtls_aes_free(&ctx); - return -1; - } - - /* Decrypt each 16-byte block */ - for (int i = 0; i < src_len; i += 16) { - ret = mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_DECRYPT, src + i, dest + i); - if (ret != 0) { - LOG_ERR("crypt_ecb failed at block %d: %d", i/16, ret); - mbedtls_aes_free(&ctx); - return -1; - } - } - - mbedtls_aes_free(&ctx); - return src_len; + return (int)out_len; } int Utils::encrypt(const uint8_t *shared_secret, uint8_t *dest, const uint8_t *src, int src_len) @@ -125,29 +124,40 @@ int Utils::encrypt(const uint8_t *shared_secret, uint8_t *dest, const uint8_t *s dp += CIPHER_BLOCK_SIZE; } int total = (int)(dp - tmp); - int n = aes_ecb_encrypt(shared_secret, CIPHER_KEY_SIZE, tmp, total, dest); + int n = aes_ecb_crypt(shared_secret, CIPHER_KEY_SIZE, tmp, total, dest, true); return (n > 0) ? n : 0; } int Utils::decrypt(const uint8_t *shared_secret, uint8_t *dest, const uint8_t *src, int src_len) { - int n = aes_ecb_decrypt(shared_secret, CIPHER_KEY_SIZE, src, src_len, dest); + int n = aes_ecb_crypt(shared_secret, CIPHER_KEY_SIZE, src, src_len, dest, false); return (n > 0) ? n : 0; } -/* HMAC-SHA256 using mbedTLS */ +/* HMAC-SHA256 using PSA Crypto */ static int compute_hmac_truncated(const uint8_t *key, size_t key_len, const uint8_t *data, size_t data_len, uint8_t *mac_out, size_t mac_len) { - uint8_t full_hmac[32]; - const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); - if (md_info == nullptr) { - LOG_ERR("compute_hmac: SHA256 not available"); + psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; + psa_set_key_type(&attr, PSA_KEY_TYPE_HMAC); + psa_set_key_bits(&attr, key_len * 8); + psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_SIGN_MESSAGE); + psa_set_key_algorithm(&attr, PSA_ALG_HMAC(PSA_ALG_SHA_256)); + + psa_key_id_t key_id; + psa_status_t status = psa_import_key(&attr, key, key_len, &key_id); + if (status != PSA_SUCCESS) { + LOG_ERR("compute_hmac: import_key failed: %d", (int)status); return -1; } - int ret = mbedtls_md_hmac(md_info, key, key_len, data, data_len, full_hmac); - if (ret != 0) { - LOG_ERR("compute_hmac: mbedtls_md_hmac failed: %d", ret); + uint8_t full_hmac[32]; + size_t out_len; + status = psa_mac_compute(key_id, PSA_ALG_HMAC(PSA_ALG_SHA_256), + data, data_len, full_hmac, sizeof(full_hmac), &out_len); + psa_destroy_key(key_id); + + if (status != PSA_SUCCESS) { + LOG_ERR("compute_hmac: psa_mac_compute failed: %d", (int)status); return -1; } diff --git a/zephcore/src/main_companion.cpp b/zephcore/src/main_companion.cpp index 45ac4ef..aefa13b 100644 --- a/zephcore/src/main_companion.cpp +++ b/zephcore/src/main_companion.cpp @@ -549,6 +549,8 @@ int main(void) companion_mesh.prefs.airtime_factor = 10.0f; /* 10% duty cycle (EU 868 default) */ companion_mesh.prefs.rx_duty_cycle = 1; /* Companions: duty cycle ON by default (power save) */ companion_mesh.prefs.rx_boost = 1; /* Default: boosted RX (+3dB sensitivity, +2mA) */ + companion_mesh.prefs.apc_enabled = 0; /* Default: APC off */ + companion_mesh.prefs.apc_margin = 20; /* Companions: more conservative margin (mobile) */ /* Load prefs from storage */ data_store.loadPrefs(companion_mesh.prefs); diff --git a/zephcore/west.yml b/zephcore/west.yml index 634a417..2526020 100644 --- a/zephcore/west.yml +++ b/zephcore/west.yml @@ -4,9 +4,13 @@ manifest: url-base: https://github.com/zephyrproject-rtos projects: + - name: hal_espressif + remote: zephyrproject-rtos + revision: e994fd973c2d8eab1ed2c8278c04e841b3a5217a + path: modules/hal/espressif - name: zephyr remote: zephyrproject-rtos - revision: 17971b7bf45163e0ef202732290f20b3b46f9743 + revision: 56f8a30c7fd7521e5eeab186b2f425f295376905 import: true self: