fix: enhance KNX OAM router functionality and security features
Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
@@ -70,6 +70,12 @@ constexpr uint8_t kDaliGroupRawMax = 0x9F;
|
||||
#define CONFIG_GATEWAY_KNX_INSTANCE_COUNT 1
|
||||
#endif
|
||||
constexpr uint32_t kKnxEnabledInstanceCount = CONFIG_GATEWAY_KNX_INSTANCE_COUNT;
|
||||
constexpr uint32_t kKnxOamInstanceId = 16;
|
||||
#if defined(CONFIG_GATEWAY_KNX_OAM_ROUTER_SUPPORTED)
|
||||
constexpr bool kKnxOamInstanceSupported = true;
|
||||
#else
|
||||
constexpr bool kKnxOamInstanceSupported = false;
|
||||
#endif
|
||||
|
||||
void ConfigureDaliCppLogging() {
|
||||
static bool configured = false;
|
||||
@@ -400,21 +406,49 @@ std::optional<int> QueryInt(std::string_view query, std::string_view primary,
|
||||
}
|
||||
|
||||
std::optional<uint32_t> ValidKnxInstanceId(int value) {
|
||||
if (value < 0 || static_cast<uint32_t>(value) >= kKnxEnabledInstanceCount) {
|
||||
return std::nullopt;
|
||||
if (value >= 0) {
|
||||
const auto instance_id = static_cast<uint32_t>(value);
|
||||
if (instance_id < kKnxEnabledInstanceCount ||
|
||||
(kKnxOamInstanceSupported && instance_id == kKnxOamInstanceId)) {
|
||||
return instance_id;
|
||||
}
|
||||
}
|
||||
return static_cast<uint32_t>(value);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::string KnxInstanceIdRangeMessage() {
|
||||
return "KNX instanceId must be in range 0.." +
|
||||
std::to_string(kKnxEnabledInstanceCount - 1);
|
||||
std::string message = "KNX instanceId must be in range 0.." +
|
||||
std::to_string(kKnxEnabledInstanceCount - 1);
|
||||
if (kKnxOamInstanceSupported) {
|
||||
message += " or " + std::to_string(kKnxOamInstanceId) + " for OAM";
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
std::optional<uint32_t> QueryKnxInstanceId(std::string_view query) {
|
||||
return ValidKnxInstanceId(QueryInt(query, "instanceId", "instance").value_or(0));
|
||||
}
|
||||
|
||||
bool IsKnxOamInstanceId(uint32_t instance_id) {
|
||||
return kKnxOamInstanceSupported && instance_id == kKnxOamInstanceId;
|
||||
}
|
||||
|
||||
cJSON* KnxAvailableInstanceIdsCjson(bool oam_enabled) {
|
||||
cJSON* instances = cJSON_CreateArray();
|
||||
if (instances == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
for (uint32_t instance_id = 0; instance_id < kKnxEnabledInstanceCount; ++instance_id) {
|
||||
cJSON_AddItemToArray(instances,
|
||||
cJSON_CreateNumber(static_cast<double>(instance_id)));
|
||||
}
|
||||
if (kKnxOamInstanceSupported && oam_enabled) {
|
||||
cJSON_AddItemToArray(instances,
|
||||
cJSON_CreateNumber(static_cast<double>(kKnxOamInstanceId)));
|
||||
}
|
||||
return instances;
|
||||
}
|
||||
|
||||
bool EraseOpenKnxRuntimeData(const std::string& nvs_namespace) {
|
||||
if (nvs_namespace.empty()) {
|
||||
return false;
|
||||
@@ -2401,9 +2435,19 @@ struct GatewayBridgeService::ChannelRuntime {
|
||||
}
|
||||
const auto effective_knx =
|
||||
knx_config.has_value() ? knx_config : service_config.default_knx_config;
|
||||
const bool oam_instance_enabled =
|
||||
effective_knx.has_value() && effective_knx->oam_router.enabled;
|
||||
cJSON_AddNumberToObject(knx_json, "instanceId", static_cast<double>(instance_id));
|
||||
cJSON_AddNumberToObject(knx_json, "enabledInstanceCount",
|
||||
static_cast<double>(kKnxEnabledInstanceCount));
|
||||
cJSON* instance_ids_json = KnxAvailableInstanceIdsCjson(oam_instance_enabled);
|
||||
if (instance_ids_json != nullptr) {
|
||||
cJSON_AddItemToObject(knx_json, "availableInstanceIds", instance_ids_json);
|
||||
}
|
||||
if (kKnxOamInstanceSupported) {
|
||||
cJSON_AddNumberToObject(knx_json, "oamInstanceId",
|
||||
static_cast<double>(kKnxOamInstanceId));
|
||||
}
|
||||
cJSON_AddBoolToObject(knx_json, "enabled", service_config.knx_enabled);
|
||||
cJSON_AddBoolToObject(knx_json, "startupEnabled", service_config.knx_startup_enabled);
|
||||
cJSON_AddBoolToObject(knx_json, "started", knx_started);
|
||||
@@ -2457,14 +2501,19 @@ struct GatewayBridgeService::ChannelRuntime {
|
||||
cJSON_AddStringToObject(security_json, "storage", "none");
|
||||
#endif
|
||||
#if defined(CONFIG_GATEWAY_KNX_DATA_SECURE_SUPPORTED)
|
||||
const auto fdsk_info = openknx::LoadFactoryFdskInfoForInstance(instance_id);
|
||||
const bool oam_instance = IsKnxOamInstanceId(instance_id);
|
||||
const auto fdsk_info = oam_instance
|
||||
? openknx::LoadOamFactoryFdskInfo()
|
||||
: openknx::LoadFactoryFdskInfoForInstance(instance_id);
|
||||
cJSON* fdsk_json = FactoryFdskInfoToCjson(fdsk_info, true);
|
||||
if (fdsk_json != nullptr) {
|
||||
cJSON_AddItemToObject(security_json, "factorySetupKey", fdsk_json);
|
||||
}
|
||||
cJSON* certificate_json =
|
||||
FactoryCertificateToCjson(
|
||||
openknx::BuildFactoryCertificatePayloadForInstance(instance_id), false);
|
||||
oam_instance ? openknx::BuildOamFactoryCertificatePayload()
|
||||
: openknx::BuildFactoryCertificatePayloadForInstance(instance_id),
|
||||
false);
|
||||
if (certificate_json != nullptr) {
|
||||
cJSON_AddItemToObject(security_json, "factoryCertificate", certificate_json);
|
||||
}
|
||||
@@ -4963,6 +5012,7 @@ GatewayBridgeHttpResponse GatewayBridgeService::handlePost(
|
||||
return ErrorResponse(ESP_ERR_INVALID_ARG, message.c_str());
|
||||
}
|
||||
|
||||
const bool reset_oam = IsKnxOamInstanceId(instance_id.value());
|
||||
const bool reset_runtime = instance_id.value() == 0;
|
||||
const bool restart_router = reset_runtime &&
|
||||
(runtime->knx_started ||
|
||||
@@ -4975,7 +5025,9 @@ GatewayBridgeHttpResponse GatewayBridgeService::handlePost(
|
||||
}
|
||||
|
||||
std::string nvs_namespace = runtime->openKnxNamespace();
|
||||
if (instance_id.value() != 0) {
|
||||
if (reset_oam) {
|
||||
nvs_namespace = kGatewayKnxOamOpenKnxNamespace;
|
||||
} else if (instance_id.value() != 0) {
|
||||
nvs_namespace += "_" + std::to_string(instance_id.value());
|
||||
}
|
||||
if (!EraseOpenKnxRuntimeData(nvs_namespace)) {
|
||||
@@ -4983,7 +5035,11 @@ GatewayBridgeHttpResponse GatewayBridgeService::handlePost(
|
||||
}
|
||||
|
||||
openknx::FactoryFdskInfo info;
|
||||
if (!openknx::ResetFactorySecurityForInstance(instance_id.value(), &info)) {
|
||||
const bool security_reset = reset_oam
|
||||
? openknx::ResetOamFactoryFdskCache(&info)
|
||||
: openknx::ResetFactorySecurityForInstance(instance_id.value(),
|
||||
&info);
|
||||
if (!security_reset) {
|
||||
return ErrorResponse(ESP_FAIL, "failed to restore KNX factory security key");
|
||||
}
|
||||
|
||||
|
||||
@@ -489,6 +489,16 @@ bool LoadFactoryFdsk(uint8_t* data, size_t len) {
|
||||
return LoadFactoryFdskForContext(kReg1Context, data, len);
|
||||
}
|
||||
|
||||
extern "C" bool knx_platform_get_fdsk_for_namespace(const char* nvs_namespace,
|
||||
uint8_t* data,
|
||||
size_t len) {
|
||||
const std::string namespace_name = nvs_namespace == nullptr ? std::string() : nvs_namespace;
|
||||
if (namespace_name.size() >= 4 && namespace_name.compare(namespace_name.size() - 4, 4, "_oam") == 0) {
|
||||
return LoadFactoryFdskForContext(kOamContext, data, len);
|
||||
}
|
||||
return LoadFactoryFdsk(data, len);
|
||||
}
|
||||
|
||||
FactoryFdskInfo LoadFactoryFdskInfo() {
|
||||
return LoadFactoryFdskInfoForContext(kReg1Context);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user