Commit Graph

6671 Commits

Author SHA1 Message Date
arnulfrupp fa3213ec85 [tcat] implement vendor policy for TLV support and automatic advertisement activation/deactivation (#13038)
This commit implements additional vendor application or ecosystem
policy settings for TCAT including:

1) Automatic deactivation of the TCAT agent / TCAT advertisement after
   the thread network has been started over TCAT
2) Automatic activation of the TCAT agent / TCAT advertisement after
   the thread network has been stopped over TCAT
3) Automatic activation of the TCAT agent / TCAT advertisement after
   decommissioning over TCAT
4) Blocking support of certain TCAT TLVs by the application /
   ecosystem

The commit also fixes an issue with certificate storage after
decommissioning.
2026-05-28 22:02:29 -07:00
Abtin Keshavarzian 2a2d4be953 [ip6] rename methods fully initializing an Ip6::Address/Prefix (#13169)
This commit renames several methods in `Ip6::Address`,
`Ip6::InterfaceIdentifier`, `Ip6::Prefix`, and `Ip4::Address` that
fully initialize the object from `Set...()` to `Init...()`.

This creates a clear semantic distinction in the API:
- `Init...()`: Fully (re-)initializing the object.
- `Set...()`: Modifies a specific property or a sub-component of
   the object (e.g., `SetPrefix()`,  `SetLocator()`,
   `SetSubnetId()`).

Some examples of renames include:
- `SetFromExtAddress()` -> `InitFromExtAddress()`
- `SetToLocator()` -> `InitAsLocator()`
- `SetToLinkLocalAddress()` -> `InitAsLinkLocalAddress()`
- `SetToRoutingLocator()` -> `InitAsRoutingLocator()`
- `SetToAnycastLocator()` -> `InitAsAnycastLocator()`
- `SetToIp4Mapped()` -> `InitAsIp4Mapped()`

All calls to these methods across the codebase have been updated
to reflect the new names.
2026-05-28 20:52:05 -07:00
Abtin Keshavarzian eac46963bb [mlr] simplify MLR state tracking on Child (#13166)
This commit simplifies MLR state tracking for child devices. Previously,
`Child::Ip6AddrEntry` inherited from `Ip6::Address` to encapsulate the
MLR registration check using the `Child` reference. This introduced
tight coupling between `Child` and `Ip6AddrEntry`.

The logic is refactored by removing `Ip6AddrEntry`. Instead, `Child`
now directly manages a `Child::Ip6AddressArray` and encapsulates the
MLR state querying/updating through new methods:
  - `SetAddressMlrRegistrationState()`
  - `GetAllMlrRegisteredAddresses()`
  - `ClearAllAddressesMlrRegistrationState()`

In `Mlr::Manager`, the redundant `ChildAddressArray` typedef and
`kMaxChildAddresses` constant are removed, reusing the
`Child::Ip6AddressArray`. The method `UpdateProxiedSubscriptions()`
is  renamed to the more intuitive `UpdateChildRegistrations()`, and
overloaded to allow calling it without an old address list during
initial child registration.
2026-05-28 07:25:40 -07:00
Jonathan Hui eb671b2a6d [bit-set] cast bitwise NOT in FlipBits to uint8_t (#13164)
Explicitly cast the result of the bitwise NOT operator ~ to uint8_t in
BitSetUtils::FlipBits to resolve a build error under AppleClang.

In C++, using the bitwise NOT operator on a uint8_t value promotes it to
an int. Assigning the promoted int back to uint8_t triggers an implicit
conversion warning/error (-Wimplicit-int-conversion) under newer
compiler versions, which fails the build when compiled with -Werror.
2026-05-27 13:24:56 -07:00
Abtin Keshavarzian 3243bc3529 [dataset] introduce AffectsConnectivity() and public API (#13134)
This commit introduces helper methods to `MeshCoP::Dataset` to determine
if a given Dataset affects network connectivity or the Network Key.
It also adds a corresponding public API `otDatasetAffectsConnectivity()`.

A Dataset is considered to affect connectivity if it contains a
different Channel, PAN ID, Mesh Local Prefix, or Network Key than
the current values in use.
2026-05-27 12:48:31 -07:00
Abtin Keshavarzian 597ca44261 [instance] fix typo in mIsLogLevelOverridden member variable (#13160)
This commit fixes a spelling error in `Instance` class where
`mIsLogLevelOverriden` was misspelled. It has been corrected to
`mIsLogLevelOverridden`.
2026-05-27 12:46:37 -07:00
Tobías Lifschitz 96c85c24e7 [mle] skip announce driven attach when channel/PAN ID match (#13139)
`Mle::AnnounceHandler::HandleAnnounce` previously executed the
`kAnnounceAttachAfterDelay` action on an attached node even when
the announced channel and PAN ID already equaled the current MAC
parameters. The `!channelAndPanIdMatch` guard was only consulted
in the `IsDetached()` branch. For an attached node this scheduled
`StartAnnounceAttach`, which calls `Stop()` then `Start()` with
the same channel/PAN ID -- accomplishing nothing while disrupting
attached children.

This causes an endless role flap in a topology where two FTDs
share channel, PAN ID, and network credentials but hold different
Active Dataset Timestamps, and where their RF link is too weak to
merge partitions (Advertisements rejected with LinkMarginLow at
`mle_router.cpp`). Each side restarts on every Announce received
from the higher-timestamp peer; the reactive `kSendAnnouceBack`
path further amplifies this because the lower-timestamp side's
own outgoing Announces draw Announce responses from the peer.

Apply the channel/PAN ID match guard unconditionally in
`kAnnounceAttachAfterDelay`. Mirror it on the FTD
`kSendAnnouceBack` path (matching the existing `isFromOrphan`
behavior) so peers sharing MAC parameters are not prompted to
migrate to the channel/PAN ID they already use.

Add `addon_test_announce_no_flap_on_unmergeable_partitions.py`
which builds the topology above and asserts that both nodes
retain their original partition IDs across a 20-minute simulated
window. Without this change the lower-timestamp node is
repeatedly demoted from leader during that window.
2026-05-27 11:41:21 -07:00
Abtin Keshavarzian 7ff1b5c661 [child-table] move max child IP addresses logic from Mle (#13159)
This commit moves the state and logic for managing the maximum number
of IP addresses per child from `Mle` to `ChildTable`. The logic for
checking the limit is also moved to the `Child` class itself.
This change better encapsulates the child table properties.
2026-05-27 11:36:59 -07:00
Jonathan Hui dcbd870245 [dhcp6] obsolete DHCPv6 Server Unicast Option per RFC 9915 (#13146)
This commit updates the DHCPv6 Prefix Delegation (PD) client to
comply with RFC 9915, which obsoletes the Server Unicast option
(Option 12) and the UseMulticast status code.

Changes:
- Removed `mServerAddress` and `ProcessServerUnicastOption()` from
  `Dhcp6PdClient`.
- Modified `Dhcp6PdClient::SendMessage` to always transmit via
  multicast to `ff02::1:2`.
- Removed `UseMulticast` status code handling in `HandleReply()`.
- Added `otMessageFree` weak stub in simulation platform's
  `infra_if.c` to resolve linking errors on simulation radio-only
  targets when DHCPv6 PD client is enabled.
- Updated `test_dhcp6_pd_client.cpp` to expect multicast and
  removed the obsolete UseMulticast test case.
2026-05-27 10:31:00 -07:00
Abtin Keshavarzian 494a4868a3 [net-diag] convert MAC and MLE counters TLVs to SimpleTlvInfo (#13157)
This commit updates `MacCountersTlv` and `MleCountersTlv` to use the
`SimpleTlvInfo` template. The original classes are replaced with
`MacCountersTlvValue` and `MleCountersTlvValue` which only represent
the TLV values. This helps simplify the TLV parsing and appending
logic and more importantly allows the TLV value formats to be
reused.
2026-05-27 10:25:03 -07:00
Abtin Keshavarzian 0693bceb75 [bit-set] enhance BitSet class (#13156)
This commit extends the `BitSet` class with several new
methods:
- `CountElements()`
- `IsSubsetOf()` and `IsSupersetOf()`
- `Complement()`
- `UnionWith()`, `IntersectWith()`, and `SubtractWith()`
- `SetMask()`, `AppendTo()`, and `ReadFrom()` message.

This commit also introduces a new `BitSetUtils` non-template base class
for the `BitSet<kNumBits>` template class. This change helps optimize
code by moving the common implementation logic for various bit
manipulation operations out of the template, reducing template
instantiation overhead.
2026-05-27 10:21:44 -07:00
Jonathan Hui 91a783f6ca [config] fix typo in core config check header (#13158)
Fix typo "was replaces" to "was replaced" in
openthread-core-config-check.h.
2026-05-27 07:37:23 -07:00
Abtin Keshavarzian 3ce616d835 [netdiag] rename namespace NetworkDiagnostic to NetDiag (#13154)
This commit renames the `NetworkDiagnostic` namespace in `src/core/thread/`
and its related types to `NetDiag` for brevity. It updates the
corresponding filenames and header guards as well.
2026-05-26 20:19:48 -07:00
Abtin Keshavarzian 337d424d4f [mlr] stop fast polls upon receiving response (#13149)
When a sleepy end device (where `Mle::IsRxOnWhenIdle()` returns
false) sends an MLR request, it initiates fast data polls via
`DataPollSender::SendFastPolls()` to quickly receive the response.
This commit updates `Manager::HandleResponse()` to call
`DataPollSender::StopFastPolls()` when the MLR response is processed
by a sleepy end device. This ensures that the device does not
unnecessarily continue fast polling.
2026-05-26 20:13:42 -07:00
Yakun Xu 06e210fe89 [sub-mac] redo security processing for every (re)transmission (#13093)
Retransmissions of frames containing time-dependent header Information
Elements (IEs), such as CSL or Time Sync, require updates to these
IEs to reflect the exact time of sending. If the frame counter is not
incremented for these retransmissions, it leads to nonce reuse in
AES-CCM encryption, which is a security vulnerability.

This commit addresses this issue by ensuring that every transmission
attempt (initial or retry) uses a fresh frame counter:
- Deferred security processing from `SubMac::Send()` to
  `SubMac::BeginTransmit()`.
- Upon retransmission in `SubMac::HandleTransmitDone()`, the frame is
  restored to plaintext via `TxFrame::DecryptTransmitAesCcm()` and
  security flags are cleared.
- This allows time-dependent IEs to be updated and a new frame counter
  to be assigned for every attempt.

Added a Nexus test case `retransmission_security` to verify that both
CSL and standard MAC retransmissions use incrementing frame counters
and updated CSL phases.
2026-05-26 10:36:55 -07:00
Abtin Keshavarzian 5783555d4c [mlr] introduce state machine and use timer in Mlr::Manager (#13132)
This commit introduces a structured state machine to `Mlr::Manager` to
coordinate Multicast Listener Registration (MLR) activities more
efficiently. The previous implementation relied on independent delay
variables and the global `TimeTicker`, which could lead to redundant
or premature registrations, especially when a Primary Backbone Router
(PBBR) was newly discovered or updated.

The new state machine (`kStateStopped`, `kStateIdle`,
`kStateToRegisterAll`, `kStateRegistering`, `kStateRegistered`,
`kStateNewAddrToRegister`) provides explicit transitions for the
entire MLR lifecycle. This ensures that registrations are properly
aggregated and that periodic renewals are correctly rescheduled after
successful out-of-band registrations.

Additionally, the manager now uses a dedicated `TimerMilli` instead of
`TimeTicker`, reducing system-wide overhead and providing more
precise timing control.
2026-05-26 08:38:18 -07:00
Esko Dijk cf7e5bb2b3 [srp] always send Update Lease (UL) option in success response (#13148)
Per RFC 9664, the UL option is always included in a success response (RCODE=0).
Comment in test_srp_server is updated also to avoid suggesting the opposite.
2026-05-26 07:37:39 -07:00
Abtin Keshavarzian 4de7bc578e [random] introduce template-based NonCrypto random APIs (#13142)
This commit introduces a new set of template-based APIs for
non-cryptographic random number generation in the `Random::NonCrypto`
namespace. These new methods provide a cleaner, type-safe, and more
robust interface compared to the previous methods.

Key additions:
- `Generate<UintType>()`: Returns a random value of the given
  unsigned integer type (`uint8_t`, `uint16_t`, or `uint32_t`).
- `GenerateUpToExcluding<UintType>(aMax)`: Returns a random value in
  the range `[0, aMax)`.
- `GenerateFromMinUpToExcluding<UintType>(aMin, aMax)`: Returns a
  random value in the range `[aMin, aMax)`.
- `GenerateInClosedRange<UintType>(aMin, aMax)`: Returns a random
  value in the closed range `[aMin, aMax]`.

The introduction of `GenerateInClosedRange` is an improvement as it
safely handles ranges up to the maximum value of the integer type
(e.g., `0xffff`) without the risk of overflow.

All call sites across the OpenThread core stack and tests have been
updated to adopt these new APIs. The public `otRandomNonCrypto`
functions are also updated to leverage the new internal methods.

Doxygen documentation is added for all new template methods,
detailing their behavior, including edge cases where the upper bound
is smaller than or equal to the lower bound.
2026-05-25 19:39:59 -07:00
Abtin Keshavarzian 6847b9acdf [routing-manager] fix minor style issues in StateToString() (#13144)
This commit fixes minor coding style issues in
`RoutingManager::RoutePublisher::StateToString()`. It adds a missing
semicolon after the `DefineEnumStringArray()` macro and corrects the
indentation of the return statement.
2026-05-25 19:39:13 -07:00
Abtin Keshavarzian d50b9b444f [tlv] define Tlv::AppendTlvHeader() public and use it in core (#13143)
This commit makes `Tlv::AppendTlvHeader()` public and updates call
sites to use it. This method automatically handles the formatting
of the TLV header as either a standard TLV header or an extended one
based on the provided length.
2026-05-25 19:38:59 -07:00
Jonathan Hui 5265a0bf48 [bbr] remove Backbone Router DUA ND Proxying feature (#13136)
This commit removes all code, configurations, APIs, and tests related
to the OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE feature.

Specifically, the following changes were made:
- Removed DUA ND Proxying Backbone Router configuration option and the
  related OPENTHREAD_CONFIG_NDPROXY_TABLE_ENTRY_NUM definition.
- Removed CLI commands: `bbr mgmt dua` and the proactive backbone
  notification fake command `/b/ba`.
- Removed NdProxyTable and bbr_manager DUA ND Proxying implementation.
- Removed public/internal APIs for ND Proxying and proactive backbone
  notifications.
- Deleted ndproxy_table source files and unit tests.
- Simplified CMake and GN build files to remove deleted targets.
2026-05-23 07:57:57 -07:00
sarveshkumarv3 494575f8fc [cli] add cli command to clear EID-RLOC cache (#9985)
Co-authored-by: Abtin Keshavarzian <abtink@google.com>
2026-05-21 17:18:54 -07:00
Abtin Keshavarzian 4152ea10e4 [bbr] fix overflow in Config::SelectRandomReregistrationDelay() (#13128)
This commit fixes a potential `uint16_t` overflow in
`Config::SelectRandomReregistrationDelay()` which could occur if
`mReregistrationDelay` was set to the maximum `uint16_t` value.

The `Random::NonCrypto::GetUint16InRange(lower, upper)` function
includes the lower bound but excludes the upper bound. Previously,
the code called `GetUint16InRange(1, mReregistrationDelay + 1)`,
which would overflow the upper bound if `mReregistrationDelay` was
`0xffff`. The logic is updated to `1 + GetUint16InRange(0,
mReregistrationDelay)`, which safely produces a random value in the
range `[1, mReregistrationDelay]` without overflow.
2026-05-21 13:13:39 -07:00
Abtin Keshavarzian bd47a31674 [tlv] add Tlv::AppendTlvWithValueFromMessage() helper (#13120)
This commit introduces a new helper method that allows appending a
TLV by copying its value directly from a specified `OffsetRange` of
another `Message`.

This helper automatically handles formatting the TLV as an Extended
TLV if the length exceeds 254 bytes, eliminating the need for manual
length checks and TLV header construction at the call sites.

Key changes:
- Added `Tlv::AppendTlvWithValueFromMessage()`.
- Refactored TLV header construction into a private helper
  `Tlv::AppendTlvHeader()` to share logic between `AppendTlv` variants
  and `StartTlv()`.
- Updated `Commissioner::SendRelayTransmit()` and
  `JoinerRouter::HandleUdpReceive()` to use the new helper for
  `JoinerDtlsEncapsulation` TLVs.
- Updated `TcatAgent::HandlePing()` to use the new helper, significantly
  simplifying the payload response generation.
2026-05-21 08:41:01 -07:00
Tongze Wang 7048835ba1 [core] check if Instance has been initialized before logging (#13099)
When logging while `Instance` has not been initialized yet, use 0 as
return value of `GetUptime` and use `OPENTHREAD_CONFIG_LOG_LEVEL_INIT`
as default log level instead of accessing raw memory.
2026-05-20 12:39:33 -07:00
Abtin Keshavarzian 9137b82dbe [bbr] handle role changes directly in BackboneRouter::Local (#13112)
This commit updates `BackboneRouter::Local` to receive role change
events directly from the `Notifier`. Previously, `Bbr::Local` was
indirectly relying on `BackboneRouter::Leader` to emit events even
when the PBBR configuration had not changed (e.g., during role
transitions).

The previous design was fragile and created an unnecessary dependency.
`Bbr::Local` now independently tracks role changes to ensure it
correctly evaluates its own status (e.g., deciding whether to
register as the Primary BBR).
2026-05-18 22:02:40 -07:00
Abtin Keshavarzian c5efa406c2 [bbr-leader] introduce PrimaryEvent to represent PBBR changes (#13112)
This commit introduces `PrimaryEvent` to represent changes in the
Primary Backbone Router (PBBR) configuration, replacing the previous
`State` enum. Calling it `State` was misleading as the values
describe transitions or updates to the PBBR rather than a persistent
state.

The new `PrimaryEvent` enum provides a more descriptive way to notify
dependent modules (`Mlr::Manager`, `DuaManager`, and `Bbr::Local`)
about specific changes in the PBBR, such as when it is added,
removed, or when its configuration parameters (e.g., RLOC16, Sequence
Number, or MLR Timeout) are updated.
2026-05-18 22:02:40 -07:00
Abtin Keshavarzian 3bc8b3f29a [tcat] use Tlv::Info and OffsetRange in HandleSingleTlv() (#13119)
This commit simplifies and enhances the TLV parsing logic in
`TcatAgent` so to use the `Tlv::Info` helper class. This safely and
automatically handles both standard and extended TLVs, removing the
need for manual type checking and length/offset calculations.

Key changes:
- Updated `TcatAgent::HandleSingleTlv()` to use `Tlv::Info::ParseFrom()`.
- Replaced individual `aOffset` and `aLength` parameters with
  `const OffsetRange &` across various TLV handler methods (e.g.,
  `HandlePing`, `HandleSetActiveOperationalDataset`, `VerifyHash`).

This improves code readability, safety, and consistency with common
OpenThread TLV parsing patterns.
2026-05-18 21:19:30 -07:00
Abtin Keshavarzian 9d5539844c [ble] simplify BleSecure::HandleTlsReceive() (#13118)
This commit simplifies the logic in `BleSecure::HandleTlsReceive`
by reducing the nesting level through the use of early `ExitNow()`
calls and replacing a complex `if-else` block with a `switch`
statement for handling `errorTcatAgent`.

Key improvements:
- Removed a large `else` block by adding `ExitNow()` after the
  initial transparent mode check.
- Used a `switch` statement to handle `errorTcatAgent` returned
  by `MeshCoP::TcatAgent::HandleSingleTlv()`, clearly separating
  `kErrorNone`, `kErrorAbort` (disconnect), and default fatal
  error handling.
- Improved code formatting and comment readability.
2026-05-18 19:11:41 -07:00
Abtin Keshavarzian b42e3747ee [ble] clean up message parsing in BleSecure::HandleTransport() (#13117)
This commit refactors `BleSecure::HandleTransport()` to use the
`OffsetRange` and `Message::ReadAndAdvance()` helper methods. This
replaces manual length and offset tracking, resulting in cleaner
and safer message parsing logic.

Additionally:
- Simplified the payload length calculation by using nested `Min()`
  calls instead of multiple `if/else` blocks.
- Added a `RadioPacket` typedef in `BleSecure` to alias the public
  `otBleRadioPacket` structure, aligning with OpenThread's core
  namespace conventions.
2026-05-18 19:11:10 -07:00
Abtin Keshavarzian 9a4d2dc66b [bbr] improve Backbone Router callback and Config APIs (#13111)
This commit refactors and improves the Backbone Router callback and
`Config` introducing new methods and encapsulating configuration-related
logic.

Key changes:
- Added `Leader::GetConfig()` to provide direct access to the internal
  cached `Config` object.
- Renamed `Leader::GetConfig(Config &)` to `Leader::ReadConfig(Config &)`
  to better reflect its purpose.
- Added `Config::SelectRandomReregistrationDelay()` to encapsulate the
  logic for selecting a random re-registration delay.
- Simplified variosu `HandleBackboneRouterPrimaryUpdate()` callbacks
  to remove the parameter `aConfig`,  allowing these modules to use
  `Leader::GetConfig()` instead.
2026-05-18 19:10:12 -07:00
Esko Dijk 29bb6f634a [posix] add details to UDP bind failure and log at Warn level (#13109)
This adds details to the Posix platform UDP bind error message, showing address and
port just like for the otPlatUdpConnect case. Also the severity is changed from Crit
to Warn, since it's not a critical failure given that otPlatUdpBind() is used in a
loop to find an available ephemeral port - i.e. probe the ports in range until one
succeeds.

It also fixes an issue where `errno` might be modified by the logging code itself.

Ideally the platform code would discern 'port in use' vs 'unrecoverable failure to
bind the port', but the currently defined OT APIs don't allow for any other errors
apart from ok/failed. If the specific port number is really needed, the caller
is responsible to log a critical failure.
2026-05-18 13:41:26 -07:00
Esko Dijk 5dbe57331c [posix] DHCPv6-PD client handling of sendto() failure (#13100)
If the PD client sendto() fails, e.g. because of an unroutable IPv6
destination, currently the message remains in the queue. Then the
subsequent retries cause a 100% CPU use (without end). This fixes the
issue by dropping the message in case of an unresolvable sendto()
failure.
2026-05-18 13:13:09 -07:00
Abtin Keshavarzian 64c4124bd1 [sntp] clean up and improve Sntp::Client (#13114)
This commit refactors and improves the `Sntp::Client` class by
adopting common OpenThread patterns and simplifying the logic.

Key changes:
- Introduced `Sntp::Client::QueryInfo` core class to wrap the
  public `otSntpQuery` structure.
- Added `Timestamp` class to handle SNTP timestamps, simplifying
  the `Header` structure.
- Renamed methods and variables to be more concise and consistent
  (e.g., `FinalizeSntpTransaction` to `Finalize`,
  `mRetransmissionTimer` to `mTimer`).
- Simplified the `HandleUdpReceive` logic by splitting response
  processing into `ProcessResponse`.

This change improves code readability and maintainability of the
SNTP client module.
2026-05-18 13:04:37 -07:00
Abtin Keshavarzian 56010e2f65 [bbr] introduce BackboneRouter::Config core class (#13108)
This commit introduces a new core class `BackboneRouter::Config` that
inherits from the public `otBackboneRouterConfig` struct. This aligns
with the OpenThread architectural pattern of using core-internal
classes to wrap public API structures, providing a cleaner interface
and encapsulating logic.

Importantly, this commit ensures that the `MlrTimeout` is adjusted
and clamped to valid ranges before comparing the new configuration
with the existing one. This ensures that the state transition
(e.g., `kStateRefreshed`) correctly reflects the actual values
that will be used.

Other improvements:
- Added helper methods `IsPresent()`, `MarkAsAbsent()`, and getters
  for configuration fields.
- Moved `MlrTimeout` adjustment logic into `Config::AdjustMlrTimeout()`.
- Added `Config::Log()` to log configuration details, and updated
  `Leader` to log both old and new configurations when a Primary
  Backbone Router event occurs.
2026-05-18 13:01:02 -07:00
Shu Chen b6f6d34606 [diag] invoke SetDiagMode before setting channel/power (#12941)
In Host + RCP mode, running `diag start` from the host CLI may trigger
RadioSpinel warnings: InvalidState, “Error processing result” / “Error
waiting response”.

**Root cause**

Diags::ProcessStart sent channel / power commands before enabling diag
mode. On Spinel, these are forwarded to the RCP (via
`SPINEL_PROP_NEST_STREAM_MFG`), but the RCP only accepts other diag
commands after start.

```    
    if (!IsEnabled() && !StringMatch(aArgs[0], "start"))
    {
        Output("diagnostics mode is disabled\r\n");
        ExitNow(error = kErrorInvalidState);
    }
```

As a result, early channel / power commands are rejected with
InvalidState.
2026-05-15 07:31:14 -07:00
Abtin Keshavarzian 545a649ecd [bbr-leader] remove kDomainPrefixUnchanged from DomainPrefixEvent (#13107)
This commit removes the `kDomainPrefixUnchanged` event from the
`DomainPrefixEvent` enum and refactors the related logic in
`BackboneRouter::Leader`. This value was redundant, as the manager
should only report events when an actual change (addition, removal,
or refresh) occurs in the Domain Prefix configuration.
2026-05-14 22:57:51 -07:00
Abtin Keshavarzian a84fc2e50b [message] introduce ReadAndAdvance() to simplify sequential parsing (#13106)
This commit introduces `Message::ReadAndAdvance()` and its template
flavor to the `Message` class. This helper method reads data from a
`Message` at a given `OffsetRange` and advances the `OffsetRange` by
the number of bytes read upon success.

Sequential parsing of structured data (such as TLVs or protocol
headers) is a common pattern across the OpenThread codebase.
Previously, this required two separate calls: one to `Read()` and
another to `AdvanceOffset()`. The new `ReadAndAdvance()` method
consolidates these into a single, safer operation that ensures the
offset is only advanced if the read operation succeeds.

This commit updates numerous call sites across the core stack
(MLE, BBR, DatasetManager, NetworkDiagnostic, DHCPv6, etc.) to use
the new helper, improving code clarity and reducing boilerplate.
2026-05-14 22:57:08 -07:00
Abtin Keshavarzian 27737f616e [tlv] remove unused Tlv::FindTlv() method variations (#13105)
This commit removes the legacy `Tlv::FindTlv()` method variations
that read a TLV into a local buffer. These methods are no longer
used across the codebase, having been replaced by safer and more
efficient alternatives such as `Tlv::Find<TlvType>()`,
`Tlv::FindTlvValueOffsetRange()`, or `Tlv::Info::FindIn()`.

The removed methods were prone to misuse, as they did not always
handle Extended TLVs correctly if the caller provided a fixed-size
buffer. Removing these variations forces new code to use the modern
helper functions, which provide better validation and correctly
handle the decoupling of the TLV header from its value.
2026-05-14 22:56:29 -07:00
Abtin Keshavarzian 181405efc9 [mle] introduce RouteTlv::Data to represent parsed Route TLV (#13098)
This commit introduces a new model for handling `RouteTlv` by
adding the `RouteTlv::Data` and `RouteTlv::Data::Entry` classes.
Previously, `RouteTlv` directly represented the packed on-wire
format, which made it difficult to work with, especially when
supporting different configurations such as
`OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE`.

The new `RouteTlv::Data` class decouples the on-wire serialization
from the in-memory representation, providing a cleaner API for
parsing the TLV from a `Message` and accessing its entries and
their properties (Router ID, Route Cost, and Link Qualities).

This change improves code clarity and maintainability by providing
a structured way to handle route information.
2026-05-14 11:17:37 -07:00
Jonathan Hui 83d334ce85 [posix] implement address labeling for mesh-local addresses (#13101)
Ideally, the mesh-local address (ML-EID) is only used when
communicating with devices in the Thread mesh. The mesh-local
address must not be used when communicating with other devices on
the infrastructure link or outside the Thread mesh.

This commit addresses this by implementing address labeling:
1. Modifying `UpdateUnicastLinux` in `src/posix/platform/netif.cpp`
   to stop marking mesh-local addresses as deprecated. They are now
   added as preferred addresses.
2. Implementing `AddAddressLabel` and `DeleteAddressLabel` to manage
   address labels via netlink (RTM_NEWADDRLABEL/RTM_DELADDRLABEL).
3. Calling `AddAddressLabel` when a mesh-local address is added to
   assign a specific label (99) to the Mesh-Local Prefix.

This ensures that the kernel prefers the ML-EID for destinations
sharing the same label (i.e., within the Thread mesh), while
avoiding its use for external traffic where other addresses with
standard labels would be a better match.

Issue: 8443
2026-05-14 11:11:13 -07:00
Stefan Agner 2cb137fabf [mesh-forwarder] lower log level on missing priority (#11062)
It seems that frames which are received through TREL do not have a
priority field. This creates quite some log noise when having notice log
level enabled. Lower this log entry to debug level.
2026-05-13 07:24:45 -07:00
Abtin Keshavarzian ddfd66526e [mlr] simplify multicast address state tracking (#13089)
This commit simplifies the tracking of Multicast Listener Registration
(MLR) state for IPv6 addresses by removing intermediate states and
relying on the original CoAP request payload.

Previously, `Mlr::Manager` used a 3-state system (`kStateToRegister`,
`kStateRegistering`, `kStateRegistered`) which required core structures
like `Child` and `Netif` to track transient registration states.

This commit reduces the state to a single boolean (`IsMlrRegistered`)
tracked in `ChildTable` and `ThreadNetif`. When a CoAP response is
received, `Mlr::Manager` now uses `GetDispatchingRequest()` to
retrieve the original TMR MLE request message, parses the
`Ip6AddressesTlv` to determine exactly which addresses were included
in the request, and updates the registration states based purely on
this info (minus any explicitly failed addresses).

This change improves robustness, reduces RAM usage by eliminating
state-tracking arrays, and significantly cleans up the logical flow
within the MLR manager.
2026-05-11 16:46:17 -07:00
Will Rosenberg 1f24ace91a [spinel] fix writeable size in spinel logging (#13094)
There exists a NULL-byte OOB in the spinel logging. The initial stack
buffer is initialized with an extra byte for the NULL-byte. However,
the full size is passed into `spinel_datatype_unpack_in_place()` which
interprets it as the valid writable size (`require_action(NULL !=
block_len_ptr && *block_len_ptr >= block_len, bail, (ret = -1, errno =
EINVAL));`).

When `block_len` is the length of the buffer, the NULL-byte write
after the function call will be OOB.
2026-05-11 11:26:31 -07:00
Abtin Keshavarzian 2a56b165c7 [mlr] extract AddressArray and add FindIn() to Ip6AddressesTlv (#13088)
This commit moves the `AddressArray` class out of the `Mlr::Manager`
and into a dedicated `mlr_types.hpp` file as `Mlr::AddressArray`. This
decouples the type from the manager, making it available for broader
use across the module.

Additionally, the logic for parsing the `Ip6AddressesTlv` is extracted
from `Mlr::Manager::ParseResponse()` into a new `FindIn()` method on
the TLV class itself. This centralizes the TLV parsing logic within
the TLV class, which is more idiomatic. The `FindIn()` method also
provides a safety guarantee by clearing the output `AddressArray` if
parsing fails.

The build system configurations (`BUILD.gn` and `CMakeLists.txt`) are
updated to include the newly added `mlr_types.cpp` file. Doxygen
documentation is also provided for the new types and methods.
2026-05-11 09:06:11 -07:00
Abtin Keshavarzian c650cede5a [coap] add mechanism to access request message in response handler (#13081)
This commit updates `CoapBase::PendingRequests` to track the request
currently being processed during callback invocation via the new
`mDispatchingRequest` pointer.

It also introduces `GetDispatchingRequest()` which returns a copy of
the original request `Message`. This enables response handler
callbacks to inspect the original request (for example to read
specific TLVs). The method is restricted to confirmable requests and
must only be called from within the context of a response handler.
The method `InvokeResponseHandler` is renamed to `DispatchResponse`
to align with the new nomenclature.
2026-05-11 09:05:46 -07:00
Jonathan Hui 0841be04fd [posix] detect and fail on unused radio URL parameters (#13087)
This commit enhances the radio URL parsing logic to detect and fail
when unused parameters are provided in the URL. This prevents typos
or unsupported parameters from being silently ignored.

The following changes were made:

- Updated ot::Url::Url to track parameter usage by appending a
  trailing '&' delimiter in Init() and replacing it with '\0'
  in GetValue() when a parameter is matched. This marks the
  parameter as used and removes any limit on the number of
  trackable parameters.
- Added a Validate() method to ot::Url::Url to verify that all
  parameters in the query string were accessed.
- Refactored ot::Posix::Radio to share a single RadioUrl instance
  with SpinelManager, ensuring all components track usage on the
  same URL object.
- Integrated Validate() calls in otSysInit() and platformTrelInit()
  to perform validation after all platform components have been
  initialized.
- Updated Radio::ProcessMaxPowerTable to use a local copy of the
  parameter string to avoid premature modification of the URL buffer.
- Adjusted RadioUrl and unit tests to provide sufficient buffer
  space for the additional tracking delimiter.
- Added new unit tests in tests/unit/test_url.cpp to verify the
  usage tracking and validation logic.
2026-05-09 10:04:07 -07:00
Abtin Keshavarzian 545a83efbf [mlr] remove CheckInvariants() method (#13082)
This commit removes the `CheckInvariants()` method and all its calls
from `Mlr::Manager`.

The `CheckInvariants()` method verified internal state consistency
by checking the `kStateRegistering` status of multicast addresses
against variables like `mPending` and `mSendDelay`. As the MLR module
is being prepared for upcoming structural updates, including changes
to how address states and delays are tracked, these specific invariant
checks are no longer applicable. Removing them clears the way for
the planned redesign of the MLR state machine.
2026-05-09 07:32:47 -07:00
Abtin Keshavarzian 294eb9a065 [mle] rate-limit scheduled discovery responses (#13086)
This commit introduces a cap on the number of concurrently scheduled
discovery responses in `Mle::DelayedSender`.

By adding the `CountMatchingSchedules()` method, we can now track how
many discovery responses are currently queued. The newly defined
constant `kMaxScheduledDiscoveryResponse` sets this limit to 16. If
the limit is reached, further `ScheduleDiscoveryResponse()` requests
are ignored.

This change protects the device from resource exhaustion (RAM, CPU,
and network) if it is flooded with discovery requests, preventing
potential Denial of Service (DoS) conditions.
2026-05-08 13:02:44 -07:00
Abtin Keshavarzian e6d9a13144 [border-router] add Deprecate() method in OnLinkPrefix (#13084)
This commit introduces the `Deprecate()` method in the `OnLinkPrefix`
class. This method properly deprecates an on-link prefix by setting
its preferred lifetime to zero and bounding the remaining valid
lifetime to a maximum of two hours from the current time.

Previously, `RxRaTracker` only called `ClearPreferredLifetime()`,
which left the valid lifetime unchanged. By replacing
`ClearPreferredLifetime()` with the new `Deprecate()` method, we
ensure that the valid lifetime of deprecated prefixes is also
bounded.

This change ensures that if a router is deemed unreachable, its
on-link prefixes will live for a maximum of 2 more hours. This
allows the state associated with an unreachable router to age out
more quickly, even if the router had previously advertised the on-link
prefix with long valid lifetime.
2026-05-08 13:02:15 -07:00