From 69af294b968edb28c114412c95080f9ea15efceb Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Mon, 10 Aug 2026 04:35:36 +0700 Subject: [PATCH 1/5] Add per-request association context for static writes --- .../ariec61850/mms/static_object_table.hpp | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/include/ariec61850/mms/static_object_table.hpp b/include/ariec61850/mms/static_object_table.hpp index f533cdabe..9852feb57 100644 --- a/include/ariec61850/mms/static_object_table.hpp +++ b/include/ariec61850/mms/static_object_table.hpp @@ -24,6 +24,23 @@ using MmsStaticWriteCallback = MmsStaticWriteResult (*)( void* context, std::span encoded_data) noexcept; +// Per-request identity propagated by a connection/runtime adapter. The core +// deliberately treats Owner as opaque binary identity and does not bind it to +// an IP address, socket, TLS implementation, or operating-system handle. +struct MmsStaticRequestAccessContext final { + std::uint64_t association_id{}; + std::span owner{}; + + [[nodiscard]] constexpr bool valid() const noexcept { + return association_id != 0U && !owner.empty(); + } +}; + +using MmsStaticContextualWriteCallback = MmsStaticWriteResult (*)( + void* context, + std::span encoded_data, + const MmsStaticRequestAccessContext& access) noexcept; + struct MmsStaticObjectEntry final { std::string_view domain; std::string_view item; @@ -34,8 +51,12 @@ struct MmsStaticObjectEntry final { MmsStaticWriteCallback write{}; void* write_context{}; + // Appended for source compatibility with existing aggregate initializers. + // A contextual callback takes precedence over the legacy write callback. + MmsStaticContextualWriteCallback contextual_write{}; + [[nodiscard]] constexpr bool writable() const noexcept { - return write != nullptr; + return write != nullptr || contextual_write != nullptr; } }; From 20981a317eccc4296f84ff7ff9c9381a625fc600 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Mon, 10 Aug 2026 04:35:49 +0700 Subject: [PATCH 2/5] Propagate request access context through dispatcher API --- include/ariec61850/mms/static_dispatcher.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/ariec61850/mms/static_dispatcher.hpp b/include/ariec61850/mms/static_dispatcher.hpp index 87c65d580..c8bd088af 100644 --- a/include/ariec61850/mms/static_dispatcher.hpp +++ b/include/ariec61850/mms/static_dispatcher.hpp @@ -58,12 +58,14 @@ class MmsStaticApplicationDispatcher final { [[nodiscard]] MmsStaticDispatchResult dispatch( std::span mms_request, std::span response, - std::span workspace) const noexcept; + std::span workspace, + const MmsStaticRequestAccessContext& access = {}) const noexcept; [[nodiscard]] MmsStaticDispatchResult dispatch( const MmsConfirmedPduView& request, std::span response, - std::span workspace) const noexcept; + std::span workspace, + const MmsStaticRequestAccessContext& access = {}) const noexcept; [[nodiscard]] constexpr const MmsStaticDispatchPolicy& policy() const noexcept { return policy_; From 7c7e3fe1c96798f70cc7e87272a3dd3ac56901df Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Mon, 10 Aug 2026 04:37:04 +0700 Subject: [PATCH 3/5] Route association context through static MMS writes --- src/mms/static_dispatcher.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/mms/static_dispatcher.cpp b/src/mms/static_dispatcher.cpp index ebc8ace4d..c3d35f50b 100644 --- a/src/mms/static_dispatcher.cpp +++ b/src/mms/static_dispatcher.cpp @@ -320,7 +320,8 @@ namespace { const MmsStaticObjectTable& objects, const MmsStaticDispatchPolicy& policy, const MmsConfirmedPduView& confirmed, - const std::span response) noexcept { + const std::span response, + const MmsStaticRequestAccessContext& access) noexcept { MmsWriteRequestView request; if (!MmsServiceSpanCodec::try_decode_write_request(confirmed, request)) { return make_status(MmsStaticDispatchStatus::malformed_request, confirmed); @@ -352,7 +353,9 @@ namespace { false, policy.access_denied_failure_code}; continue; } - const auto applied = object->write(object->write_context, values[index]); + const auto applied = object->contextual_write != nullptr + ? object->contextual_write(object->write_context, values[index], access) + : object->write(object->write_context, values[index]); results[index] = MmsWriteAccessResultInput{ applied.success, applied.success ? 0U : applied.failure_code}; @@ -371,7 +374,8 @@ namespace { MmsStaticDispatchResult MmsStaticApplicationDispatcher::dispatch( const std::span mms_request, const std::span response, - const std::span workspace) const noexcept { + const std::span workspace, + const MmsStaticRequestAccessContext& access) const noexcept { MmsConfirmedPduView request; if (!MmsPduSpanCodec::try_decode_confirmed_request_view(mms_request, request)) { return MmsStaticDispatchResult{ @@ -381,13 +385,14 @@ MmsStaticDispatchResult MmsStaticApplicationDispatcher::dispatch( 0U, 0U}; } - return dispatch(request, response, workspace); + return dispatch(request, response, workspace, access); } MmsStaticDispatchResult MmsStaticApplicationDispatcher::dispatch( const MmsConfirmedPduView& request, const std::span response, - const std::span workspace) const noexcept { + const std::span workspace, + const MmsStaticRequestAccessContext& access) const noexcept { if (!objects_.valid() || !data_sets_.valid_against(objects_) || !policy_valid(policy_)) { return make_status(MmsStaticDispatchStatus::invalid_object_table, request); } @@ -405,7 +410,7 @@ MmsStaticDispatchResult MmsStaticApplicationDispatcher::dispatch( case MmsWireConfirmedService::read: return dispatch_read(objects_, policy_, request, response, workspace); case MmsWireConfirmedService::write: - return dispatch_write(objects_, policy_, request, response); + return dispatch_write(objects_, policy_, request, response, access); default: return make_status(MmsStaticDispatchStatus::unsupported_service, request); } From 906c14d81b6ef6884fffe2a68e0ee3ec9b40de43 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Mon, 10 Aug 2026 04:37:35 +0700 Subject: [PATCH 4/5] Attach stable owner identity to MMS connection policy --- include/ariec61850/mms/connection_runtime.hpp | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/include/ariec61850/mms/connection_runtime.hpp b/include/ariec61850/mms/connection_runtime.hpp index 8cb2ddbc8..2223a94b3 100644 --- a/include/ariec61850/mms/connection_runtime.hpp +++ b/include/ariec61850/mms/connection_runtime.hpp @@ -3,6 +3,7 @@ #include "ariec61850/mms/static_dispatcher.hpp" +#include #include #include #include @@ -31,9 +32,26 @@ enum class MmsStaticConnectionStatus : std::uint8_t { }; struct MmsStaticConnectionPolicy final { + static constexpr std::size_t maximum_owner_bytes = 16U; + std::uint16_t cotp_source_reference{0x1001U}; std::uint8_t maximum_tpdu_size_code{0x0AU}; bool require_end_of_transmission{true}; + + // Optional portable association identity used by contextual MMS writes. + // The transport/server adapter assigns association_id and stable Owner. + // Leaving these zero/empty preserves legacy non-contextual behavior. + std::uint64_t association_id{}; + std::array owner{}; + std::size_t owner_size{}; + + [[nodiscard]] constexpr MmsStaticRequestAccessContext access_context() const noexcept { + return { + association_id, + owner_size > 0U && owner_size <= owner.size() + ? std::span{owner.data(), owner_size} + : std::span{}}; + } }; struct MmsStaticConnectionResult final { @@ -81,6 +99,10 @@ class MmsStaticConnectionRuntime final { return mms_presentation_context_id_; } + [[nodiscard]] constexpr MmsStaticRequestAccessContext access_context() const noexcept { + return policy_.access_context(); + } + private: const MmsStaticApplicationDispatcher& dispatcher_; MmsStaticConnectionPolicy policy_{}; From 6c191641835f03a08de265b00e471e279adb740e Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Mon, 10 Aug 2026 04:39:00 +0700 Subject: [PATCH 5/5] Propagate connection identity into MMS dispatcher --- src/mms/connection_runtime.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mms/connection_runtime.cpp b/src/mms/connection_runtime.cpp index 88e18abfe..d0246f11b 100644 --- a/src/mms/connection_runtime.cpp +++ b/src/mms/connection_runtime.cpp @@ -337,7 +337,7 @@ MmsStaticConnectionResult MmsStaticConnectionRuntime::process_tcp_window( } const auto application = dispatcher_.dispatch( - pdv.single_asn1_type, response, workspace); + pdv.single_asn1_type, response, workspace, policy_.access_context()); if (!application.success()) { if (application.status == MmsStaticDispatchStatus::response_buffer_too_small) { const auto fully_encoded = osi::PresentationSpanCodec::fully_encoded_data_size(