Add secure transport and OAM router runtime implementations
- Implement secure transport mechanisms in `gateway_knx_secure_transport.cpp` for handling secure sessions, including AES encryption, session key generation, and secure packet wrapping and unwrapping. - Introduce `OamRouterRuntime` in `oam_router_runtime.cpp` to manage OAM router identity, individual addresses, and tunnel frame handling. - Enhance secure session management with functions for session allocation, authentication, and secure packet processing. - Ensure compatibility with existing KNXnet/IP protocols while adding support for secure communications. Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
@@ -36,6 +36,16 @@ void GatewayKnxTpIpRouter::setGroupObjectWriteHandler(GroupObjectWriteHandler ha
|
||||
group_object_write_handler_ = std::move(handler);
|
||||
}
|
||||
|
||||
void GatewayKnxTpIpRouter::setOamIpSecureCredentials(
|
||||
const GatewayKnxIpSecureCredentialMaterial& credentials) {
|
||||
oam_ip_secure_credentials_ = credentials;
|
||||
}
|
||||
|
||||
void GatewayKnxTpIpRouter::setOamIpSecureRoutingSequenceStoreHandler(
|
||||
RoutingSequenceStoreHandler handler) {
|
||||
routing_sequence_store_handler_ = std::move(handler);
|
||||
}
|
||||
|
||||
const GatewayKnxConfig& GatewayKnxTpIpRouter::config() const { return config_; }
|
||||
|
||||
bool GatewayKnxTpIpRouter::tpUartOnline() const { return tp_uart_online_; }
|
||||
@@ -69,6 +79,38 @@ esp_err_t GatewayKnxTpIpRouter::toggleProgrammingMode() {
|
||||
return setProgrammingMode(!programmingMode());
|
||||
}
|
||||
|
||||
bool GatewayKnxTpIpRouter::oamProgrammingMode() {
|
||||
if (openknx_lock_ == nullptr) {
|
||||
return false;
|
||||
}
|
||||
SemaphoreGuard guard(openknx_lock_);
|
||||
return oam_router_ != nullptr ? oam_router_->programmingMode() : oam_programming_mode_;
|
||||
}
|
||||
|
||||
esp_err_t GatewayKnxTpIpRouter::setOamProgrammingMode(bool enabled) {
|
||||
if (openknx_lock_ == nullptr) {
|
||||
last_error_ = "KNX runtime lock is unavailable";
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (!config_.oam_router.enabled) {
|
||||
last_error_ = "OAM KNX/IP router persona is disabled";
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
SemaphoreGuard guard(openknx_lock_);
|
||||
oam_programming_mode_ = enabled;
|
||||
if (oam_router_ != nullptr) {
|
||||
oam_router_->setProgrammingMode(enabled);
|
||||
}
|
||||
setOamProgrammingLed(enabled);
|
||||
ESP_LOGI(kTag, "OAM KNX/IP router programming mode %s namespace=%s",
|
||||
enabled ? "enabled" : "disabled", openknx_namespace_.c_str());
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t GatewayKnxTpIpRouter::toggleOamProgrammingMode() {
|
||||
return setOamProgrammingMode(!oamProgrammingMode());
|
||||
}
|
||||
|
||||
esp_err_t GatewayKnxTpIpRouter::start(uint32_t task_stack_size, UBaseType_t task_priority) {
|
||||
if (started_ || task_handle_ != nullptr) {
|
||||
return ESP_OK;
|
||||
@@ -193,6 +235,19 @@ esp_err_t GatewayKnxTpIpRouter::initializeRuntime() {
|
||||
bridge_.setRuntimeContext(ets_device_.get());
|
||||
knx_ip_parameters_ = std::make_unique<IpParameterObject>(
|
||||
ets_device_->deviceObject(), ets_device_->platform());
|
||||
if (config_.oam_router.enabled) {
|
||||
oam_router_ = std::make_unique<openknx::OamRouterRuntime>(
|
||||
openknx_namespace_ + "_oam", config_.oam_router.individual_address,
|
||||
config_.oam_router.tunnel_address_base);
|
||||
if (oam_router_->available()) {
|
||||
oam_router_->setProgrammingMode(oam_programming_mode_);
|
||||
} else {
|
||||
ESP_LOGW(kTag, "OAM router persona requested but BAU091A support is not compiled in");
|
||||
oam_router_.reset();
|
||||
}
|
||||
} else {
|
||||
oam_router_.reset();
|
||||
}
|
||||
openknx_configured_.store(ets_device_->configured());
|
||||
ESP_LOGI(kTag,
|
||||
"OpenKNX runtime namespace=%s configured=%d ipInterface=0x%04x "
|
||||
@@ -200,6 +255,14 @@ esp_err_t GatewayKnxTpIpRouter::initializeRuntime() {
|
||||
openknx_namespace_.c_str(), ets_device_->configured(),
|
||||
effectiveIpInterfaceIndividualAddress(), ets_device_->individualAddress(),
|
||||
ets_device_->tunnelClientAddress(), commissioning_only_);
|
||||
if (oam_router_ != nullptr) {
|
||||
ESP_LOGI(kTag,
|
||||
"OAM router persona namespace=%s_oam configured=%d device=0x%04x tunnelClient=0x%04x secureTunnel=%d secureRouting=%d",
|
||||
openknx_namespace_.c_str(), oam_router_->configured(),
|
||||
oam_router_->individualAddress(), oam_router_->tunnelClientAddress(),
|
||||
config_.oam_router.secure_tunnel_enabled,
|
||||
config_.oam_router.secure_routing_enabled);
|
||||
}
|
||||
ets_device_->setFunctionPropertyHandlers(
|
||||
[this](uint8_t object_index, uint8_t property_id, const uint8_t* data, size_t len,
|
||||
std::vector<uint8_t>* response) {
|
||||
@@ -300,6 +363,10 @@ void GatewayKnxTpIpRouter::taskLoop() {
|
||||
if (ets_device_ != nullptr) {
|
||||
pollProgrammingButton();
|
||||
ets_device_->loop();
|
||||
if (oam_router_ != nullptr) {
|
||||
oam_router_->loop();
|
||||
oam_programming_mode_ = oam_router_->programmingMode();
|
||||
}
|
||||
tp_uart_online_ = ets_device_->tpUartOnline();
|
||||
updateProgrammingLed();
|
||||
}
|
||||
@@ -376,8 +443,11 @@ void GatewayKnxTpIpRouter::finishTask() {
|
||||
{
|
||||
SemaphoreGuard guard(openknx_lock_);
|
||||
setProgrammingLed(false);
|
||||
setOamProgrammingLed(false);
|
||||
oam_programming_mode_ = false;
|
||||
knx_ip_parameters_.reset();
|
||||
bridge_.setRuntimeContext(nullptr);
|
||||
oam_router_.reset();
|
||||
ets_device_.reset();
|
||||
openknx_configured_.store(false);
|
||||
}
|
||||
@@ -387,32 +457,57 @@ void GatewayKnxTpIpRouter::finishTask() {
|
||||
}
|
||||
|
||||
void GatewayKnxTpIpRouter::pollProgrammingButton() {
|
||||
if (config_.programming_button_gpio < 0 || ets_device_ == nullptr) {
|
||||
const TickType_t now = xTaskGetTickCount();
|
||||
|
||||
if (config_.programming_button_gpio >= 0 && ets_device_ != nullptr) {
|
||||
const int level = gpio_get_level(static_cast<gpio_num_t>(config_.programming_button_gpio));
|
||||
const bool pressed = config_.programming_button_active_low ? level == 0 : level != 0;
|
||||
if (pressed && !programming_button_last_pressed_ &&
|
||||
now - programming_button_last_toggle_tick_ >= pdMS_TO_TICKS(200)) {
|
||||
ets_device_->toggleProgrammingMode();
|
||||
ESP_LOGI(kTag, "KNX programming mode %s namespace=%s",
|
||||
ets_device_->programmingMode() ? "enabled" : "disabled",
|
||||
openknx_namespace_.c_str());
|
||||
programming_button_last_toggle_tick_ = now;
|
||||
}
|
||||
programming_button_last_pressed_ = pressed;
|
||||
}
|
||||
|
||||
if (!config_.oam_router.enabled || config_.oam_router.programming_button_gpio < 0) {
|
||||
return;
|
||||
}
|
||||
const int level = gpio_get_level(static_cast<gpio_num_t>(config_.programming_button_gpio));
|
||||
const bool pressed = config_.programming_button_active_low ? level == 0 : level != 0;
|
||||
const TickType_t now = xTaskGetTickCount();
|
||||
if (pressed && !programming_button_last_pressed_ &&
|
||||
now - programming_button_last_toggle_tick_ >= pdMS_TO_TICKS(200)) {
|
||||
ets_device_->toggleProgrammingMode();
|
||||
ESP_LOGI(kTag, "KNX programming mode %s namespace=%s",
|
||||
ets_device_->programmingMode() ? "enabled" : "disabled",
|
||||
const int oam_level = gpio_get_level(
|
||||
static_cast<gpio_num_t>(config_.oam_router.programming_button_gpio));
|
||||
const bool oam_pressed = config_.oam_router.programming_button_active_low
|
||||
? oam_level == 0
|
||||
: oam_level != 0;
|
||||
if (oam_pressed && !oam_programming_button_last_pressed_ &&
|
||||
now - oam_programming_button_last_toggle_tick_ >= pdMS_TO_TICKS(200)) {
|
||||
oam_programming_mode_ = !oam_programming_mode_;
|
||||
if (oam_router_ != nullptr) {
|
||||
oam_router_->setProgrammingMode(oam_programming_mode_);
|
||||
}
|
||||
setOamProgrammingLed(oam_programming_mode_);
|
||||
ESP_LOGI(kTag, "OAM KNX/IP router programming mode %s namespace=%s",
|
||||
oam_programming_mode_ ? "enabled" : "disabled",
|
||||
openknx_namespace_.c_str());
|
||||
programming_button_last_toggle_tick_ = now;
|
||||
oam_programming_button_last_toggle_tick_ = now;
|
||||
}
|
||||
programming_button_last_pressed_ = pressed;
|
||||
oam_programming_button_last_pressed_ = oam_pressed;
|
||||
}
|
||||
|
||||
void GatewayKnxTpIpRouter::updateProgrammingLed() {
|
||||
if (config_.programming_led_gpio < 0 || ets_device_ == nullptr) {
|
||||
return;
|
||||
if (config_.programming_led_gpio >= 0 && ets_device_ != nullptr) {
|
||||
const bool programming_mode = ets_device_->programmingMode();
|
||||
if (programming_mode != programming_led_state_) {
|
||||
setProgrammingLed(programming_mode);
|
||||
}
|
||||
}
|
||||
const bool programming_mode = ets_device_->programmingMode();
|
||||
if (programming_mode == programming_led_state_) {
|
||||
return;
|
||||
|
||||
if (config_.oam_router.enabled && config_.oam_router.programming_led_gpio >= 0 &&
|
||||
oam_programming_mode_ != oam_programming_led_state_) {
|
||||
setOamProgrammingLed(oam_programming_mode_);
|
||||
}
|
||||
setProgrammingLed(programming_mode);
|
||||
}
|
||||
|
||||
void GatewayKnxTpIpRouter::setProgrammingLed(bool on) {
|
||||
@@ -425,6 +520,17 @@ void GatewayKnxTpIpRouter::setProgrammingLed(bool on) {
|
||||
programming_led_state_ = on;
|
||||
}
|
||||
|
||||
void GatewayKnxTpIpRouter::setOamProgrammingLed(bool on) {
|
||||
if (config_.oam_router.programming_led_gpio < 0) {
|
||||
oam_programming_led_state_ = on;
|
||||
return;
|
||||
}
|
||||
const bool level = config_.oam_router.programming_led_active_high ? on : !on;
|
||||
gpio_set_level(static_cast<gpio_num_t>(config_.oam_router.programming_led_gpio),
|
||||
level ? 1 : 0);
|
||||
oam_programming_led_state_ = on;
|
||||
}
|
||||
|
||||
void GatewayKnxTpIpRouter::closeSockets() {
|
||||
if (udp_sock_ >= 0) {
|
||||
shutdown(udp_sock_, SHUT_RDWR);
|
||||
@@ -609,6 +715,7 @@ void GatewayKnxTpIpRouter::closeTcpClient(TcpClient& client) {
|
||||
resetTunnelClient(tunnel);
|
||||
}
|
||||
}
|
||||
closeSecureSessionsForTcp(sock);
|
||||
if (active_tcp_sock_ == sock) {
|
||||
active_tcp_sock_ = -1;
|
||||
}
|
||||
@@ -754,6 +861,9 @@ bool GatewayKnxTpIpRouter::configureProgrammingGpio() {
|
||||
programming_button_last_pressed_ = false;
|
||||
programming_button_last_toggle_tick_ = 0;
|
||||
programming_led_state_ = false;
|
||||
oam_programming_button_last_pressed_ = false;
|
||||
oam_programming_button_last_toggle_tick_ = 0;
|
||||
oam_programming_led_state_ = false;
|
||||
|
||||
if (config_.programming_button_gpio >= 0) {
|
||||
gpio_config_t button_config{};
|
||||
@@ -792,6 +902,47 @@ bool GatewayKnxTpIpRouter::configureProgrammingGpio() {
|
||||
setProgrammingLed(false);
|
||||
}
|
||||
|
||||
if (config_.oam_router.enabled && config_.oam_router.programming_button_gpio >= 0) {
|
||||
gpio_config_t button_config{};
|
||||
button_config.pin_bit_mask =
|
||||
1ULL << static_cast<uint32_t>(config_.oam_router.programming_button_gpio);
|
||||
button_config.mode = GPIO_MODE_INPUT;
|
||||
button_config.pull_up_en = config_.oam_router.programming_button_active_low
|
||||
? GPIO_PULLUP_ENABLE
|
||||
: GPIO_PULLUP_DISABLE;
|
||||
button_config.pull_down_en = config_.oam_router.programming_button_active_low
|
||||
? GPIO_PULLDOWN_DISABLE
|
||||
: GPIO_PULLDOWN_ENABLE;
|
||||
button_config.intr_type = GPIO_INTR_DISABLE;
|
||||
const esp_err_t err = gpio_config(&button_config);
|
||||
if (err != ESP_OK) {
|
||||
last_error_ = EspErrDetail("failed to configure OAM KNX programming button GPIO" +
|
||||
std::to_string(config_.oam_router.programming_button_gpio),
|
||||
err);
|
||||
ESP_LOGE(kTag, "%s", last_error_.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (config_.oam_router.enabled && config_.oam_router.programming_led_gpio >= 0) {
|
||||
gpio_config_t led_config{};
|
||||
led_config.pin_bit_mask =
|
||||
1ULL << static_cast<uint32_t>(config_.oam_router.programming_led_gpio);
|
||||
led_config.mode = GPIO_MODE_OUTPUT;
|
||||
led_config.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
led_config.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
led_config.intr_type = GPIO_INTR_DISABLE;
|
||||
const esp_err_t err = gpio_config(&led_config);
|
||||
if (err != ESP_OK) {
|
||||
last_error_ = EspErrDetail("failed to configure OAM KNX programming LED GPIO" +
|
||||
std::to_string(config_.oam_router.programming_led_gpio),
|
||||
err);
|
||||
ESP_LOGE(kTag, "%s", last_error_.c_str());
|
||||
return false;
|
||||
}
|
||||
setOamProgrammingLed(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user