upmerge: merge up to commit 5cfbcfc

This commit is contained in:
Lukasz Maciejonczyk 2022-06-23 11:30:45 +02:00
commit 4881ea3910
181 changed files with 7878 additions and 3664 deletions

View File

@ -46,7 +46,7 @@ jobs:
REFERENCE_DEVICE: 1
VIRTUAL_TIME: 0
PACKET_VERIFICATION: 1
THREAD_VERSION: 1.2
THREAD_VERSION: 1.3
INTER_OP: 1
COVERAGE: 1
MULTIPLY: 1
@ -83,12 +83,12 @@ jobs:
sudo -E ./script/test cert_suite ./tests/scripts/thread-cert/backbone/*.py || (sudo chmod a+r *.log *.json *.pcap && false)
- uses: actions/upload-artifact@v2
with:
name: cov-thread-1-2-backbone-docker
name: cov-thread-1-3-backbone-docker
path: /tmp/coverage/
- uses: actions/upload-artifact@v2
if: ${{ failure() }}
with:
name: thread-1-2-backbone-results
name: thread-1-3-backbone-results
path: |
*.pcap
*.json
@ -100,7 +100,7 @@ jobs:
./script/test generate_coverage gcc
- uses: actions/upload-artifact@v2
with:
name: cov-thread-1-2-backbone
name: cov-thread-1-3-backbone
path: tmp/coverage.info
thread-border-router:
@ -144,7 +144,7 @@ jobs:
REFERENCE_DEVICE: 1
VIRTUAL_TIME: 0
PACKET_VERIFICATION: ${{ matrix.packet_verification }}
THREAD_VERSION: 1.2
THREAD_VERSION: 1.3
INTER_OP: 1
COVERAGE: 1
MULTIPLY: 1
@ -220,7 +220,7 @@ jobs:
script/test combine_coverage
- name: Upload Coverage
continue-on-error: true
uses: codecov/codecov-action@v1
uses: codecov/codecov-action@v2
with:
files: final.info
fail_ci_if_error: true

View File

@ -61,7 +61,7 @@ jobs:
- name: Build
run: |
./bootstrap
make -f examples/Makefile-simulation THREAD_VERSION=1.2 DUA=1 MLR=1 BACKBONE_ROUTER=1 CSL_RECEIVER=1
make -f examples/Makefile-simulation THREAD_VERSION=1.3 DUA=1 MLR=1 BACKBONE_ROUTER=1 CSL_RECEIVER=1
- name: Install OTCI Python Library
run: |
(cd tools/otci && python3 setup.py install --user)

View File

@ -293,7 +293,7 @@ jobs:
run: |
script/test combine_coverage
- name: Upload Coverage
uses: codecov/codecov-action@v1
uses: codecov/codecov-action@v2
with:
files: final.info
fail_ci_if_error: true

View File

@ -372,7 +372,7 @@ jobs:
run: |
script/test combine_coverage
- name: Upload Coverage
uses: codecov/codecov-action@v1
uses: codecov/codecov-action@v2
with:
files: final.info
fail_ci_if_error: true

View File

@ -26,7 +26,7 @@
# POSSIBILITY OF SUCH DAMAGE.
#
name: Simulation 1.2
name: Simulation 1.3
on: [push, pull_request]
@ -40,15 +40,15 @@ jobs:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
if: "github.ref != 'refs/heads/main'"
thread-1-2:
name: thread-1-2-${{ matrix.compiler.c }}-${{ matrix.arch }}
thread-1-3:
name: thread-1-3-${{ matrix.compiler.c }}-${{ matrix.arch }}
runs-on: ubuntu-20.04
env:
CFLAGS: -${{ matrix.arch }}
CXXFLAGS: -${{ matrix.arch }}
LDFLAGS: -${{ matrix.arch }}
COVERAGE: 1
THREAD_VERSION: 1.2
THREAD_VERSION: 1.3
VIRTUAL_TIME: 1
INTER_OP: 1
CC: ${{ matrix.compiler.c }}
@ -87,12 +87,12 @@ jobs:
- uses: actions/upload-artifact@v2
if: ${{ failure() }}
with:
name: thread-1-2-${{ matrix.compiler.c }}-${{ matrix.arch }}-pcaps
name: thread-1-3-${{ matrix.compiler.c }}-${{ matrix.arch }}-pcaps
path: "*.pcap"
- uses: actions/upload-artifact@v2
if: ${{ failure() && env.CRASHED == '1' }}
with:
name: core-packet-verification-thread-1-2
name: core-packet-verification-thread-1-3
path: |
./ot-core-dump/*
- name: Generate Coverage
@ -100,7 +100,7 @@ jobs:
./script/test generate_coverage "${{ matrix.compiler.gcov }}"
- uses: actions/upload-artifact@v2
with:
name: cov-thread-1-2-${{ matrix.compiler.c }}-${{ matrix.arch }}
name: cov-thread-1-3-${{ matrix.compiler.c }}-${{ matrix.arch }}
path: tmp/coverage.info
packet-verification-low-power:
@ -110,7 +110,7 @@ jobs:
VIRTUAL_TIME: 1
COVERAGE: 1
PACKET_VERIFICATION: 1
THREAD_VERSION: 1.2
THREAD_VERSION: 1.3
MAC_FILTER: 1
INTER_OP: 1
INTER_OP_BBR: 0
@ -164,13 +164,13 @@ jobs:
name: cov-packet-verification-low-power
path: tmp/coverage.info
packet-verification-1-1-on-1-2:
packet-verification-1-1-on-1-3:
runs-on: ubuntu-20.04
env:
REFERENCE_DEVICE: 1
VIRTUAL_TIME: 1
PACKET_VERIFICATION: 1
THREAD_VERSION: 1.2
THREAD_VERSION: 1.3
MULTIPLY: 3
steps:
- uses: actions/checkout@v2
@ -193,7 +193,7 @@ jobs:
- uses: actions/upload-artifact@v2
if: ${{ failure() }}
with:
name: packet-verification-1.1-on-1.2-pcaps
name: packet-verification-1.1-on-1.3-pcaps
path: |
*.pcap
*.json
@ -202,14 +202,14 @@ jobs:
./script/test generate_coverage gcc
- uses: actions/upload-artifact@v2
with:
name: cov-packet-verification-1-1-on-1-2
name: cov-packet-verification-1-1-on-1-3
path: tmp/coverage.info
expects:
runs-on: ubuntu-20.04
env:
COVERAGE: 1
THREAD_VERSION: 1.2
THREAD_VERSION: 1.3
VIRTUAL_TIME: 0
steps:
- uses: actions/checkout@v2
@ -232,7 +232,7 @@ jobs:
- uses: actions/upload-artifact@v2
if: ${{ failure() && env.CRASHED == '1' }}
with:
name: core-expect-1-2
name: core-expect-1-3
path: |
./ot-core-dump/*
- name: Generate Coverage
@ -243,13 +243,13 @@ jobs:
name: cov-expects
path: tmp/coverage.info
thread-1-2-posix:
thread-1-3-posix:
runs-on: ubuntu-20.04
env:
COVERAGE: 1
PYTHONUNBUFFERED: 1
READLINE: readline
THREAD_VERSION: 1.2
THREAD_VERSION: 1.3
OT_NODE_TYPE: rcp
USE_MTD: 1
VIRTUAL_TIME: 1
@ -285,12 +285,12 @@ jobs:
- uses: actions/upload-artifact@v2
if: ${{ failure() }}
with:
name: thread-1-2-posix-pcaps
name: thread-1-3-posix-pcaps
path: "*.pcap"
- uses: actions/upload-artifact@v2
if: ${{ failure() && env.CRASHED == '1' }}
with:
name: core-thread-1-2-posix
name: core-thread-1-3-posix
path: |
./ot-core-dump/*
- name: Generate Coverage
@ -298,16 +298,16 @@ jobs:
./script/test generate_coverage gcc
- uses: actions/upload-artifact@v2
with:
name: cov-thread-1-2-posix
name: cov-thread-1-3-posix
path: tmp/coverage.info
upload-coverage:
needs:
- thread-1-2
- thread-1-3
- packet-verification-low-power
- packet-verification-1-1-on-1-2
- packet-verification-1-1-on-1-3
- expects
- thread-1-2-posix
- thread-1-3-posix
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
@ -323,7 +323,7 @@ jobs:
run: |
script/test combine_coverage
- name: Upload Coverage
uses: codecov/codecov-action@v1
uses: codecov/codecov-action@v2
with:
files: final.info
fail_ci_if_error: true

View File

@ -139,7 +139,7 @@ jobs:
run: |
script/test combine_coverage
- name: Upload Coverage
uses: codecov/codecov-action@v1
uses: codecov/codecov-action@v2
with:
files: final.info
fail_ci_if_error: true

View File

@ -220,8 +220,7 @@ LOCAL_SRC_FILES := \
src/core/backbone_router/bbr_manager.cpp \
src/core/backbone_router/multicast_listeners_table.cpp \
src/core/backbone_router/ndproxy_table.cpp \
src/core/border_router/infra_if_platform.cpp \
src/core/border_router/router_advertisement.cpp \
src/core/border_router/infra_if.cpp \
src/core/border_router/routing_manager.cpp \
src/core/coap/coap.cpp \
src/core/coap/coap_message.cpp \
@ -303,6 +302,7 @@ LOCAL_SRC_FILES := \
src/core/net/ip6_filter.cpp \
src/core/net/ip6_headers.cpp \
src/core/net/ip6_mpl.cpp \
src/core/net/nd6.cpp \
src/core/net/nd_agent.cpp \
src/core/net/netif.cpp \
src/core/net/sntp_client.cpp \

View File

@ -102,12 +102,14 @@ if(OT_PACKAGE_VERSION STREQUAL "")
endif()
message(STATUS "Package Version: ${OT_PACKAGE_VERSION}")
set(OT_THREAD_VERSION "1.2" CACHE STRING "Thread version chosen by the user at configure time")
set_property(CACHE OT_THREAD_VERSION PROPERTY STRINGS "1.1" "1.2")
set(OT_THREAD_VERSION "1.3" CACHE STRING "Thread version chosen by the user at configure time")
set_property(CACHE OT_THREAD_VERSION PROPERTY STRINGS "1.1" "1.2" "1.3")
if(${OT_THREAD_VERSION} EQUAL "1.1")
target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_THREAD_VERSION=OT_THREAD_VERSION_1_1")
elseif(${OT_THREAD_VERSION} EQUAL "1.2")
target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_THREAD_VERSION=OT_THREAD_VERSION_1_2")
elseif(${OT_THREAD_VERSION} EQUAL "1.3")
target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_THREAD_VERSION=OT_THREAD_VERSION_1_3")
else()
message(FATAL_ERROR "Thread version unknown: ${OT_THREAD_VERSION}")
endif()

View File

@ -59,7 +59,16 @@
* @defgroup api-ip6 IPv6
* @defgroup api-srp SRP
* @defgroup api-ping-sender Ping Sender
*
* @defgroup api-tcp-group TCP
*
* @{
*
* @defgroup api-tcp TCP
* @defgroup api-tcp-ext TCP Abstractions
*
* @}
*
* @defgroup api-udp-group UDP
*
* @{

View File

@ -360,6 +360,11 @@ if (OT_TREL)
target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE=1")
endif()
option(OT_TX_BEACON_PAYLOAD "enable Thread beacon payload in outgoing beacons")
if (OT_TX_BEACON_PAYLOAD)
target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_MAC_OUTGOING_BEACON_PAYLOAD_ENABLE=1")
endif()
option(OT_UDP_FORWARD "enable UDP forward support")
if(OT_UDP_FORWARD)
target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE=1")

View File

@ -37,13 +37,17 @@ if(NOT DEFINED OT_PLATFORM_LIB_RCP)
set(OT_PLATFORM_LIB_RCP ${OT_PLATFORM_LIB})
endif()
if(NOT DEFINED OT_MBEDTLS_RCP)
set(OT_MBEDTLS_RCP ${OT_MBEDTLS})
endif()
target_link_libraries(ot-cli-radio PRIVATE
openthread-cli-radio
${OT_PLATFORM_LIB_RCP}
openthread-radio-cli
${OT_PLATFORM_LIB_RCP}
openthread-cli-radio
${OT_MBEDTLS}
${OT_MBEDTLS_RCP}
ot-config
)

View File

@ -86,7 +86,7 @@ SLAAC ?= 1
SNTP_CLIENT ?= 0
SRP_CLIENT ?= 0
SRP_SERVER ?= 0
THREAD_VERSION ?= 1.2
THREAD_VERSION ?= 1.3
TIME_SYNC ?= 0
TREL ?= 0
UDP_FORWARD ?= 0
@ -333,6 +333,8 @@ ifeq ($(THREAD_VERSION),1.1)
COMMONCFLAGS += -DOPENTHREAD_CONFIG_THREAD_VERSION=2
else ifeq ($(THREAD_VERSION),1.2)
COMMONCFLAGS += -DOPENTHREAD_CONFIG_THREAD_VERSION=3
else ifeq ($(THREAD_VERSION),1.3)
COMMONCFLAGS += -DOPENTHREAD_CONFIG_THREAD_VERSION=4
endif
ifeq ($(TIME_SYNC),1)

View File

@ -163,10 +163,11 @@ void platformRadioReceive(otInstance *aInstance, uint8_t *aBuf, uint16_t aBufLen
*
* @param[in,out] aReadFdSet A pointer to the read file descriptors.
* @param[in,out] aWriteFdSet A pointer to the write file descriptors.
* @param[in,out] aTimeout A pointer to the timeout.
* @param[in,out] aMaxFd A pointer to the max file descriptor.
*
*/
void platformRadioUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, int *aMaxFd);
void platformRadioUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, struct timeval *aTimeout, int *aMaxFd);
/**
* This function performs radio driver processing.

View File

@ -29,6 +29,7 @@
#include "platform-simulation.h"
#include <errno.h>
#include <sys/time.h>
#include <openthread/dataset.h>
#include <openthread/link.h>
@ -47,6 +48,9 @@
// The IPv4 group for receiving packets of radio simulation
#define OT_RADIO_GROUP "224.0.0.116"
#define MS_PER_S 1000
#define US_PER_MS 1000
enum
{
IEEE802154_ACK_LENGTH = 5,
@ -75,6 +79,10 @@ static uint16_t sPortOffset = 0;
static uint16_t sPort = 0;
#endif
static int8_t sEnergyScanResult = OT_RADIO_RSSI_INVALID;
static bool sEnergyScanning = false;
static uint32_t sEnergyScanEndTime = 0;
enum
{
SIM_RADIO_CHANNEL_MIN = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN,
@ -156,6 +164,13 @@ static otMacKeyMaterial sCurrKey;
static otMacKeyMaterial sNextKey;
static otRadioKeyType sKeyType;
static int8_t GetRssi(uint16_t aChannel);
static bool IsTimeAfterOrEqual(uint32_t aTimeA, uint32_t aTimeB)
{
return (aTimeA - aTimeB) < (1U << 31);
}
static void ReverseExtAddress(otExtAddress *aReversed, const otExtAddress *aOrigin)
{
for (size_t i = 0; i < sizeof(*aReversed); i++)
@ -493,20 +508,23 @@ otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
int8_t otPlatRadioGetRssi(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
assert(aInstance != NULL);
int8_t rssi = SIM_LOW_RSSI_SAMPLE;
uint8_t channel = sReceiveFrame.mChannel;
return GetRssi(sReceiveFrame.mChannel);
}
static int8_t GetRssi(uint16_t aChannel)
{
int8_t rssi = SIM_LOW_RSSI_SAMPLE;
uint32_t probabilityThreshold;
otEXPECT((SIM_RADIO_CHANNEL_MIN <= channel) && channel <= (SIM_RADIO_CHANNEL_MAX));
otEXPECT((SIM_RADIO_CHANNEL_MIN <= aChannel) && aChannel <= (SIM_RADIO_CHANNEL_MAX));
// To emulate a simple interference model, we return either a high or
// a low RSSI value with a fixed probability per each channel. The
// probability is increased per channel by a constant.
probabilityThreshold = (channel - SIM_RADIO_CHANNEL_MIN) * SIM_HIGH_RSSI_PROB_INC_PER_CHANNEL;
probabilityThreshold = (aChannel - SIM_RADIO_CHANNEL_MIN) * SIM_HIGH_RSSI_PROB_INC_PER_CHANNEL;
if (otRandomNonCryptoGetUint16() < (probabilityThreshold * 0xffff / 100))
{
@ -736,7 +754,7 @@ void platformRadioReceive(otInstance *aInstance, uint8_t *aBuf, uint16_t aBufLen
radioReceive(aInstance);
}
#else
void platformRadioUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, int *aMaxFd)
void platformRadioUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, struct timeval *aTimeout, int *aMaxFd)
{
if (aReadFdSet != NULL && (sState != OT_RADIO_STATE_TRANSMIT || sTxWait))
{
@ -757,6 +775,25 @@ void platformRadioUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, int *aMax
*aMaxFd = sTxFd;
}
}
if (sEnergyScanning)
{
struct timeval tv = {0, 0};
uint32_t now = otPlatAlarmMilliGetNow();
if (IsTimeAfterOrEqual(sEnergyScanEndTime, now))
{
uint32_t remaining = sEnergyScanEndTime - now;
tv.tv_sec = remaining / MS_PER_S;
tv.tv_usec = (remaining % MS_PER_S) * US_PER_MS;
}
if (timercmp(&tv, aTimeout, <))
{
*aTimeout = tv;
}
}
}
// no need to close in virtual time mode.
@ -811,11 +848,16 @@ void platformRadioProcess(otInstance *aInstance, const fd_set *aReadFdSet, const
}
}
#endif
if (platformRadioIsTransmitPending())
{
radioSendMessage(aInstance);
}
if (sEnergyScanning && IsTimeAfterOrEqual(otPlatAlarmMilliGetNow(), sEnergyScanEndTime))
{
sEnergyScanning = false;
otPlatRadioEnergyScanDone(aInstance, sEnergyScanResult);
}
}
void radioTransmit(struct RadioMessage *aMessage, const struct otRadioFrame *aFrame)
@ -982,13 +1024,22 @@ otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint1
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aScanChannel);
OT_UNUSED_VARIABLE(aScanDuration);
otError error = OT_ERROR_NONE;
assert(aInstance != NULL);
assert(aScanChannel >= SIM_RADIO_CHANNEL_MIN && aScanChannel <= SIM_RADIO_CHANNEL_MAX);
assert(aScanDuration > 0);
return OT_ERROR_NOT_IMPLEMENTED;
otEXPECT_ACTION((gRadioCaps & OT_RADIO_CAPS_ENERGY_SCAN), error = OT_ERROR_NOT_IMPLEMENTED);
otEXPECT_ACTION(!sEnergyScanning, error = OT_ERROR_BUSY);
sEnergyScanResult = GetRssi(aScanChannel);
sEnergyScanning = true;
sEnergyScanEndTime = otPlatAlarmMilliGetNow() + aScanDuration;
exit:
return error;
}
otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower)

View File

@ -70,10 +70,11 @@ static void handleSignal(int aSignal)
*/
enum
{
OT_SIM_OPT_HELP = 'h',
OT_SIM_OPT_SLEEP_TO_TX = 't',
OT_SIM_OPT_TIME_SPEED = 's',
OT_SIM_OPT_UNKNOWN = '?',
OT_SIM_OPT_HELP = 'h',
OT_SIM_OPT_ENABLE_ENERGY_SCAN = 'E',
OT_SIM_OPT_SLEEP_TO_TX = 't',
OT_SIM_OPT_TIME_SPEED = 's',
OT_SIM_OPT_UNKNOWN = '?',
};
static void PrintUsage(const char *aProgramName, int aExitCode)
@ -82,9 +83,10 @@ static void PrintUsage(const char *aProgramName, int aExitCode)
"Syntax:\n"
" %s [Options] NodeId\n"
"Options:\n"
" -h --help Display this usage information.\n"
" -t --sleep-to-tx Let radio support direct transition from sleep to TX with CSMA.\n"
" -s --time-speed=val Speed up the time in simulation.\n",
" -h --help Display this usage information.\n"
" -E --enable-energy-scan Enable energy scan capability.\n"
" -t --sleep-to-tx Let radio support direct transition from sleep to TX with CSMA.\n"
" -s --time-speed=val Speed up the time in simulation.\n",
aProgramName);
exit(aExitCode);
@ -97,6 +99,7 @@ void otSysInit(int aArgCount, char *aArgVector[])
static const struct option long_options[] = {
{"help", no_argument, 0, OT_SIM_OPT_HELP},
{"enable-energy-scan", no_argument, 0, OT_SIM_OPT_SLEEP_TO_TX},
{"sleep-to-tx", no_argument, 0, OT_SIM_OPT_SLEEP_TO_TX},
{"time-speed", required_argument, 0, OT_SIM_OPT_TIME_SPEED},
{0, 0, 0, 0},
@ -112,7 +115,7 @@ void otSysInit(int aArgCount, char *aArgVector[])
while (true)
{
int c = getopt_long(aArgCount, aArgVector, "hts:", long_options, NULL);
int c = getopt_long(aArgCount, aArgVector, "Ehts:", long_options, NULL);
if (c == -1)
{
@ -127,6 +130,9 @@ void otSysInit(int aArgCount, char *aArgVector[])
case OT_SIM_OPT_HELP:
PrintUsage(aArgVector[0], EXIT_SUCCESS);
break;
case OT_SIM_OPT_ENABLE_ENERGY_SCAN:
gRadioCaps |= OT_RADIO_CAPS_ENERGY_SCAN;
break;
case OT_SIM_OPT_SLEEP_TO_TX:
gRadioCaps |= OT_RADIO_CAPS_SLEEP_TO_TX;
break;
@ -197,8 +203,8 @@ void otSysProcessDrivers(otInstance *aInstance)
FD_ZERO(&error_fds);
platformUartUpdateFdSet(&read_fds, &write_fds, &error_fds, &max_fd);
platformRadioUpdateFdSet(&read_fds, &write_fds, &max_fd);
platformAlarmUpdateTimeout(&timeout);
platformRadioUpdateFdSet(&read_fds, &write_fds, &timeout, &max_fd);
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
platformTrelUpdateFdSet(&read_fds, &write_fds, &timeout, &max_fd);
#endif

View File

@ -213,6 +213,17 @@ typedef struct otOperationalDatasetComponents
bool mIsChannelMaskPresent : 1; ///< TRUE if Channel Mask is present, FALSE otherwise.
} otOperationalDatasetComponents;
/**
* This structure represents a Thread Dataset timestamp component.
*
*/
typedef struct otTimestamp
{
uint64_t mSeconds;
uint16_t mTicks;
bool mAuthoritative;
} otTimestamp;
/**
* This structure represents an Active or Pending Operational Dataset.
*
@ -221,8 +232,8 @@ typedef struct otOperationalDatasetComponents
*/
typedef struct otOperationalDataset
{
uint64_t mActiveTimestamp; ///< Active Timestamp
uint64_t mPendingTimestamp; ///< Pending Timestamp
otTimestamp mActiveTimestamp; ///< Active Timestamp
otTimestamp mPendingTimestamp; ///< Pending Timestamp
otNetworkKey mNetworkKey; ///< Network Key
otNetworkName mNetworkName; ///< Network Name
otExtendedPanId mExtendedPanId; ///< Extended PAN ID

View File

@ -147,6 +147,22 @@ typedef enum
OT_DNSSD_QUERY_TYPE_RESOLVE_HOST = 3, ///< Service type resolve hostname.
} otDnssdQueryType;
/**
* This structure contains the counters of DNS-SD server.
*
*/
typedef struct otDnssdCounters
{
uint32_t mSuccessResponse; ///< The number of successful responses
uint32_t mServerFailureResponse; ///< The number of server failure responses
uint32_t mFormatErrorResponse; ///< The number of format error responses
uint32_t mNameErrorResponse; ///< The number of name error responses
uint32_t mNotImplementedResponse; ///< The number of 'not implemented' responses
uint32_t mOtherResponse; ///< The number of other responses
uint32_t mResolvedBySrp; ///< The number of queries completely resolved by the local SRP server
} otDnssdCounters;
/**
* This function sets DNS-SD server query callbacks.
*
@ -219,6 +235,16 @@ const otDnssdQuery *otDnssdGetNextQuery(otInstance *aInstance, const otDnssdQuer
*/
otDnssdQueryType otDnssdGetQueryTypeAndName(const otDnssdQuery *aQuery, char (*aNameOutput)[OT_DNS_MAX_NAME_SIZE]);
/**
* This function returns the counters of the DNS-SD server.
*
* @param[in] aInstance The OpenThread instance structure.
*
* @returns A pointer to the counters of the DNS-SD server.
*
*/
const otDnssdCounters *otDnssdGetCounters(otInstance *aInstance);
/**
* @}
*

View File

@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (207)
#define OPENTHREAD_API_VERSION (220)
/**
* @addtogroup api-instance

View File

@ -391,6 +391,10 @@ typedef struct otActiveScanResult
unsigned int mVersion : 4; ///< Version
bool mIsNative : 1; ///< Native Commissioner flag
bool mDiscover : 1; ///< Result from MLE Discovery
// Applicable/Required only when beacon payload parsing feature
// (`OPENTHREAD_CONFIG_MAC_BEACON_PAYLOAD_PARSING_ENABLE`) is enabled.
bool mIsJoinable : 1; ///< Joining Permitted flag
} otActiveScanResult;
/**
@ -486,7 +490,6 @@ bool otLinkIsEnergyScanInProgress(otInstance *aInstance);
* @param[in] aInstance A pointer to an OpenThread instance.
*
* @retval OT_ERROR_NONE Successfully enqueued an IEEE 802.15.4 Data Request message.
* @retval OT_ERROR_ALREADY An IEEE 802.15.4 Data Request message is already enqueued.
* @retval OT_ERROR_INVALID_STATE Device is not in rx-off-when-idle mode.
* @retval OT_ERROR_NO_BUFS Insufficient message buffers available.
*

View File

@ -236,6 +236,7 @@ typedef void (*otLinkRawEnergyScanDone)(otInstance *aInstance, int8_t aEnergySca
* @param[in] aCallback A pointer to a function called on completion of a scanned channel.
*
* @retval OT_ERROR_NONE Successfully started scanning the channel.
* @retval OT_ERROR_BUSY The radio is performing enery scanning.
* @retval OT_ERROR_NOT_IMPLEMENTED The radio doesn't support energy scanning.
* @retval OT_ERROR_INVALID_STATE If the raw link-layer isn't enabled.
*

View File

@ -192,12 +192,18 @@ void otNetDataUnpublishDnsSrpService(otInstance *aInstance);
*
* Only stable entries can be published (i.e.,`aConfig.mStable` MUST be TRUE).
*
* A subsequent call to this method will replace a previous request for the same prefix. In particular, if the new call
* only changes the flags (e.g., preference level) and the prefix is already added in the Network Data, the change to
* flags is immediately reflected in the Network Data. This ensures that existing entries in the Network Data are not
* abruptly removed. Note that a change in the preference level can potentially later cause the entry to be removed
* from the Network Data after determining there are other nodes that are publishing the same prefix with the same or
* higher preference.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aConfig The on-mesh prefix config to publish (MUST NOT be NULL).
*
* @retval OT_ERROR_NONE The on-mesh prefix is published successfully.
* @retval OT_ERROR_INVALID_ARGS The @p aConfig is not valid (bad prefix, invalid flag combinations, or not stable).
* @retval OT_ERROR_ALREADY An entry with the same prefix is already in the published list.
* @retval OT_ERROR_NO_BUFS Could not allocate an entry for the new request. Publisher supports a limited number
* of entries (shared between on-mesh prefix and external route) determined by config
* `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES`.
@ -213,12 +219,18 @@ otError otNetDataPublishOnMeshPrefix(otInstance *aInstance, const otBorderRouter
*
* Only stable entries can be published (i.e.,`aConfig.mStable` MUST be TRUE).
*
* A subsequent call to this method will replace a previous request for the same prefix. In particular, if the new call
* only changes the flags (e.g., preference level) and the prefix is already added in the Network Data, the change to
* flags is immediately reflected in the Network Data. This ensures that existing entries in the Network Data are not
* abruptly removed. Note that a change in the preference level can potentially later cause the entry to be removed
* from the Network Data after determining there are other nodes that are publishing the same prefix with the same or
* higher preference.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aConfig The external route config to publish (MUST NOT be NULL).
*
* @retval OT_ERROR_NONE The external route is published successfully.
* @retval OT_ERROR_INVALID_ARGS The @p aConfig is not valid (bad prefix, invalid flag combinations, or not stable).
* @retval OT_ERROR_ALREADY An entry with the same prefix is already in the published list.
* @retval OT_ERROR_NO_BUFS Could not allocate an entry for the new request. Publisher supports a limited number
* of entries (shared between on-mesh prefix and external route) determined by config
* `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES`.

View File

@ -857,6 +857,7 @@ int8_t otPlatRadioGetRssi(otInstance *aInstance);
* @param[in] aScanDuration The duration, in milliseconds, for the channel to be scanned.
*
* @retval OT_ERROR_NONE Successfully started scanning the channel.
* @retval OT_ERROR_BUSY The radio is performing enery scanning.
* @retval OT_ERROR_NOT_IMPLEMENTED The radio doesn't support energy scanning.
*
*/

View File

@ -55,7 +55,8 @@ extern "C" {
* This enumeration defines the keys of settings.
*
* Note: When adding a new settings key, if the settings corresponding to the key contains security sensitive
* information, the developer MUST add the key to the array `kSensitiveKeys`.
* information, the developer MUST add the key to the array `aSensitiveKeys` which is passed in
* `otPlatSettingsInit()`.
*
*/
enum
@ -65,17 +66,20 @@ enum
OT_SETTINGS_KEY_NETWORK_INFO = 0x0003, ///< Thread network information.
OT_SETTINGS_KEY_PARENT_INFO = 0x0004, ///< Parent information.
OT_SETTINGS_KEY_CHILD_INFO = 0x0005, ///< Child information.
OT_SETTINGS_KEY_RESERVED = 0x0006, ///< Reserved (previously auto-start).
OT_SETTINGS_KEY_SLAAC_IID_SECRET_KEY = 0x0007, ///< SLAAC key to generate semantically opaque IID.
OT_SETTINGS_KEY_DAD_INFO = 0x0008, ///< Duplicate Address Detection (DAD) information.
OT_SETTINGS_KEY_LEGACY_OMR_PREFIX = 0x0009, ///< Reserved. Legacy Off-mesh routable (OMR) prefix.
OT_SETTINGS_KEY_ON_LINK_PREFIX = 0x000a, ///< On-link prefix for infrastructure link.
OT_SETTINGS_KEY_SRP_ECDSA_KEY = 0x000b, ///< SRP client ECDSA public/private key pair.
OT_SETTINGS_KEY_SRP_CLIENT_INFO = 0x000c, ///< The SRP client info (selected SRP server address).
OT_SETTINGS_KEY_SRP_SERVER_INFO = 0x000d, ///< The SRP server info (UDP port).
OT_SETTINGS_KEY_LEGACY_NAT64_PREFIX = 0x000e, ///< Reserved. Legacy NAT64 prefix.
OT_SETTINGS_KEY_BR_ULA_PREFIX = 0x000f, ///< BR ULA prefix.
// Deprecated and reserved key values:
//
// 0x0006 previously auto-start.
// 0x0009 previously OMR prefix.
// 0x000a previously on-link prefix.
// 0x000e previously NAT64 prefix.
// Keys in range 0x8000-0xffff are reserved for vendor-specific use.
OT_SETTINGS_KEY_VENDOR_RESERVED_MIN = 0x8000,
OT_SETTINGS_KEY_VENDOR_RESERVED_MAX = 0xffff,
@ -104,80 +108,100 @@ void otPlatSettingsInit(otInstance *aInstance, const uint16_t *aSensitiveKeys, u
*/
void otPlatSettingsDeinit(otInstance *aInstance);
/// Fetches the value of a setting
/** This function fetches the value of the setting identified
* by aKey and write it to the memory pointed to by aValue.
* It then writes the length to the integer pointed to by
* aValueLength. The initial value of aValueLength is the
* maximum number of bytes to be written to aValue.
/**
* Fetches the value of a setting.
*
* This function can be used to check for the existence of
* a key without fetching the value by setting aValue and
* aValueLength to NULL. You can also check the length of
* the setting without fetching it by setting only aValue
* to NULL.
* This function fetches the value of the setting identified
* by @p aKey and write it to the memory pointed to by aValue.
* It then writes the length to the integer pointed to by
* @p aValueLength. The initial value of @p aValueLength is the
* maximum number of bytes to be written to @p aValue.
*
* Note that the underlying storage implementation is not
* required to maintain the order of settings with multiple
* values. The order of such values MAY change after ANY
* write operation to the store.
* This function can be used to check for the existence of
* a key without fetching the value by setting @p aValue and
* @p aValueLength to NULL. You can also check the length of
* the setting without fetching it by setting only aValue
* to NULL.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aKey The key associated with the requested setting.
* @param[in] aIndex The index of the specific item to get.
* @param[out] aValue A pointer to where the value of the setting should be written. May be set to NULL if
* just testing for the presence or length of a setting.
* @param[in,out] aValueLength A pointer to the length of the value. When called, this pointer should point to an
* integer containing the maximum value size that can be written to aValue. At return,
* the actual length of the setting is written. This may be set to NULL if performing
* a presence check.
* Note that the underlying storage implementation is not
* required to maintain the order of settings with multiple
* values. The order of such values MAY change after ANY
* write operation to the store.
*
* @retval OT_ERROR_NONE The given setting was found and fetched successfully.
* @retval OT_ERROR_NOT_FOUND The given setting was not found in the setting store.
* @retval OT_ERROR_NOT_IMPLEMENTED This function is not implemented on this platform.
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aKey The key associated with the requested setting.
* @param[in] aIndex The index of the specific item to get.
* @param[out] aValue A pointer to where the value of the setting should be written. May be set to NULL if
* just testing for the presence or length of a setting.
* @param[in,out] aValueLength A pointer to the length of the value. When called, this pointer should point to an
* integer containing the maximum value size that can be written to @p aValue. At return,
* the actual length of the setting is written. This may be set to NULL if performing
* a presence check.
*
* @retval OT_ERROR_NONE The given setting was found and fetched successfully.
* @retval OT_ERROR_NOT_FOUND The given setting was not found in the setting store.
* @retval OT_ERROR_NOT_IMPLEMENTED This function is not implemented on this platform.
*/
otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength);
/// Sets or replaces the value of a setting
/** This function sets or replaces the value of a setting
* identified by aKey. If there was more than one
* value previously associated with aKey, then they are
* all deleted and replaced with this single entry.
/**
* Sets or replaces the value of a setting.
*
* Calling this function successfully may cause unrelated
* settings with multiple values to be reordered.
* This function sets or replaces the value of a setting
* identified by @p aKey.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aKey The key associated with the setting to change.
* @param[in] aValue A pointer to where the new value of the setting should be read from. MUST NOT be NULL if
* aValueLength is non-zero.
* @param[in] aValueLength The length of the data pointed to by aValue. May be zero.
* Calling this function successfully may cause unrelated
* settings with multiple values to be reordered.
*
* @retval OT_ERROR_NONE The given setting was changed or staged.
* @retval OT_ERROR_NOT_IMPLEMENTED This function is not implemented on this platform.
* @retval OT_ERROR_NO_BUFS No space remaining to store the given setting.
* OpenThread stack guarantees to use `otPlatSettingsSet()`
* method for a @p aKey that was either previously set using
* `otPlatSettingsSet()` (i.e., contains a single value) or
* is empty and/or fully deleted (contains no value).
*
* Platform layer can rely and use this fact for optimizing
* its implementation.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aKey The key associated with the setting to change.
* @param[in] aValue A pointer to where the new value of the setting should be read from. MUST NOT be NULL if
* @p aValueLength is non-zero.
* @param[in] aValueLength The length of the data pointed to by aValue. May be zero.
*
* @retval OT_ERROR_NONE The given setting was changed or staged.
* @retval OT_ERROR_NOT_IMPLEMENTED This function is not implemented on this platform.
* @retval OT_ERROR_NO_BUFS No space remaining to store the given setting.
*/
otError otPlatSettingsSet(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength);
/// Adds a value to a setting
/** This function adds the value to a setting
* identified by aKey, without replacing any existing
* values.
/**
* Adds a value to a setting.
*
* Note that the underlying implementation is not required
* to maintain the order of the items associated with a
* specific key. The added value may be added to the end,
* the beginning, or even somewhere in the middle. The order
* of any pre-existing values may also change.
* This function adds the value to a setting
* identified by @p aKey, without replacing any existing
* values.
*
* Calling this function successfully may cause unrelated
* settings with multiple values to be reordered.
* Note that the underlying implementation is not required
* to maintain the order of the items associated with a
* specific key. The added value may be added to the end,
* the beginning, or even somewhere in the middle. The order
* of any pre-existing values may also change.
*
* Calling this function successfully may cause unrelated
* settings with multiple values to be reordered.
*
* OpenThread stack guarantees to use `otPlatSettingsAdd()`
* method for a @p aKey that was either previously managed by
* `otPlatSettingsAdd()` (i.e., contains one or more items) or
* is empty and/or fully deleted (contains no value).
*
* Platform layer can rely and use this fact for optimizing
* its implementation.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aKey The key associated with the setting to change.
* @param[in] aValue A pointer to where the new value of the setting should be read from. MUST NOT be NULL
* if aValueLength is non-zero.
* @param[in] aValueLength The length of the data pointed to by aValue. May be zero.
* if @p aValueLength is non-zero.
* @param[in] aValueLength The length of the data pointed to by @p aValue. May be zero.
*
* @retval OT_ERROR_NONE The given setting was added or staged to be added.
* @retval OT_ERROR_NOT_IMPLEMENTED This function is not implemented on this platform.
@ -185,29 +209,34 @@ otError otPlatSettingsSet(otInstance *aInstance, uint16_t aKey, const uint8_t *a
*/
otError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength);
/// Removes a setting from the setting store
/** This function deletes a specific value from the
* setting identified by aKey from the settings store.
/**
* Removes a setting from the setting store.
*
* Note that the underlying implementation is not required
* to maintain the order of the items associated with a
* specific key.
* This function deletes a specific value from the
* setting identified by aKey from the settings store.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aKey The key associated with the requested setting.
* @param[in] aIndex The index of the value to be removed. If set to -1, all values for this aKey will be removed.
* Note that the underlying implementation is not required
* to maintain the order of the items associated with a
* specific key.
*
* @retval OT_ERROR_NONE The given key and index was found and removed successfully.
* @retval OT_ERROR_NOT_FOUND The given key or index was not found in the setting store.
* @retval OT_ERROR_NOT_IMPLEMENTED This function is not implemented on this platform.
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aKey The key associated with the requested setting.
* @param[in] aIndex The index of the value to be removed. If set to -1, all values for this @p aKey will be
* removed.
*
* @retval OT_ERROR_NONE The given key and index was found and removed successfully.
* @retval OT_ERROR_NOT_FOUND The given key or index was not found in the setting store.
* @retval OT_ERROR_NOT_IMPLEMENTED This function is not implemented on this platform.
*/
otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex);
/// Removes all settings from the setting store
/** This function deletes all settings from the settings
* store, resetting it to its initial factory state.
/**
* Removes all settings from the setting store.
*
* @param[in] aInstance The OpenThread instance structure.
* This function deletes all settings from the settings
* store, resetting it to its initial factory state.
*
* @param[in] aInstance The OpenThread instance structure.
*/
void otPlatSettingsWipe(otInstance *aInstance);

View File

@ -75,8 +75,9 @@ typedef enum
typedef struct otSrpClientHostInfo
{
const char * mName; ///< Host name (label) string (NULL if not yet set).
const otIp6Address * mAddresses; ///< Pointer to an array of host IPv6 addresses (NULL if not yet set).
const otIp6Address * mAddresses; ///< Array of host IPv6 addresses (NULL if not set or auto address is enabled).
uint8_t mNumAddresses; ///< Number of IPv6 addresses in `mAddresses` array.
bool mAutoAddress; ///< Indicates whether auto address mode is enabled or not.
otSrpClientItemState mState; ///< Host info state.
} otSrpClientHostInfo;
@ -315,6 +316,34 @@ void otSrpClientDisableAutoStartMode(otInstance *aInstance);
*/
bool otSrpClientIsAutoStartModeEnabled(otInstance *aInstance);
/**
* This function gets the TTL value in every record included in SRP update requests.
*
* Note that this is the TTL requested by the SRP client. The server may choose to accept a different TTL.
*
* By default, the TTL will equal the lease interval. Passing 0 or a value larger than the lease interval via
* `otSrpClientSetTtl()` will also cause the TTL to equal the lease interval.
*
* @param[in] aInstance A pointer to the OpenThread instance.
*
* @returns The TTL (in seconds).
*
*/
uint32_t otSrpClientGetTtl(otInstance *aInstance);
/**
* This function sets the TTL value in every record included in SRP update requests.
*
* Changing the TTL does not impact the TTL of already registered services/host-info.
* It only affects future SRP update messages (i.e., adding new services and/or refreshes of the existing services).
*
* @param[in] aInstance A pointer to the OpenThread instance.
* @param[in] aTtl The TTL (in seconds). If value is zero or greater than lease interval, the TTL is set to the
* lease interval.
*
*/
void otSrpClientSetTtl(otInstance *aInstance, uint32_t aTtl);
/**
* This function gets the lease interval used in SRP update requests.
*
@ -400,6 +429,27 @@ const otSrpClientHostInfo *otSrpClientGetHostInfo(otInstance *aInstance);
*/
otError otSrpClientSetHostName(otInstance *aInstance, const char *aName);
/**
* This function enables auto host address mode.
*
* When enabled host IPv6 addresses are automatically set by SRP client using all the unicast addresses on Thread netif
* excluding all link-local and mesh-local addresses. If there is no valid address, then Mesh Local EID address is
* added. The SRP client will automatically re-register when/if addresses on Thread netif are updated (new addresses
* are added or existing addresses are removed).
*
* The auto host address mode can be enabled before start or during operation of SRP client except when the host info
* is being removed (client is busy handling a remove request from an call to `otSrpClientRemoveHostAndServices()` and
* host info still being in either `STATE_TO_REMOVE` or `STATE_REMOVING` states).
*
* After auto host address mode is enabled, it can be disabled by a call to `otSrpClientSetHostAddresses()` which
* then explicitly sets the host addresses.
*
* @retval OT_ERROR_NONE Successfully enabled auto host address mode.
* @retval OT_ERROR_INVALID_STATE Host is being removed and therefore cannot enable auto host address mode.
*
*/
otError otSrpClientEnableAutoHostAddress(otInstance *aInstance);
/**
* This function sets/updates the list of host IPv6 address.
*
@ -414,6 +464,9 @@ otError otSrpClientSetHostName(otInstance *aInstance, const char *aName);
* After a successful call to this function, `otSrpClientCallback` will be called to report the status of the address
* registration with SRP server.
*
* Calling this function disables auto host address mode if it was previously enabled from a successful call to
* `otSrpClientEnableAutoHostAddress()`.
*
* @param[in] aInstance A pointer to the OpenThread instance.
* @param[in] aIp6Addresses A pointer to the an array containing the host IPv6 addresses.
* @param[in] aNumAddresses The number of addresses in the @p aIp6Addresses array.

View File

@ -155,6 +155,16 @@ typedef enum otSrpServerAddressMode
OT_SRP_SERVER_ADDRESS_MODE_ANYCAST = 1, ///< Anycast address mode.
} otSrpServerAddressMode;
/**
* This structure includes SRP server TTL configurations.
*
*/
typedef struct otSrpServerTtlConfig
{
uint32_t mMinTtl; ///< The minimum TTL in seconds.
uint32_t mMaxTtl; ///< The maximum TTL in seconds.
} otSrpServerTtlConfig;
/**
* This structure includes SRP server LEASE and KEY-LEASE configurations.
*
@ -167,6 +177,32 @@ typedef struct otSrpServerLeaseConfig
uint32_t mMaxKeyLease; ///< The maximum KEY-LEASE interval in seconds.
} otSrpServerLeaseConfig;
/**
* This structure includes SRP server lease information of a host/service.
*
*/
typedef struct otSrpServerLeaseInfo
{
uint32_t mLease; ///< The lease time of a host/service in milliseconds.
uint32_t mKeyLease; ///< The key lease time of a host/service in milliseconds.
uint32_t mRemainingLease; ///< The remaining lease time of the host/service in milliseconds.
uint32_t mRemainingKeyLease; ///< The remaining key lease time of a host/service in milliseconds.
} otSrpServerLeaseInfo;
/**
* This structure includes the statistics of SRP server responses.
*
*/
typedef struct otSrpServerResponseCounters
{
uint32_t mSuccess; ///< The number of successful responses.
uint32_t mServerFailure; ///< The number of server failure responses.
uint32_t mFormatError; ///< The number of format error responses.
uint32_t mNameExists; ///< The number of 'name exists' responses.
uint32_t mRefused; ///< The number of refused responses.
uint32_t mOther; ///< The number of other responses.
} otSrpServerResponseCounters;
/**
* This function returns the domain authorized to the SRP server.
*
@ -207,6 +243,16 @@ otError otSrpServerSetDomain(otInstance *aInstance, const char *aDomain);
*/
otSrpServerState otSrpServerGetState(otInstance *aInstance);
/**
* This function returns the port the SRP server is listening to.
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
* @returns The port of the SRP server. It returns 0 if the server is not running.
*
*/
uint16_t otSrpServerGetPort(otInstance *aInstance);
/**
* This function returns the address mode being used by the SRP server.
*
@ -262,6 +308,30 @@ otError otSrpServerSetAnycastModeSequenceNumber(otInstance *aInstance, uint8_t a
*/
void otSrpServerSetEnabled(otInstance *aInstance, bool aEnabled);
/**
* This function returns SRP server TTL configuration.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[out] aTtlConfig A pointer to an `otSrpServerTtlConfig` instance.
*
*/
void otSrpServerGetTtlConfig(otInstance *aInstance, otSrpServerTtlConfig *aTtlConfig);
/**
* This function sets SRP server TTL configuration.
*
* The granted TTL will always be no greater than the max lease interval configured via `otSrpServerSetLeaseConfig()`,
* regardless of the minimum and maximum TTL configuration.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aTtlConfig A pointer to an `otSrpServerTtlConfig` instance.
*
* @retval OT_ERROR_NONE Successfully set the TTL configuration.
* @retval OT_ERROR_INVALID_ARGS The TTL configuration is not valid.
*
*/
otError otSrpServerSetTtlConfig(otInstance *aInstance, const otSrpServerTtlConfig *aTtlConfig);
/**
* This function returns SRP server LEASE and KEY-LEASE configurations.
*
@ -365,6 +435,16 @@ void otSrpServerHandleServiceUpdateResult(otInstance *aInstance, otSrpServerServ
*/
const otSrpServerHost *otSrpServerGetNextHost(otInstance *aInstance, const otSrpServerHost *aHost);
/**
* This function returns the response counters of the SRP server.
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
* @returns A pointer to the response counters of the SRP server.
*
*/
const otSrpServerResponseCounters *otSrpServerGetResponseCounters(otInstance *aInstance);
/**
* This function tells if the SRP service host has been deleted.
*
@ -399,6 +479,15 @@ const char *otSrpServerHostGetFullName(const otSrpServerHost *aHost);
*/
const otIp6Address *otSrpServerHostGetAddresses(const otSrpServerHost *aHost, uint8_t *aAddressesNum);
/**
* This function returns the LEASE and KEY-LEASE information of a given host.
*
* @param[in] aHost A pointer to the SRP server host.
* @param[out] aLeaseInfo A pointer to where to output the LEASE and KEY-LEASE information.
*
*/
void otSrpServerHostGetLeaseInfo(const otSrpServerHost *aHost, otSrpServerLeaseInfo *aLeaseInfo);
/**
* This function returns the next service (excluding any sub-type services) of given host.
*
@ -562,6 +651,16 @@ uint16_t otSrpServerServiceGetWeight(const otSrpServerService *aService);
*/
uint16_t otSrpServerServiceGetPriority(const otSrpServerService *aService);
/**
* This function returns the TTL of the service instance.
*
* @param[in] aService A pointer to the SRP service.
*
* @returns The TTL of the service instance..
*
*/
uint32_t otSrpServerServiceGetTtl(const otSrpServerService *aService);
/**
* This function returns the TXT record data of the service instance.
*
@ -583,6 +682,14 @@ const uint8_t *otSrpServerServiceGetTxtData(const otSrpServerService *aService,
*/
const otSrpServerHost *otSrpServerServiceGetHost(const otSrpServerService *aService);
/**
* This function returns the LEASE and KEY-LEASE information of a given service.
*
* @param[in] aService A pointer to the SRP server service.
* @param[out] aLeaseInfo A pointer to where to output the LEASE and KEY-LEASE information.
*
*/
void otSrpServerServiceGetLeaseInfo(const otSrpServerService *aService, otSrpServerLeaseInfo *aLeaseInfo);
/**
* @}
*

View File

@ -194,11 +194,22 @@ typedef struct otThreadParentResponseInfo
bool mIsAttached; ///< Is the node receiving parent response attached
} otThreadParentResponseInfo;
/**
* This callback informs the application that the detaching process has finished.
*
* @param[in] aContext A pointer to application-specific context.
*
*/
typedef void (*otDetachGracefullyCallback)(void *aContext);
/**
* This function starts Thread protocol operation.
*
* The interface must be up when calling this function.
*
* Calling this function with @p aEnabled set to FALSE stops any ongoing processes of detaching started by
* otThreadDetachGracefully(). Its callback will be called.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aEnabled TRUE if Thread is enabled, FALSE otherwise.
*
@ -1009,6 +1020,21 @@ otError otThreadSendProactiveBackboneNotification(otInstance * aIns
otIp6InterfaceIdentifier *aMlIid,
uint32_t aTimeSinceLastTransaction);
/**
* This function notifies other nodes in the network (if any) and then stops Thread protocol operation.
*
* It sends an Address Release if it's a router, or sets its child timeout to 0 if it's a child.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aCallback A pointer to a function that is called upon finishing detaching.
* @param[in] aContext A pointer to callback application-specific context.
*
* @retval OT_ERROR_NONE Successfully started detaching.
* @retval OT_ERROR_BUSY Detaching is already in progress.
*
*/
otError otThreadDetachGracefully(otInstance *aInstance, otDetachGracefullyCallback aCallback, void *aContext);
/**
* @}
*

View File

@ -43,7 +43,7 @@ build_cc2538()
"DNS_CLIENT=1"
"JOINER=1"
"SLAAC=1"
# cc2538 does not have enough resources to support Thread 1.2
# cc2538 does not have enough resources to support Thread 1.3
"THREAD_VERSION=1.1"
)

View File

@ -51,7 +51,7 @@ reset_source()
build_cc2538()
{
local options=(
# cc2538 does not have enough resources to support Thread 1.2
# cc2538 does not have enough resources to support Thread 1.3
"-DOT_THREAD_VERSION=1.1"
)

View File

@ -43,10 +43,10 @@ main()
ninja -C gn-out
test -f gn-out/obj/src/core/libopenthread-ftd.a
# Check GN build for OT1.2
# Check GN build for OT1.3
rm gn-out -r || true
mkdir gn-out
echo 'openthread_config_thread_version = "1.2"' >gn-out/args.gn
echo 'openthread_config_thread_version = "1.3"' >gn-out/args.gn
gn gen --check gn-out
gn args gn-out --list
ninja -C gn-out

View File

@ -89,9 +89,11 @@ build_all_features()
"-DOPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE=1"
"-DOPENTHREAD_CONFIG_TMF_NETWORK_DIAG_MTD_ENABLE=1"
"-DOPENTHREAD_CONFIG_UDP_FORWARD_ENABLE=1"
"-DOPENTHREAD_CONFIG_MAC_BEACON_PAYLOAD_PARSING_ENABLE=1"
"-DOPENTHREAD_CONFIG_MAC_OUTGOING_BEACON_PAYLOAD_ENABLE=1"
)
local options_1_2=(
local options_1_3=(
"-DOPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE=1"
"-DOPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE=1"
"-DOPENTHREAD_CONFIG_DUA_ENABLE=1"
@ -108,15 +110,15 @@ build_all_features()
reset_source
make -f examples/Makefile-simulation THREAD_VERSION=1.1 FULL_LOGS=1
# Build Thread 1.2 with full features and logs
export CPPFLAGS="${options[*]} ${options_1_2[*]} -DOPENTHREAD_CONFIG_LOG_OUTPUT=OT_LOG_OUTPUT_NONE"
# Build Thread 1.3 with full features and logs
export CPPFLAGS="${options[*]} ${options_1_3[*]} -DOPENTHREAD_CONFIG_LOG_OUTPUT=OT_LOG_OUTPUT_NONE"
reset_source
make -f examples/Makefile-simulation THREAD_VERSION=1.2
make -f examples/Makefile-simulation THREAD_VERSION=1.3
# Build Thread 1.2 with full features and full logs
export CPPFLAGS="${options[*]} ${options_1_2[*]}"
# Build Thread 1.3 with full features and full logs
export CPPFLAGS="${options[*]} ${options_1_3[*]}"
reset_source
make -f examples/Makefile-simulation THREAD_VERSION=1.2 FULL_LOGS=1
make -f examples/Makefile-simulation THREAD_VERSION=1.3 FULL_LOGS=1
# Build Thread 1.1 with ASSERT disabled
export CPPFLAGS="${options[*]} -DOPENTHREAD_CONFIG_ASSERT_ENABLE=0"

View File

@ -53,7 +53,7 @@ build_all_features()
-DOT_FTD=OFF \
-DOT_MTD=OFF
# Thread 1.2 options
# Thread 1.3 options
local options=(
"-DOT_BACKBONE_ROUTER=ON"
"-DOT_BORDER_ROUTING=ON"
@ -61,18 +61,18 @@ build_all_features()
"-DOT_MLR=ON"
"-DOT_OTNS=ON"
"-DOT_SIMULATION_VIRTUAL_TIME=ON"
"-DOT_THREAD_VERSION=1.2"
"-DOT_THREAD_VERSION=1.3"
)
# Build Thread 1.2 with full features
# Build Thread 1.3 with full features
reset_source
"$(dirname "$0")"/cmake-build simulation "${options[@]}" -DOT_DUA=ON
# Build Thread 1.2 Backbone Router without DUA ND Proxying
# Build Thread 1.3 Backbone Router without DUA ND Proxying
reset_source
"$(dirname "$0")"/cmake-build simulation "${options[@]}" -DOT_BACKBONE_ROUTER_DUA_NDPROXYING=OFF
# Build Thread 1.2 Backbone Router without Multicast Routing
# Build Thread 1.3 Backbone Router without Multicast Routing
reset_source
"$(dirname "$0")"/cmake-build simulation "${options[@]}" -DOT_BACKBONE_ROUTER_MULTICAST_ROUTING=OFF
@ -82,11 +82,11 @@ build_all_features()
-DOT_THREAD_VERSION=1.1 \
-DOT_VENDOR_EXTENSION=../../src/core/common/extension_example.cpp
# Build Thread 1.2 with no additional features
# Build Thread 1.3 with no additional features
reset_source
"$(dirname "$0")"/cmake-build simulation -DOT_THREAD_VERSION=1.2
"$(dirname "$0")"/cmake-build simulation -DOT_THREAD_VERSION=1.3
# Build Thread 1.2 with full features and OT_ASSERT=OFF
# Build Thread 1.3 with full features and OT_ASSERT=OFF
reset_source
"$(dirname "$0")"/cmake-build simulation "${options[@]}" -DOT_DUA=ON -DOT_ASSERT=OFF

View File

@ -151,9 +151,9 @@ size_nrf52840_version()
local thread_version=$1
if [[ ${thread_version} == "1.2" ]]; then
if [[ ${thread_version} != "1.1" ]]; then
options+=(
"-DOT_THREAD_VERSION=1.2"
"-DOT_THREAD_VERSION=1.3"
"-DOT_BACKBONE_ROUTER=ON"
"-DOT_DUA=ON"
"-DOT_MLR=ON"
@ -243,7 +243,7 @@ size_nrf52840()
"${reporter}" init OpenThread
size_nrf52840_version 1.1
size_nrf52840_version 1.2
size_nrf52840_version 1.3
"${reporter}" post
}

View File

@ -121,7 +121,7 @@ readonly OT_CLANG_TIDY_BUILD_OPTS=(
'-DOT_SNTP_CLIENT=ON'
'-DOT_SRP_CLIENT=ON'
'-DOT_SRP_SERVER=ON'
'-DOT_THREAD_VERSION=1.2'
'-DOT_THREAD_VERSION=1.3'
'-DOT_TREL=ON'
'-DOT_COVERAGE=ON'
'-DOT_LOG_LEVEL_DYNAMIC=ON'
@ -177,7 +177,7 @@ do_clang_tidy_fix()
(mkdir -p ./build/cmake-tidy \
&& cd ./build/cmake-tidy \
&& THREAD_VERSION=1.2 cmake "${OT_CLANG_TIDY_BUILD_OPTS[@]}" ../.. \
&& THREAD_VERSION=1.3 cmake "${OT_CLANG_TIDY_BUILD_OPTS[@]}" ../.. \
&& ../../script/clang-tidy -header-filter='.*' -checks="${OT_CLANG_TIDY_CHECKS}" -j"$OT_BUILD_JOBS" "${OT_CLANG_TIDY_FIX_DIRS[@]}" -fix)
}
@ -190,7 +190,7 @@ do_clang_tidy_check()
(
mkdir -p ./build/cmake-tidy \
&& cd ./build/cmake-tidy \
&& THREAD_VERSION=1.2 cmake "${OT_CLANG_TIDY_BUILD_OPTS[@]}" ../.. \
&& THREAD_VERSION=1.3 cmake "${OT_CLANG_TIDY_BUILD_OPTS[@]}" ../.. \
&& ../../script/clang-tidy -header-filter='.*' -checks="${OT_CLANG_TIDY_CHECKS}" -j"$OT_BUILD_JOBS" "${OT_CLANG_TIDY_FIX_DIRS[@]}" \
| grep -v -E "third_party" >output.txt
if grep -q "warning: \|error: " output.txt; then

View File

@ -42,7 +42,7 @@ readonly OT_COLOR_NONE='\033[0m'
readonly OT_NODE_TYPE="${OT_NODE_TYPE:-cli}"
readonly OT_NATIVE_IP="${OT_NATIVE_IP:-0}"
readonly THREAD_VERSION="${THREAD_VERSION:-1.2}"
readonly THREAD_VERSION="${THREAD_VERSION:-1.3}"
readonly INTER_OP="${INTER_OP:-0}"
readonly VERBOSE="${VERBOSE:-0}"
readonly BORDER_ROUTING="${BORDER_ROUTING:-1}"
@ -81,7 +81,7 @@ build_simulation()
options+=("-DOT_FULL_LOGS=ON")
fi
if [[ ${version} == "1.2" ]]; then
if [[ ${version} != "1.1" ]]; then
options+=("-DOT_DUA=ON")
options+=("-DOT_MLR=ON")
fi
@ -90,7 +90,7 @@ build_simulation()
options+=("-DOT_SIMULATION_VIRTUAL_TIME=ON")
fi
if [[ ${version} == "1.2" ]]; then
if [[ ${version} != "1.1" ]]; then
options+=("-DOT_CSL_RECEIVER=ON")
options+=("-DOT_LINK_METRICS_INITIATOR=ON")
options+=("-DOT_LINK_METRICS_SUBJECT=ON")
@ -106,7 +106,7 @@ build_simulation()
OT_CMAKE_NINJA_TARGET=ot-rcp OT_CMAKE_BUILD_DIR="${OT_BUILDDIR}/openthread-simulation-${version}" "${OT_SRCDIR}"/script/cmake-build simulation "${options[@]}" "-DOT_SIMULATION_VIRTUAL_TIME_UART=ON"
fi
if [[ ${version} == "1.2" && ${INTER_OP_BBR} == 1 ]]; then
if [[ ${version} != "1.1" && ${INTER_OP_BBR} == 1 ]]; then
options+=("-DOT_BACKBONE_ROUTER=ON")
@ -124,7 +124,7 @@ build_posix()
local version="$1"
local options=("-DOT_MESSAGE_USE_HEAP=ON" "-DOT_THREAD_VERSION=${version}" "-DBUILD_TESTING=ON")
if [[ ${version} == "1.2" ]]; then
if [[ ${version} != "1.1" ]]; then
options+=("-DOT_DUA=ON")
options+=("-DOT_MLR=ON")
fi
@ -147,7 +147,7 @@ build_posix()
OT_CMAKE_BUILD_DIR="${OT_BUILDDIR}/openthread-posix-${version}" "${OT_SRCDIR}"/script/cmake-build posix "${options[@]}"
if [[ ${version} == "1.2" && ${INTER_OP_BBR} == 1 ]]; then
if [[ ${version} != "1.1" && ${INTER_OP_BBR} == 1 ]]; then
options+=("-DOT_BACKBONE_ROUTER=ON")
@ -170,7 +170,7 @@ do_build()
{
build_for_one_version "${THREAD_VERSION}"
if [[ ${THREAD_VERSION} == "1.2" && ${INTER_OP} == "1" ]]; then
if [[ ${THREAD_VERSION} != "1.1" && ${INTER_OP} == "1" ]]; then
build_for_one_version 1.1
fi
}
@ -201,8 +201,8 @@ do_unit()
{
do_unit_version "${THREAD_VERSION}"
if [[ ${THREAD_VERSION} == "1.2" && ${INTER_OP_BBR} == 1 ]]; then
do_unit_version "1.2-bbr"
if [[ ${THREAD_VERSION} != "1.1" && ${INTER_OP_BBR} == 1 ]]; then
do_unit_version "1.3-bbr"
fi
}
@ -220,8 +220,8 @@ do_cert()
;;
esac
if [[ ${THREAD_VERSION} == "1.2" ]]; then
export top_builddir_1_2_bbr="${OT_BUILDDIR}/openthread-simulation-1.2-bbr"
if [[ ${THREAD_VERSION} != "1.1" ]]; then
export top_builddir_1_3_bbr="${OT_BUILDDIR}/openthread-simulation-1.3-bbr"
if [[ ${INTER_OP} == "1" ]]; then
export top_builddir_1_1="${OT_BUILDDIR}/openthread-simulation-1.1"
fi
@ -238,8 +238,8 @@ do_cert_suite()
{
export top_builddir="${OT_BUILDDIR}/openthread-simulation-${THREAD_VERSION}"
if [[ ${THREAD_VERSION} == "1.2" ]]; then
export top_builddir_1_2_bbr="${OT_BUILDDIR}/openthread-simulation-1.2-bbr"
if [[ ${THREAD_VERSION} != "1.1" ]]; then
export top_builddir_1_3_bbr="${OT_BUILDDIR}/openthread-simulation-1.3-bbr"
if [[ ${INTER_OP} == "1" ]]; then
export top_builddir_1_1="${OT_BUILDDIR}/openthread-simulation-1.1"
fi
@ -386,7 +386,7 @@ do_expect()
test_patterns=(-name 'tun-*.exp')
else
test_patterns=(-name 'posix-*.exp' -o -name 'cli-*.exp')
if [[ ${THREAD_VERSION} == "1.2" ]]; then
if [[ ${THREAD_VERSION} != "1.1" ]]; then
test_patterns+=(-o -name 'v1_2-*.exp')
fi
fi
@ -421,9 +421,9 @@ ENVIRONMENTS:
VERBOSE 1 to build or test verbosely. The default is 0.
VIRTUAL_TIME 1 for virtual time, otherwise real time. The default value is 0 when running expect tests,
otherwise default value is 1.
THREAD_VERSION 1.1 for Thread 1.1 stack, 1.2 for Thread 1.2 stack. The default is 1.2.
INTER_OP 1 to build 1.1 together. Only works when THREAD_VERSION is 1.2. The default is 0.
INTER_OP_BBR 1 to build bbr version together. Only works when THREAD_VERSION is 1.2. The default is 1.
THREAD_VERSION 1.1 for Thread 1.1 stack, 1.3 for Thread 1.3 stack. The default is 1.3.
INTER_OP 1 to build 1.1 together. Only works when THREAD_VERSION is 1.3. The default is 0.
INTER_OP_BBR 1 to build bbr version together. Only works when THREAD_VERSION is 1.3. The default is 1.
COMMANDS:
clean Clean built files to prepare for new build.
@ -455,7 +455,7 @@ EXAMPLES:
THREAD_VERSION=1.1 VIRTUAL_TIME=0 $0 clean build cert tests/scripts/thread-cert/Cert_5_1_01_RouterAttach.py
THREAD_VERSION=1.1 VIRTUAL_TIME=0 $0 cert tests/scripts/thread-cert/Cert_5_1_02_ChildAddressTimeout.py
# Test Thread 1.2 with real time, use 'INTER_OP=1' when the case needs both versions.
# Test Thread 1.3 with real time, use 'INTER_OP=1' when the case needs both versions.
VIRTUAL_TIME=0 $0 clean build cert tests/scripts/thread-cert/v1_2_test_enhanced_keep_alive.py
INTER_OP=1 VIRTUAL_TIME=0 $0 clean build cert tests/scripts/thread-cert/v1_2_router_5_1_1.py
INTER_OP=1 VIRTUAL_TIME=0 $0 clean build cert_suite tests/scripts/thread-cert/v1_2_*
@ -559,10 +559,10 @@ envsetup()
export RADIO_DEVICE="${OT_BUILDDIR}/openthread-simulation-${THREAD_VERSION}/examples/apps/ncp/ot-rcp"
export OT_CLI_PATH="${OT_BUILDDIR}/openthread-posix-${THREAD_VERSION}/src/posix/ot-cli"
if [[ ${THREAD_VERSION} == "1.2" ]]; then
if [[ ${THREAD_VERSION} != "1.1" ]]; then
export RADIO_DEVICE_1_1="${OT_BUILDDIR}/openthread-simulation-1.1/examples/apps/ncp/ot-rcp"
export OT_CLI_PATH_1_1="${OT_BUILDDIR}/openthread-posix-1.1/src/posix/ot-cli"
export OT_CLI_PATH_1_2_BBR="${OT_BUILDDIR}/openthread-posix-1.2-bbr/src/posix/ot-cli"
export OT_CLI_PATH_BBR="${OT_BUILDDIR}/openthread-posix-1.3-bbr/src/posix/ot-cli"
fi
fi
@ -606,7 +606,7 @@ main()
fi
[[ ${VIRTUAL_TIME} == 1 ]] && echo "Using virtual time" || echo "Using real time"
[[ ${THREAD_VERSION} == "1.2" ]] && echo "Using Thread 1.2 stack" || echo "Using Thread 1.1 stack"
[[ ${THREAD_VERSION} != "1.1" ]] && echo "Using Thread 1.3 stack" || echo "Using Thread 1.1 stack"
while [[ $# != 0 ]]; do
case "$1" in

View File

@ -62,7 +62,6 @@ Done
- [leaderdata](#leaderdata)
- [leaderweight](#leaderweight)
- [linkmetrics](#linkmetrics-mgmt-ipaddr-enhanced-ack-clear)
- [linkquality](#linkquality-extaddr)
- [locate](#locate)
- [log](#log-filename-filename)
- [mac](#mac-retries-direct)
@ -1627,25 +1626,6 @@ Done
- RSSI: -18 (dBm) (Exponential Moving Average)
```
### linkquality \<extaddr\>
Get the link quality on the link to a given extended address.
```bash
> linkquality 36c1dd7a4f5201ff
3
Done
```
### linkquality \<extaddr\> \<linkquality\>
Set the link quality on the link to a given extended address.
```bash
> linkquality 36c1dd7a4f5201ff 3
Done
```
### locate
Gets the current state (`In Progress` or `Idle`) of anycast locator.

View File

@ -196,7 +196,7 @@ Done
Usage: `dataset activetimestamp [timestamp]`
Get active timestamp.
Get active timestamp seconds.
```bash
> dataset activetimestamp
@ -204,7 +204,7 @@ Get active timestamp.
Done
```
Set active timestamp.
Set active timestamp seconds.
```bash
> dataset activetimestamp 123456789
@ -457,7 +457,7 @@ Done
Usage: `dataset pendingtimestamp [timestamp]`
Get pending timestamp.
Get pending timestamp seconds.
```bash
> dataset pendingtimestamp
@ -465,7 +465,7 @@ Get pending timestamp.
Done
```
Set pending timestamp.
Set pending timestamp seconds.
```bash
> dataset pendingtimestamp 123456789

View File

@ -15,6 +15,7 @@ Usage : `srp client [command] ...`
- [start](#start)
- [state](#state)
- [stop](#stop)
- [ttl](#ttl)
## Command Details
@ -36,6 +37,7 @@ service
start
state
stop
ttl
Done
```
@ -137,6 +139,14 @@ name:"dev4312", state:Registered, addrs:[fd00:0:0:0:0:0:0:1234, fd00:0:0:0:0:0:0
Done
```
When auto host address mode is enabled.
```bash
srp client host
name:"dev1234", state:Registered, addrs:auto
Done
```
### host name
Usage: `srp client host name [name]`
@ -158,9 +168,17 @@ Done
### host address
Usage : `srp client host address [<address> ...]`
Usage : `srp client host address [auto | <address> ...]`
Get the list of host addresses.
Indicate auto address mode is enabled.
```bash
> srp client host address
auto
Done
```
Get the list of host addresses (when auto host address is not enabled).
```bash
> srp client host address
@ -169,7 +187,14 @@ fd00:0:0:0:0:0:0:beef
Done
```
Set the list of host addresses (can be set while client is running to update the host addresses)
Enable auto host address mode. When enabled client will automatically use all Thread netif unicast addresses excluding all link-local and mesh-local addresses. If there is no valid address, then Mesh Local EID address is added. SRP client will automatically re-register if/when addresses on Thread netif get changed (e.g., new address is added or existing address is removed).
```bash
> srp client host address auto
Done
```
Explicitly set the list of host addresses (can be set while client is running to update the host addresses), also disabled auto host address mode.
```bash
> srp client host address fd00::cafe
@ -409,3 +434,23 @@ Stop the SRP client.
> srp client stop
Done
```
### ttl
Usage: `srp client ttl [value]`
Get the TTL (in seconds).
```bash
> srp client ttl
7200
Done
>
```
Set the TTL.
```bash
> srp client ttl 3600
Done
```

View File

@ -1453,6 +1453,25 @@ exit:
}
#endif
template <> otError Interpreter::Process<Cmd("detach")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
if (aArgs[0] == "async")
{
SuccessOrExit(error = otThreadDetachGracefully(GetInstancePtr(), nullptr, nullptr));
}
else
{
SuccessOrExit(error =
otThreadDetachGracefully(GetInstancePtr(), &Interpreter::HandleDetachGracefullyResult, this));
error = OT_ERROR_PENDING;
}
exit:
return error;
}
template <> otError Interpreter::Process<Cmd("discover")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
@ -4903,6 +4922,17 @@ void Interpreter::OutputChildTableEntry(uint8_t aIndentSize, const otNetworkDiag
}
#endif // OPENTHREAD_FTD || OPENTHREAD_CONFIG_TMF_NETWORK_DIAG_MTD_ENABLE
void Interpreter::HandleDetachGracefullyResult(void *aContext)
{
static_cast<Interpreter *>(aContext)->HandleDetachGracefullyResult();
}
void Interpreter::HandleDetachGracefullyResult(void)
{
OutputLine("Finished detaching");
OutputResult(OT_ERROR_NONE);
}
void Interpreter::HandleDiscoveryRequest(const otThreadDiscoveryRequestInfo &aInfo)
{
OutputFormat("~ Discovery Request from ");
@ -5017,6 +5047,7 @@ otError Interpreter::ProcessCommand(Arg aArgs[])
#if OPENTHREAD_FTD
CmdEntry("delaytimermin"),
#endif
CmdEntry("detach"),
#endif // OPENTHREAD_FTD || OPENTHREAD_MTD
#if OPENTHREAD_CONFIG_DIAG_ENABLE
CmdEntry("diag"),

View File

@ -452,6 +452,9 @@ private:
const char *LinkMetricsStatusToStr(uint8_t aStatus);
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
static void HandleDetachGracefullyResult(void *aContext);
void HandleDetachGracefullyResult(void);
static void HandleDiscoveryRequest(const otThreadDiscoveryRequestInfo *aInfo, void *aContext)
{
static_cast<Interpreter *>(aContext)->HandleDiscoveryRequest(*aInfo);

View File

@ -51,12 +51,12 @@ otError Dataset::Print(otOperationalDataset &aDataset)
{
if (aDataset.mComponents.mIsPendingTimestampPresent)
{
OutputLine("Pending Timestamp: %lu", aDataset.mPendingTimestamp);
OutputLine("Pending Timestamp: %lu", aDataset.mPendingTimestamp.mSeconds);
}
if (aDataset.mComponents.mIsActiveTimestampPresent)
{
OutputLine("Active Timestamp: %lu", aDataset.mActiveTimestamp);
OutputLine("Active Timestamp: %lu", aDataset.mActiveTimestamp.mSeconds);
}
if (aDataset.mComponents.mIsChannelPresent)
@ -205,12 +205,14 @@ template <> otError Dataset::Process<Cmd("activetimestamp")>(Arg aArgs[])
{
if (sDataset.mComponents.mIsActiveTimestampPresent)
{
OutputLine("%lu", sDataset.mActiveTimestamp);
OutputLine("%lu", sDataset.mActiveTimestamp.mSeconds);
}
}
else
{
SuccessOrExit(error = aArgs[0].ParseAsUint64(sDataset.mActiveTimestamp));
SuccessOrExit(error = aArgs[0].ParseAsUint64(sDataset.mActiveTimestamp.mSeconds));
sDataset.mActiveTimestamp.mTicks = 0;
sDataset.mActiveTimestamp.mAuthoritative = false;
sDataset.mComponents.mIsActiveTimestampPresent = true;
}
@ -423,12 +425,14 @@ template <> otError Dataset::Process<Cmd("pendingtimestamp")>(Arg aArgs[])
{
if (sDataset.mComponents.mIsPendingTimestampPresent)
{
OutputLine("%lu", sDataset.mPendingTimestamp);
OutputLine("%lu", sDataset.mPendingTimestamp.mSeconds);
}
}
else
{
SuccessOrExit(error = aArgs[0].ParseAsUint64(sDataset.mPendingTimestamp));
SuccessOrExit(error = aArgs[0].ParseAsUint64(sDataset.mPendingTimestamp.mSeconds));
sDataset.mPendingTimestamp.mTicks = 0;
sDataset.mPendingTimestamp.mAuthoritative = false;
sDataset.mComponents.mIsPendingTimestampPresent = true;
}
@ -450,14 +454,18 @@ template <> otError Dataset::Process<Cmd("mgmtsetcommand")>(Arg aArgs[])
if (*arg == "activetimestamp")
{
arg++;
SuccessOrExit(error = arg->ParseAsUint64(dataset.mActiveTimestamp.mSeconds));
dataset.mActiveTimestamp.mTicks = 0;
dataset.mActiveTimestamp.mAuthoritative = false;
dataset.mComponents.mIsActiveTimestampPresent = true;
SuccessOrExit(error = arg->ParseAsUint64(dataset.mActiveTimestamp));
}
else if (*arg == "pendingtimestamp")
{
arg++;
SuccessOrExit(error = arg->ParseAsUint64(dataset.mPendingTimestamp.mSeconds));
dataset.mPendingTimestamp.mTicks = 0;
dataset.mPendingTimestamp.mAuthoritative = false;
dataset.mComponents.mIsPendingTimestampPresent = true;
SuccessOrExit(error = arg->ParseAsUint64(dataset.mPendingTimestamp));
}
else if (*arg == "networkkey")
{

View File

@ -160,10 +160,21 @@ template <> otError SrpClient::Process<Cmd("host")>(Arg aArgs[])
{
const otSrpClientHostInfo *hostInfo = otSrpClientGetHostInfo(GetInstancePtr());
for (uint8_t index = 0; index < hostInfo->mNumAddresses; index++)
if (hostInfo->mAutoAddress)
{
OutputIp6AddressLine(hostInfo->mAddresses[index]);
OutputLine("auto");
}
else
{
for (uint8_t index = 0; index < hostInfo->mNumAddresses; index++)
{
OutputIp6AddressLine(hostInfo->mAddresses[index]);
}
}
}
else if (aArgs[1] == "auto")
{
error = otSrpClientEnableAutoHostAddress(GetInstancePtr());
}
else
{
@ -447,19 +458,28 @@ void SrpClient::OutputHostInfo(uint8_t aIndentSize, const otSrpClientHostInfo &a
OutputFormat("(null)");
}
OutputFormat(", state:%s, addrs:[", otSrpClientItemStateToString(aHostInfo.mState));
OutputFormat(", state:%s, addrs:", otSrpClientItemStateToString(aHostInfo.mState));
for (uint8_t index = 0; index < aHostInfo.mNumAddresses; index++)
if (aHostInfo.mAutoAddress)
{
if (index > 0)
OutputLine("auto");
}
else
{
OutputFormat("[");
for (uint8_t index = 0; index < aHostInfo.mNumAddresses; index++)
{
OutputFormat(", ");
if (index > 0)
{
OutputFormat(", ");
}
OutputIp6Address(aHostInfo.mAddresses[index]);
}
OutputIp6Address(aHostInfo.mAddresses[index]);
OutputLine("]");
}
OutputLine("]");
}
void SrpClient::OutputServiceList(uint8_t aIndentSize, const otSrpClientService *aServices)
@ -525,6 +545,11 @@ exit:
return error;
}
template <> otError SrpClient::Process<Cmd("ttl")>(Arg aArgs[])
{
return Interpreter::GetInterpreter().ProcessGetSet(aArgs, otSrpClientGetTtl, otSrpClientSetTtl);
}
void SrpClient::HandleCallback(otError aError,
const otSrpClientHostInfo *aHostInfo,
const otSrpClientService * aServices,
@ -578,7 +603,7 @@ otError SrpClient::Process(Arg aArgs[])
static constexpr Command kCommands[] = {
CmdEntry("autostart"), CmdEntry("callback"), CmdEntry("host"), CmdEntry("keyleaseinterval"),
CmdEntry("leaseinterval"), CmdEntry("server"), CmdEntry("service"), CmdEntry("start"),
CmdEntry("state"), CmdEntry("stop"),
CmdEntry("state"), CmdEntry("stop"), CmdEntry("ttl"),
};
static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted");

View File

@ -149,6 +149,30 @@ otError SrpServer::ProcessDisable(Arg aArgs[])
return OT_ERROR_NONE;
}
otError SrpServer::ProcessTtl(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
otSrpServerTtlConfig ttlConfig;
if (aArgs[0].IsEmpty())
{
otSrpServerGetTtlConfig(GetInstancePtr(), &ttlConfig);
OutputLine("min ttl: %u", ttlConfig.mMinTtl);
OutputLine("max ttl: %u", ttlConfig.mMaxTtl);
}
else
{
SuccessOrExit(error = aArgs[0].ParseAsUint32(ttlConfig.mMinTtl));
SuccessOrExit(error = aArgs[1].ParseAsUint32(ttlConfig.mMaxTtl));
VerifyOrExit(aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
error = otSrpServerSetTtlConfig(GetInstancePtr(), &ttlConfig);
}
exit:
return error;
}
otError SrpServer::ProcessLease(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
@ -289,6 +313,7 @@ otError SrpServer::ProcessService(Arg aArgs[])
OutputLine(kIndentSize, "port: %hu", otSrpServerServiceGetPort(service));
OutputLine(kIndentSize, "priority: %hu", otSrpServerServiceGetPriority(service));
OutputLine(kIndentSize, "weight: %hu", otSrpServerServiceGetWeight(service));
OutputLine(kIndentSize, "ttl: %hu", otSrpServerServiceGetTtl(service));
txtData = otSrpServerServiceGetTxtData(service, &txtDataLength);
OutputFormat(kIndentSize, "TXT: ");

View File

@ -90,6 +90,7 @@ private:
otError ProcessHost(Arg aArgs[]);
otError ProcessService(Arg aArgs[]);
otError ProcessSeqNum(Arg aArgs[]);
otError ProcessTtl(Arg aArgs[]);
otError ProcessHelp(Arg aArgs[]);
void OutputHostAddresses(const otSrpServerHost *aHost);
@ -100,6 +101,7 @@ private:
{"help", &SrpServer::ProcessHelp}, {"host", &SrpServer::ProcessHost},
{"lease", &SrpServer::ProcessLease}, {"seqnum", &SrpServer::ProcessSeqNum},
{"service", &SrpServer::ProcessService}, {"state", &SrpServer::ProcessState},
{"ttl", &SrpServer::ProcessTtl},
};
static_assert(BinarySearch::IsSorted(sCommands), "Command Table is not sorted");

View File

@ -46,10 +46,14 @@ target_sources(openthread-cli-radio
cli_output.cpp
)
if(NOT DEFINED OT_MBEDTLS_RCP)
set(OT_MBEDTLS_RCP ${OT_MBEDTLS})
endif()
target_link_libraries(openthread-cli-radio
PUBLIC
openthread-radio
PRIVATE
${OT_MBEDTLS}
${OT_MBEDTLS_RCP}
ot-config
)

View File

@ -37,6 +37,8 @@ if (openthread_enable_core_config_args) {
defines += [ "OPENTHREAD_CONFIG_THREAD_VERSION=OT_THREAD_VERSION_1_1" ]
} else if (openthread_config_thread_version == "1.2") {
defines += [ "OPENTHREAD_CONFIG_THREAD_VERSION=OT_THREAD_VERSION_1_2" ]
} else if (openthread_config_thread_version == "1.3") {
defines += [ "OPENTHREAD_CONFIG_THREAD_VERSION=OT_THREAD_VERSION_1_3" ]
} else if (openthread_config_thread_version != "") {
assert(false,
"Unrecognized Thread version: ${openthread_config_thread_version}")
@ -363,9 +365,8 @@ openthread_core_files = [
"backbone_router/multicast_listeners_table.hpp",
"backbone_router/ndproxy_table.cpp",
"backbone_router/ndproxy_table.hpp",
"border_router/infra_if_platform.cpp",
"border_router/router_advertisement.cpp",
"border_router/router_advertisement.hpp",
"border_router/infra_if.cpp",
"border_router/infra_if.hpp",
"border_router/routing_manager.cpp",
"border_router/routing_manager.hpp",
"coap/coap.cpp",
@ -557,6 +558,8 @@ openthread_core_files = [
"net/ip6_mpl.cpp",
"net/ip6_mpl.hpp",
"net/ip6_types.hpp",
"net/nd6.cpp",
"net/nd6.hpp",
"net/nd_agent.cpp",
"net/nd_agent.hpp",
"net/netif.cpp",

View File

@ -86,8 +86,7 @@ set(COMMON_SOURCES
backbone_router/bbr_manager.cpp
backbone_router/multicast_listeners_table.cpp
backbone_router/ndproxy_table.cpp
border_router/infra_if_platform.cpp
border_router/router_advertisement.cpp
border_router/infra_if.cpp
border_router/routing_manager.cpp
coap/coap.cpp
coap/coap_message.cpp
@ -169,6 +168,7 @@ set(COMMON_SOURCES
net/ip6_filter.cpp
net/ip6_headers.cpp
net/ip6_mpl.cpp
net/nd6.cpp
net/nd_agent.cpp
net/netif.cpp
net/sntp_client.cpp

View File

@ -176,8 +176,7 @@ SOURCES_COMMON = \
backbone_router/bbr_manager.cpp \
backbone_router/multicast_listeners_table.cpp \
backbone_router/ndproxy_table.cpp \
border_router/infra_if_platform.cpp \
border_router/router_advertisement.cpp \
border_router/infra_if.cpp \
border_router/routing_manager.cpp \
coap/coap.cpp \
coap/coap_message.cpp \
@ -259,6 +258,7 @@ SOURCES_COMMON = \
net/ip6_filter.cpp \
net/ip6_headers.cpp \
net/ip6_mpl.cpp \
net/nd6.cpp \
net/nd_agent.cpp \
net/netif.cpp \
net/sntp_client.cpp \
@ -415,7 +415,7 @@ HEADERS_COMMON = \
backbone_router/bbr_manager.hpp \
backbone_router/multicast_listeners_table.hpp \
backbone_router/ndproxy_table.hpp \
border_router/router_advertisement.hpp \
border_router/infra_if.hpp \
border_router/routing_manager.hpp \
coap/coap.hpp \
coap/coap_message.hpp \
@ -563,6 +563,7 @@ HEADERS_COMMON = \
net/ip6_headers.hpp \
net/ip6_mpl.hpp \
net/ip6_types.hpp \
net/nd6.hpp \
net/nd_agent.hpp \
net/netif.hpp \
net/sntp_client.hpp \

View File

@ -81,4 +81,9 @@ otDnssdQueryType otDnssdGetQueryTypeAndName(const otDnssdQuery *aQuery, char (*a
return MapEnum(Dns::ServiceDiscovery::Server::GetQueryTypeAndName(aQuery, *aNameOutput));
}
const otDnssdCounters *otDnssdGetCounters(otInstance *aInstance)
{
return &AsCoreType(aInstance).Get<Dns::ServiceDiscovery::Server>().GetCounters();
}
#endif // OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE

View File

@ -84,6 +84,16 @@ bool otSrpClientIsAutoStartModeEnabled(otInstance *aInstance)
}
#endif // OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
uint32_t otSrpClientGetTtl(otInstance *aInstance)
{
return AsCoreType(aInstance).Get<Srp::Client>().GetTtl();
}
void otSrpClientSetTtl(otInstance *aInstance, uint32_t aTtl)
{
return AsCoreType(aInstance).Get<Srp::Client>().SetTtl(aTtl);
}
uint32_t otSrpClientGetLeaseInterval(otInstance *aInstance)
{
return AsCoreType(aInstance).Get<Srp::Client>().GetLeaseInterval();
@ -114,6 +124,11 @@ otError otSrpClientSetHostName(otInstance *aInstance, const char *aName)
return AsCoreType(aInstance).Get<Srp::Client>().SetHostName(aName);
}
otError otSrpClientEnableAutoHostAddress(otInstance *aInstance)
{
return AsCoreType(aInstance).Get<Srp::Client>().EnableAutoHostAddress();
}
otError otSrpClientSetHostAddresses(otInstance *aInstance, const otIp6Address *aIp6Addresses, uint8_t aNumAddresses)
{
return AsCoreType(aInstance).Get<Srp::Client>().SetHostAddresses(AsCoreTypePtr(aIp6Addresses), aNumAddresses);

View File

@ -57,6 +57,11 @@ otSrpServerState otSrpServerGetState(otInstance *aInstance)
return MapEnum(AsCoreType(aInstance).Get<Srp::Server>().GetState());
}
uint16_t otSrpServerGetPort(otInstance *aInstance)
{
return AsCoreType(aInstance).Get<Srp::Server>().GetPort();
}
otSrpServerAddressMode otSrpServerGetAddressMode(otInstance *aInstance)
{
return MapEnum(AsCoreType(aInstance).Get<Srp::Server>().GetAddressMode());
@ -82,6 +87,16 @@ void otSrpServerSetEnabled(otInstance *aInstance, bool aEnabled)
AsCoreType(aInstance).Get<Srp::Server>().SetEnabled(aEnabled);
}
void otSrpServerGetTtlConfig(otInstance *aInstance, otSrpServerTtlConfig *aTtlConfig)
{
AsCoreType(aInstance).Get<Srp::Server>().GetTtlConfig(AsCoreType(aTtlConfig));
}
otError otSrpServerSetTtlConfig(otInstance *aInstance, const otSrpServerTtlConfig *aTtlConfig)
{
return AsCoreType(aInstance).Get<Srp::Server>().SetTtlConfig(AsCoreType(aTtlConfig));
}
void otSrpServerGetLeaseConfig(otInstance *aInstance, otSrpServerLeaseConfig *aLeaseConfig)
{
AsCoreType(aInstance).Get<Srp::Server>().GetLeaseConfig(AsCoreType(aLeaseConfig));
@ -109,6 +124,11 @@ const otSrpServerHost *otSrpServerGetNextHost(otInstance *aInstance, const otSrp
return AsCoreType(aInstance).Get<Srp::Server>().GetNextHost(AsCoreTypePtr(aHost));
}
const otSrpServerResponseCounters *otSrpServerGetResponseCounters(otInstance *aInstance)
{
return AsCoreType(aInstance).Get<Srp::Server>().GetResponseCounters();
}
bool otSrpServerHostIsDeleted(const otSrpServerHost *aHost)
{
return AsCoreType(aHost).IsDeleted();
@ -124,6 +144,16 @@ const otIp6Address *otSrpServerHostGetAddresses(const otSrpServerHost *aHost, ui
return AsCoreType(aHost).GetAddresses(*aAddressesNum);
}
void otSrpServerHostGetLeaseInfo(const otSrpServerHost *aHost, otSrpServerLeaseInfo *aLeaseInfo)
{
AsCoreType(aHost).GetLeaseInfo(*aLeaseInfo);
}
uint32_t otSrpServerHostGetKeyLease(const otSrpServerHost *aHost)
{
return AsCoreType(aHost).GetKeyLease();
}
const otSrpServerService *otSrpServerHostGetNextService(const otSrpServerHost * aHost,
const otSrpServerService *aService)
{
@ -184,6 +214,11 @@ uint16_t otSrpServerServiceGetPriority(const otSrpServerService *aService)
return AsCoreType(aService).GetPriority();
}
uint32_t otSrpServerServiceGetTtl(const otSrpServerService *aService)
{
return AsCoreType(aService).GetTtl();
}
const uint8_t *otSrpServerServiceGetTxtData(const otSrpServerService *aService, uint16_t *aDataLength)
{
*aDataLength = AsCoreType(aService).GetTxtDataLength();
@ -196,4 +231,9 @@ const otSrpServerHost *otSrpServerServiceGetHost(const otSrpServerService *aServ
return &AsCoreType(aService).GetHost();
}
void otSrpServerServiceGetLeaseInfo(const otSrpServerService *aService, otSrpServerLeaseInfo *aLeaseInfo)
{
AsCoreType(aService).GetLeaseInfo(*aLeaseInfo);
}
#endif // OPENTHREAD_CONFIG_SRP_SERVER_ENABLE

View File

@ -497,4 +497,9 @@ bool otThreadIsAnycastLocateInProgress(otInstance *aInstance)
}
#endif
otError otThreadDetachGracefully(otInstance *aInstance, otDetachGracefullyCallback aCallback, void *aContext)
{
return AsCoreType(aInstance).Get<Mle::MleRouter>().DetachGracefully(aCallback, aContext);
}
#endif // OPENTHREAD_FTD || OPENTHREAD_MTD

View File

@ -251,7 +251,7 @@ void NdProxyTable::HandleTimer(void)
for (NdProxy &proxy : Iterate(kFilterDadInProcess))
{
if (proxy.IsDadAttamptsComplete())
if (proxy.IsDadAttemptsComplete())
{
proxy.mDadFlag = false;
NotifyDuaRegistrationOnBackboneLink(proxy, /* aIsRenew */ false);
@ -262,7 +262,7 @@ void NdProxyTable::HandleTimer(void)
if (Get<BackboneRouter::Manager>().SendBackboneQuery(GetDua(proxy)) == kErrorNone)
{
proxy.IncreaseDadAttampts();
proxy.IncreaseDadAttempts();
}
}
}

View File

@ -111,8 +111,8 @@ public:
uint32_t aTimeSinceLastTransaction);
void Update(uint16_t aRloc16, uint32_t aTimeSinceLastTransaction);
void IncreaseDadAttampts(void) { mDadAttempts++; }
bool IsDadAttamptsComplete() const { return mDadAttempts == Mle::kDuaDadRepeats; }
void IncreaseDadAttempts(void) { mDadAttempts++; }
bool IsDadAttemptsComplete() const { return mDadAttempts == Mle::kDuaDadRepeats; }
Ip6::InterfaceIdentifier mAddressIid;
Ip6::InterfaceIdentifier mMeshLocalIid;

View File

@ -0,0 +1,162 @@
/*
* Copyright (c) 2022, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file implements infrastructure network interface.
*/
#include "infra_if.hpp"
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
#include "border_router/routing_manager.hpp"
#include "common/as_core_type.hpp"
#include "common/instance.hpp"
#include "common/locator_getters.hpp"
#include "common/logging.hpp"
#include "net/icmp6.hpp"
namespace ot {
namespace BorderRouter {
RegisterLogModule("InfraIf");
InfraIf::InfraIf(Instance &aInstance)
: InstanceLocator(aInstance)
, mInitialized(false)
, mIsRunning(false)
, mIfIndex(0)
{
}
Error InfraIf::Init(uint32_t aIfIndex)
{
Error error = kErrorNone;
VerifyOrExit(!mInitialized, error = kErrorInvalidState);
VerifyOrExit(aIfIndex > 0, error = kErrorInvalidArgs);
mIfIndex = aIfIndex;
mInitialized = true;
LogInfo("Init %s", ToString().AsCString());
exit:
return error;
}
void InfraIf::Deinit(void)
{
mInitialized = false;
mIsRunning = false;
mIfIndex = 0;
LogInfo("Deinit");
}
bool InfraIf::HasAddress(const Ip6::Address &aAddress)
{
OT_ASSERT(mInitialized);
return otPlatInfraIfHasAddress(mIfIndex, &aAddress);
}
Error InfraIf::Send(const Icmp6Packet &aPacket, const Ip6::Address &aDestination)
{
OT_ASSERT(mInitialized);
return otPlatInfraIfSendIcmp6Nd(mIfIndex, &aDestination, aPacket.GetBytes(), aPacket.GetLength());
}
void InfraIf::HandledReceived(uint32_t aIfIndex, const Ip6::Address &aSource, const Icmp6Packet &aPacket)
{
Error error = kErrorNone;
VerifyOrExit(mInitialized && mIsRunning, error = kErrorInvalidState);
VerifyOrExit(aIfIndex == mIfIndex, error = kErrorDrop);
VerifyOrExit(aPacket.GetBytes() != nullptr, error = kErrorInvalidArgs);
VerifyOrExit(aPacket.GetLength() >= sizeof(Ip6::Icmp::Header), error = kErrorParse);
Get<RoutingManager>().HandleReceived(aPacket, aSource);
exit:
if (error != kErrorNone)
{
LogDebg("Dropped ICMPv6 message: %s", ErrorToString(error));
}
}
Error InfraIf::HandleStateChanged(uint32_t aIfIndex, bool aIsRunning)
{
Error error = kErrorNone;
VerifyOrExit(mInitialized, error = kErrorInvalidState);
VerifyOrExit(aIfIndex == mIfIndex, error = kErrorInvalidArgs);
VerifyOrExit(aIsRunning != mIsRunning);
LogInfo("State changed: %sRUNNING -> %sRUNNING", mIsRunning ? "" : "NOT ", aIsRunning ? "" : "NOT ");
mIsRunning = aIsRunning;
Get<RoutingManager>().HandleInfraIfStateChanged();
exit:
return error;
}
InfraIf::InfoString InfraIf::ToString(void) const
{
InfoString string;
string.Append("infra netif %u", mIfIndex);
return string;
}
//---------------------------------------------------------------------------------------------------------------------
extern "C" void otPlatInfraIfRecvIcmp6Nd(otInstance * aInstance,
uint32_t aInfraIfIndex,
const otIp6Address *aSrcAddress,
const uint8_t * aBuffer,
uint16_t aBufferLength)
{
InfraIf::Icmp6Packet packet;
packet.Init(aBuffer, aBufferLength);
AsCoreType(aInstance).Get<InfraIf>().HandledReceived(aInfraIfIndex, AsCoreType(aSrcAddress), packet);
}
extern "C" otError otPlatInfraIfStateChanged(otInstance *aInstance, uint32_t aInfraIfIndex, bool aIsRunning)
{
return AsCoreType(aInstance).Get<InfraIf>().HandleStateChanged(aInfraIfIndex, aIsRunning);
}
} // namespace BorderRouter
} // namespace ot
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE

View File

@ -0,0 +1,186 @@
/*
* Copyright (c) 2022, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes definitions for infrastructure network interface.
*
*/
#ifndef INFRA_IF_HPP_
#define INFRA_IF_HPP_
#include "openthread-core-config.h"
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
#include <openthread/platform/infra_if.h>
#include "common/data.hpp"
#include "common/error.hpp"
#include "common/locator.hpp"
#include "common/string.hpp"
#include "net/ip6.hpp"
namespace ot {
namespace BorderRouter {
/**
* This class represents the infrastructure network interface on a border router.
*
*/
class InfraIf : public InstanceLocator
{
public:
static constexpr uint16_t kInfoStringSize = 20; ///< Max chars for the info string (`ToString()`).
typedef String<kInfoStringSize> InfoString; ///< String type returned from `ToString()`.
typedef Data<kWithUint16Length> Icmp6Packet; ///< An IMCPv6 packet (data containing the IP payload)
/**
* This constructor initializes the `InfraIf`.
*
* @param[in] aInstance A OpenThread instance.
*
*/
explicit InfraIf(Instance &aInstance);
/**
* This method initializes the `InfraIf`.
*
* @param[in] aIfIndex The infrastructure interface index.
*
* @retval kErrorNone Successfully initialized the `InfraIf`.
* @retval kErrorInvalidArgs The index of the infra interface is not valid.
* @retval kErrorInvalidState The `InfraIf` is already initialized.
*
*/
Error Init(uint32_t aIfIndex);
/**
* This method deinitilaizes the `InfraIf`.
*
*/
void Deinit(void);
/**
* This method indicates whether or not the `InfraIf` is initialized.
*
* @retval TRUE The `InfraIf` is initialized.
* @retval FALSE The `InfraIf` is not initialized.
*
*/
bool IsInitialized(void) const { return mInitialized; }
/**
* This method indicates whether or not the infra interface is running.
*
* @retval TRUE The infrastructure interface is running.
* @retval FALSE The infrastructure interface is not running.
*
*/
bool IsRunning(void) const { return mIsRunning; }
/**
* This method returns the infrastructure interface index.
*
* @returns The interface index or zero if not initialized.
*
*/
uint32_t GetIfIndex(void) const { return mIfIndex; }
/**
* This method indicates whether or not the infra interface has the given IPv6 address assigned.
*
* This method MUST be used when interface is initialized.
*
* @param[in] aAddress The IPv6 address.
*
* @retval TRUE The infrastructure interface has @p aAddress.
* @retval FALSE The infrastructure interface does not have @p aAddress.
*
*/
bool HasAddress(const Ip6::Address &aAddress);
/**
* This method sends an ICMPv6 Neighbor Discovery packet on the infrastructure interface.
*
* This method MUST be used when interface is initialized.
*
* @param[in] aPacket The ICMPv6 packet to send.
* @param[in] aDestination The destination address.
*
* @retval kErrorNone Successfully sent the ICMPv6 message.
* @retval kErrorFailed Failed to send the ICMPv6 message.
*
*/
Error Send(const Icmp6Packet &aPacket, const Ip6::Address &aDestination);
/**
* This method processes a received ICMPv6 Neighbor Discovery packet from an infrastructure interface.
*
* @param[in] aIfIndex The infrastructure interface index on which the ICMPv6 message is received.
* @param[in] aSource The IPv6 source address.
* @param[in] aPacket The ICMPv6 packet.
*
*/
void HandledReceived(uint32_t aIfIndex, const Ip6::Address &aSource, const Icmp6Packet &aPacket);
/**
* This method handles infrastructure interface state changes.
*
* @param[in] aIfIndex The infrastructure interface index.
* @param[in] aIsRunning A boolean that indicates whether the infrastructure interface is running.
*
* @retval kErrorNone Successfully updated the infra interface status.
* @retval kErrorInvalidState The `InfraIf` is not initialized.
* @retval kErrorInvalidArgs The @p IfIndex does not match the interface index of `InfraIf`.
*
*/
Error HandleStateChanged(uint32_t aIfIndex, bool aIsRunning);
/**
* This method converts the `InfraIf` to a human-readable string.
*
* @returns The string representation of `InfraIf`.
*
*/
InfoString ToString(void) const;
private:
bool mInitialized : 1;
bool mIsRunning : 1;
uint32_t mIfIndex;
};
} // namespace BorderRouter
} // namespace ot
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
#endif // INFRA_IF_HPP_

View File

@ -1,61 +0,0 @@
/*
* Copyright (c) 2020, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file implements infrastructure interface platform APIs.
*/
#include "openthread-core-config.h"
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
#include <openthread/platform/infra_if.h>
#include "border_router/routing_manager.hpp"
#include "common/as_core_type.hpp"
#include "common/instance.hpp"
using namespace ot;
extern "C" void otPlatInfraIfRecvIcmp6Nd(otInstance * aInstance,
uint32_t aInfraIfIndex,
const otIp6Address *aSrcAddress,
const uint8_t * aBuffer,
uint16_t aBufferLength)
{
AsCoreType(aInstance).Get<BorderRouter::RoutingManager>().RecvIcmp6Message(aInfraIfIndex, AsCoreType(aSrcAddress),
aBuffer, aBufferLength);
}
extern "C" otError otPlatInfraIfStateChanged(otInstance *aInstance, uint32_t aInfraIfIndex, bool aIsRunning)
{
return AsCoreType(aInstance).Get<BorderRouter::RoutingManager>().HandleInfraIfStateChanged(aInfraIfIndex,
aIsRunning);
}
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE

View File

@ -1,211 +0,0 @@
/*
* Copyright (c) 2020, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes implementations for ICMPv6 Router Advertisement.
*
*/
#include "border_router/router_advertisement.hpp"
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
#include "common/as_core_type.hpp"
#include "common/code_utils.hpp"
namespace ot {
namespace BorderRouter {
namespace RouterAdv {
const Option *Option::GetNextOption(const Option *aCurOption, const uint8_t *aBuffer, uint16_t aBufferLength)
{
const uint8_t *nextOption = nullptr;
const uint8_t *bufferEnd = aBuffer + aBufferLength;
VerifyOrExit(aBuffer != nullptr, nextOption = nullptr);
if (aCurOption == nullptr)
{
nextOption = aBuffer;
}
else
{
nextOption = reinterpret_cast<const uint8_t *>(aCurOption) + aCurOption->GetSize();
}
VerifyOrExit(nextOption + sizeof(Option) <= bufferEnd, nextOption = nullptr);
VerifyOrExit(reinterpret_cast<const Option *>(nextOption)->GetSize() > 0, nextOption = nullptr);
VerifyOrExit(nextOption + reinterpret_cast<const Option *>(nextOption)->GetSize() <= bufferEnd,
nextOption = nullptr);
exit:
return reinterpret_cast<const Option *>(nextOption);
}
PrefixInfoOption::PrefixInfoOption(void)
: Option(Type::kPrefixInfo, sizeof(*this) / kLengthUnit)
, mPrefixLength(0)
, mReserved1(0)
, mValidLifetime(0)
, mPreferredLifetime(0)
, mReserved2(0)
{
OT_UNUSED_VARIABLE(mReserved2);
mPrefix.Clear();
}
void PrefixInfoOption::SetOnLink(bool aOnLink)
{
if (aOnLink)
{
mReserved1 |= kOnLinkFlagMask;
}
else
{
mReserved1 &= ~kOnLinkFlagMask;
}
}
void PrefixInfoOption::SetAutoAddrConfig(bool aAutoAddrConfig)
{
if (aAutoAddrConfig)
{
mReserved1 |= kAutoConfigFlagMask;
}
else
{
mReserved1 &= ~kAutoConfigFlagMask;
}
}
void PrefixInfoOption::SetPrefix(const Ip6::Prefix &aPrefix)
{
mPrefixLength = aPrefix.mLength;
mPrefix = AsCoreType(&aPrefix.mPrefix);
}
Ip6::Prefix PrefixInfoOption::GetPrefix(void) const
{
Ip6::Prefix prefix;
prefix.Set(mPrefix.GetBytes(), mPrefixLength);
return prefix;
}
RouteInfoOption::RouteInfoOption(void)
: Option(Type::kRouteInfo, 0)
, mPrefixLength(0)
, mReserved(0)
, mRouteLifetime(0)
{
OT_UNUSED_VARIABLE(mReserved);
mPrefix.Clear();
}
void RouteInfoOption::SetPreference(RoutePreference aPreference)
{
mReserved &= ~kPreferenceMask;
mReserved |= (NetworkData::RoutePreferenceToValue(aPreference) << kPreferenceOffset) & kPreferenceMask;
}
RouteInfoOption::RoutePreference RouteInfoOption::GetPreference(void) const
{
return NetworkData::RoutePreferenceFromValue((mReserved & kPreferenceMask) >> kPreferenceOffset);
}
void RouteInfoOption::SetPrefix(const Ip6::Prefix &aPrefix)
{
// The total length (in bytes) of a Router Information Option
// is: (8 bytes fixed option header) + (0, 8, or 16 bytes prefix).
// Because the length of the option must be padded with 8 bytes,
// the length of the prefix (in bits) must be padded with 64 bits.
SetLength((aPrefix.mLength + kLengthUnit * CHAR_BIT - 1) / (kLengthUnit * CHAR_BIT) + 1);
mPrefixLength = aPrefix.mLength;
mPrefix = AsCoreType(&aPrefix.mPrefix);
}
Ip6::Prefix RouteInfoOption::GetPrefix(void) const
{
Ip6::Prefix prefix;
prefix.Set(mPrefix.GetBytes(), mPrefixLength);
return prefix;
}
bool RouteInfoOption::IsValid(void) const
{
return (GetLength() == 1 || GetLength() == 2 || GetLength() == 3) &&
(mPrefixLength <= OT_IP6_ADDRESS_SIZE * CHAR_BIT) && NetworkData::IsRoutePreferenceValid(GetPreference());
}
void RouterAdvMessage::SetToDefault(void)
{
mHeader.Clear();
mHeader.SetType(Ip6::Icmp::Header::kTypeRouterAdvert);
mReachableTime = 0;
mRetransTimer = 0;
}
const RouterAdvMessage &RouterAdvMessage::operator=(const RouterAdvMessage &aOther)
{
mHeader = aOther.mHeader;
// Set zero value and let platform do the calculation.
mHeader.SetChecksum(0);
mReachableTime = aOther.mReachableTime;
mRetransTimer = aOther.mRetransTimer;
return *this;
}
bool RouterAdvMessage::operator==(const RouterAdvMessage &aOther) const
{
return memcmp(&mHeader.mData, &aOther.mHeader.mData, sizeof(mHeader.mData)) == 0 &&
mReachableTime == aOther.mReachableTime && mRetransTimer == aOther.mRetransTimer;
}
RouterSolicitMessage::RouterSolicitMessage(void)
{
mHeader.Clear();
mHeader.SetType(Ip6::Icmp::Header::kTypeRouterSolicit);
}
} // namespace RouterAdv
} // namespace BorderRouter
} // namespace ot
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE

View File

@ -1,511 +0,0 @@
/*
* Copyright (c) 2020, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes definitions for IPv6 Router Advertisement.
*
* See RFC 4861: Neighbor Discovery for IP version 6 (https://tools.ietf.org/html/rfc4861).
*
*/
#ifndef ROUTER_ADVERTISEMENT_HPP_
#define ROUTER_ADVERTISEMENT_HPP_
#include "openthread-core-config.h"
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
#include <stdint.h>
#include <openthread/netdata.h>
#include <openthread/platform/toolchain.h>
#include "common/encoding.hpp"
#include "common/equatable.hpp"
#include "net/icmp6.hpp"
#include "net/ip6.hpp"
#include "thread/network_data_types.hpp"
using ot::Encoding::BigEndian::HostSwap16;
using ot::Encoding::BigEndian::HostSwap32;
namespace ot {
namespace BorderRouter {
namespace RouterAdv {
/**
* This class represents the variable length options in Neighbor
* Discovery messages.
*
* @sa PrefixInfoOption
* @sa RouteInfoOption
*
*/
OT_TOOL_PACKED_BEGIN
class Option
{
public:
enum class Type : uint8_t
{
kPrefixInfo = 3, ///< Prefix Information Option.
kRouteInfo = 24, ///< Route Information Option.
};
static constexpr uint8_t kLengthUnit = 8; ///< The unit of length in octets.
/**
* This constructor initializes the option with given type and length.
*
* @param[in] aType The type of this option.
* @param[in] aLength The length of this option in unit of 8 octets.
*
*/
explicit Option(Type aType, uint8_t aLength = 0)
: mType(aType)
, mLength(aLength)
{
}
/**
* This method returns the type of this option.
*
* @returns The option type.
*
*/
Type GetType(void) const { return mType; }
/**
* This method sets the size of the option (in bytes).
*
* Since the option must end on their natural 64-bits boundaries,
* the actual length set to the option is padded to (aSize + 7) / 8 * 8.
*
* @param[in] aSize The size of the option in unit of 1 byte.
*
*/
void SetSize(uint16_t aSize) { mLength = static_cast<uint8_t>((aSize + kLengthUnit - 1) / kLengthUnit); }
/**
* This method returns the size of the option (in bytes).
*
* @returns The size of the option in unit of 1 byte.
*
*/
uint16_t GetSize(void) const { return mLength * kLengthUnit; }
/**
* This method sets the length of the option (in unit of 8 bytes).
*
* @param[in] aLength The length of the option in unit of 8 bytes.
*
*/
void SetLength(uint8_t aLength) { mLength = aLength; }
/**
* This method returns the length of the option (in unit of 8 bytes).
*
* @returns The length of the option in unit of 8 bytes.
*
*/
uint16_t GetLength(void) const { return mLength; }
/**
* This helper method returns a pointer to the next valid option in the buffer.
*
* @param[in] aCurOption The current option. Use `nullptr` to get the first option.
* @param[in] aBuffer The buffer within which the options are held.
* @param[in] aBufferLength The length of the buffer.
*
* @returns A pointer to the next option if there are a valid one. Otherwise, `nullptr`.
*
*/
static const Option *GetNextOption(const Option *aCurOption, const uint8_t *aBuffer, uint16_t aBufferLength);
/**
* This method tells whether this option is valid.
*
* @return A boolean that indicates whether this option is valid.
*
*/
bool IsValid(void) const { return mLength > 0; }
private:
Type mType; // Type of the option.
uint8_t mLength; // Length of the option in unit of 8 octets,
// including the `type` and `length` fields.
} OT_TOOL_PACKED_END;
/**
* This class represents the Prefix Information Option.
*
* See section 4.6.2 of RFC 4861 for definition of this option.
* https://tools.ietf.org/html/rfc4861#section-4.6.2
*
*/
OT_TOOL_PACKED_BEGIN
class PrefixInfoOption : public Option
{
public:
/**
* This constructor initializes this option with zero prefix
* length, valid lifetime and preferred lifetime.
*
*/
PrefixInfoOption(void);
/**
* This method returns the on-link flag.
*
* @returns A boolean which indicates whether the on-link flag is set.
*
*/
bool GetOnLink(void) const { return (mReserved1 & kOnLinkFlagMask) != 0; }
/**
* This method sets the on-link (L) flag.
*
* @param[in] aOnLink A boolean indicates whether the prefix is on-link or off-link.
*
*/
void SetOnLink(bool aOnLink);
/**
* This method returns the autonomous address-configuration (A) flag.
*
* @returns A boolean which indicates whether the A flag is set.
*
*/
bool GetAutoAddrConfig(void) const { return (mReserved1 & kAutoConfigFlagMask) != 0; }
/**
* This method sets the autonomous address-configuration (A) flag.
*
* @param[in] aAutoAddrConfig A boolean indicates whether this prefix can be used
* for SLAAC.
*
*/
void SetAutoAddrConfig(bool aAutoAddrConfig);
/**
* This method set the valid lifetime of the prefix in seconds.
*
* @param[in] aValidLifetime The valid lifetime in seconds.
*
*/
void SetValidLifetime(uint32_t aValidLifetime) { mValidLifetime = HostSwap32(aValidLifetime); }
/**
* THis method returns the valid lifetime of the prefix in seconds.
*
* @returns The valid lifetime in seconds.
*
*/
uint32_t GetValidLifetime(void) const { return HostSwap32(mValidLifetime); }
/**
* This method sets the preferred lifetime of the prefix in seconds.
*
* @param[in] aPreferredLifetime The preferred lifetime in seconds.
*
*/
void SetPreferredLifetime(uint32_t aPreferredLifetime) { mPreferredLifetime = HostSwap32(aPreferredLifetime); }
/**
* THis method returns the preferred lifetime of the prefix in seconds.
*
* @returns The preferred lifetime in seconds.
*
*/
uint32_t GetPreferredLifetime(void) const { return HostSwap32(mPreferredLifetime); }
/**
* This method sets the prefix.
*
* @param[in] aPrefix The prefix contained in this option.
*
*/
void SetPrefix(const Ip6::Prefix &aPrefix);
/**
* This method returns the prefix in this option.
*
* @returns The IPv6 prefix in this option.
*
*/
Ip6::Prefix GetPrefix(void) const;
/**
* This method tells whether this option is valid.
*
* @returns A boolean indicates whether this option is valid.
*
*/
bool IsValid(void) const
{
return (GetSize() == sizeof(*this)) && (mPrefixLength <= OT_IP6_ADDRESS_SIZE * CHAR_BIT) &&
(GetPreferredLifetime() <= GetValidLifetime());
}
private:
static constexpr uint8_t kAutoConfigFlagMask = 0x40; // Bit mask of the Automatic Address Configure flag.
static constexpr uint8_t kOnLinkFlagMask = 0x80; // Bit mask of the On-link flag.
uint8_t mPrefixLength; // The prefix length in bits.
uint8_t mReserved1; // The reserved field.
uint32_t mValidLifetime; // The valid lifetime of the prefix.
uint32_t mPreferredLifetime; // The preferred lifetime of the prefix.
uint32_t mReserved2; // The reserved field.
Ip6::Address mPrefix; // The prefix.
} OT_TOOL_PACKED_END;
static_assert(sizeof(PrefixInfoOption) == 32, "invalid PrefixInfoOption structure");
/**
* This class represents the Route Information Option.
*
* See section 2.3 of RFC 4191 for definition of this option.
* https://tools.ietf.org/html/rfc4191#section-2.3
*
*/
OT_TOOL_PACKED_BEGIN
class RouteInfoOption : public Option
{
public:
/**
* This type represents a route preference.
*
*/
typedef NetworkData::RoutePreference RoutePreference;
/**
* This constructor initializes this option with zero prefix length.
*
*/
RouteInfoOption(void);
/**
* This method sets the route preference.
*
* @param[in] aPreference The route preference.
*
*/
void SetPreference(RoutePreference aPreference);
/**
* This method returns the route preference.
*
* @returns The route preference.
*
*/
RoutePreference GetPreference(void) const;
/**
* This method sets the lifetime of the route in seconds.
*
* @param[in] aLifetime The lifetime of the route in seconds.
*
*/
void SetRouteLifetime(uint32_t aLifetime) { mRouteLifetime = HostSwap32(aLifetime); }
/**
* This method returns Route Lifetime in seconds.
*
* @returns The Route Lifetime in seconds.
*
*/
uint32_t GetRouteLifetime(void) const { return HostSwap32(mRouteLifetime); }
/**
* This method sets the prefix.
*
* @param[in] aPrefix The prefix contained in this option.
*
*/
void SetPrefix(const Ip6::Prefix &aPrefix);
/**
* This method returns the prefix in this option.
*
* @returns The IPv6 prefix in this option.
*
*/
Ip6::Prefix GetPrefix(void) const;
/**
* This method tells whether this option is valid.
*
* @returns A boolean indicates whether this option is valid.
*
*/
bool IsValid(void) const;
private:
static constexpr uint8_t kPreferenceOffset = 3;
static constexpr uint8_t kPreferenceMask = 3 << kPreferenceOffset;
uint8_t mPrefixLength; // The prefix length in bits.
uint8_t mReserved; // The reserved field.
uint32_t mRouteLifetime; // The lifetime in seconds.
Ip6::Address mPrefix; // The prefix.
} OT_TOOL_PACKED_END;
static_assert(sizeof(RouteInfoOption) == 24, "invalid RouteInfoOption structure");
/**
* This class implements the Router Advertisement message.
*
* See section 4.2 of RFC 4861 for definition of this message.
* https://tools.ietf.org/html/rfc4861#section-4.2
*
*/
OT_TOOL_PACKED_BEGIN
class RouterAdvMessage : public Unequatable<RouterAdvMessage>
{
public:
/**
* This constructor initializes the Router Advertisement message with
* zero router lifetime, reachable time and retransmission timer.
*
*/
RouterAdvMessage(void) { SetToDefault(); }
/**
* This method sets the RA message to default values.
*
*/
void SetToDefault(void);
/**
* This method sets the checksum value.
*
* @param[in] aChecksum The checksum value.
*
*/
void SetChecksum(uint16_t aChecksum) { mHeader.SetChecksum(aChecksum); }
/**
* This method sets the Router Lifetime in seconds.
*
* Zero Router Lifetime means we are not a default router.
*
* @param[in] aRouterLifetime The router lifetime in seconds.
*
*/
void SetRouterLifetime(uint16_t aRouterLifetime)
{
mHeader.mData.m16[kRouteLifetimeIdx] = HostSwap16(aRouterLifetime);
}
/**
* This method returns the Router Lifetime.
*
* Zero Router Lifetime means we are not a default router.
*
* @returns The router lifetime in seconds.
*
*/
uint16_t GetRouterLifetime(void) const { return HostSwap16(mHeader.mData.m16[kRouteLifetimeIdx]); }
/**
* This method returns the Managed Address Configuration ('m') flag.
*
* @returns A boolean which indicates whether the 'm' flag is set.
*
*/
bool GetManagedAddrConfig(void) const { return (mHeader.mData.m8[kReservedIdx] & kManagedAddressConfigMask) != 0; }
/**
* This method overloads the assignment operator.
*
*/
const RouterAdvMessage &operator=(const RouterAdvMessage &aOther);
/**
* This method overloads operator `==` to evaluate whether or not
* two instances of `RouterAdvMessage` are equal.
*
* @param[in] aOther The other `RouterAdvMessage` instance to compare with.
*
* @retval TRUE If the two `RouterAdvMessage` instances are equal.
* @retval FALSE If the two `RouterAdvMessage` instances are not equal.
*
*/
bool operator==(const RouterAdvMessage &aOther) const;
private:
// The index of Route Lifetime in ICMPv6 Header Data. In unit of 2 octets.
static constexpr uint8_t kRouteLifetimeIdx = 1;
// The index of Reserved byte in ICMPv6 Header Data. In unit of 1 octet.
static constexpr uint8_t kReservedIdx = 1;
// The bitmask of the Managed Address Configuration ('m') flag.
static constexpr uint8_t kManagedAddressConfigMask = 0x80;
Ip6::Icmp::Header mHeader; // The common ICMPv6 header.
uint32_t mReachableTime; // The reachable time. In milliseconds.
uint32_t mRetransTimer; // The retransmission timer. In milliseconds.
} OT_TOOL_PACKED_END;
static_assert(sizeof(RouterAdvMessage) == 16, "invalid RouterAdvMessage structure");
/**
* This class implements the Router Solicitation message.
*
* See section 4.1 of RFC 4861 for definition of this message.
* https://tools.ietf.org/html/rfc4861#section-4.1
*
*/
OT_TOOL_PACKED_BEGIN
class RouterSolicitMessage
{
public:
/**
* This constructor initializes the Router Solicitation message.
*
*/
RouterSolicitMessage(void);
private:
Ip6::Icmp::Header mHeader; // The common ICMPv6 header.
} OT_TOOL_PACKED_END;
static_assert(sizeof(RouterSolicitMessage) == 8, "invalid RouterSolicitMessage structure");
} // namespace RouterAdv
} // namespace BorderRouter
} // namespace ot
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
#endif // ROUTER_ADVERTISEMENT_HPP_

File diff suppressed because it is too large Load Diff

View File

@ -48,15 +48,16 @@
#endif
#include <openthread/netdata.h>
#include <openthread/platform/infra_if.h>
#include "border_router/router_advertisement.hpp"
#include "border_router/infra_if.hpp"
#include "common/array.hpp"
#include "common/error.hpp"
#include "common/locator.hpp"
#include "common/notifier.hpp"
#include "common/string.hpp"
#include "common/timer.hpp"
#include "net/ip6.hpp"
#include "net/nd6.hpp"
#include "thread/network_data.hpp"
namespace ot {
@ -73,6 +74,7 @@ namespace BorderRouter {
class RoutingManager : public InstanceLocator
{
friend class ot::Notifier;
friend class ot::Instance;
public:
/**
@ -155,35 +157,21 @@ public:
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_NAT64_ENABLE
/**
* This method receives an ICMPv6 message on the infrastructure interface.
* This method processes a received ICMPv6 message from the infrastructure interface.
*
* Malformed or undesired messages are dropped silently.
*
* @param[in] aInfraIfIndex The infrastructure interface index.
* @param[in] aPacket The received ICMPv6 packet.
* @param[in] aSrcAddress The source address this message is sent from.
* @param[in] aBuffer THe ICMPv6 message buffer.
* @param[in] aLength The length of the ICMPv6 message buffer.
*
*/
void RecvIcmp6Message(uint32_t aInfraIfIndex,
const Ip6::Address &aSrcAddress,
const uint8_t * aBuffer,
uint16_t aBufferLength);
void HandleReceived(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress);
/**
* This method handles infrastructure interface state changes.
*
* @param[in] aInfraIfIndex The index of the infrastructure interface.
* @param[in] aIsRunning A boolean that indicates whether the infrastructure
* interface is running.
*
* @retval kErrorNone Successfully updated the infra interface status.
* @retval kErrorInvalidState The Routing Manager is not initialized.
* @retval kErrorInvalidArgs The @p aInfraIfIndex doesn't match the infra interface
* the Routing Manager is initialized with.
*
*/
Error HandleInfraIfStateChanged(uint32_t aInfraIfIndex, bool aIsRunning);
void HandleInfraIfStateChanged(void) { EvaluateState(); }
/**
* This method checks if the on-mesh prefix configuration is a valid OMR prefix.
@ -250,76 +238,162 @@ private:
// The value is chosen in range of [`kMaxRtrAdvInterval` upper bound (1800s), `kDefaultOnLinkPrefixLifetime`].
static constexpr uint32_t kRtrAdvStaleTime = 1800;
// The VICARIOUS_SOLICIT_TIME in seconds. The Routing Manager will consider
// the discovered prefixes invalid if they are not refreshed after receiving
// a Router Solicitation message.
// The value is equal to Router Solicitation timeout.
static constexpr uint32_t kVicariousSolicitationTime =
kRtrSolicitationInterval * (kMaxRtrSolicitations - 1) + kMaxRtrSolicitationDelay;
static_assert(kMinRtrAdvInterval <= 3 * kMaxRtrAdvInterval / 4, "invalid RA intervals");
static_assert(kDefaultOmrPrefixLifetime >= kMaxRtrAdvInterval, "invalid default OMR prefix lifetime");
static_assert(kDefaultOnLinkPrefixLifetime >= kMaxRtrAdvInterval, "invalid default on-link prefix lifetime");
static_assert(kRtrAdvStaleTime >= 1800 && kRtrAdvStaleTime <= kDefaultOnLinkPrefixLifetime,
"invalid RA STALE time");
// This struct represents an external prefix which is
// discovered on the infrastructure interface.
struct ExternalPrefix : public Clearable<ExternalPrefix>, public Unequatable<ExternalPrefix>
class DiscoveredPrefixTable : public InstanceLocator
{
Ip6::Prefix mPrefix;
uint32_t mValidLifetime;
// This class maintains the discovered on-link and route prefixes
// from the received RA messages by processing PIO and RIO options
// from the message. It takes care of processing the RA message but
// delegates the decision whether to include or exclude a prefix to
// `RoutingManager` by calling its `ShouldProcessPrefixInfoOption()`
// and `ShouldProcessRouteInfoOption()` methods.
//
// It manages the lifetime of the discovered entries and publishes
// and unpublishes the prefixes in the Network Data (as external
// route) as they are added or removed.
//
// When there is any change in the table (an entry is added, removed,
// or modified), it signals the change to `RoutingManager` by calling
// `HandleDiscoveredPrefixTableChanged()` callback. A `Tasklet` is
// used for signalling which ensures that if there are multiple
// changes within the same flow of execution, the callback is
// invoked after all the changes are processed.
union
public:
enum NetDataMode : uint8_t // Used in `Remove{}` methods
{
// Preferred Lifetime of on-link prefix, available
// only when `mIsOnLinkPrefix` is TRUE.
uint32_t mPreferredLifetime;
// The preference of this route, available
// only when `mIsOnLinkPrefix` is FALSE.
RoutePreference mRoutePreference;
kUnpublishFromNetData, // Unpublish the entry from Network Data if previously published.
kKeepInNetData, // Keep entry in Network Data if previously published.
};
TimeMilli mTimeLastUpdate;
bool mIsOnLinkPrefix;
bool operator==(const ExternalPrefix &aPrefix) const
explicit DiscoveredPrefixTable(Instance &aInstance);
void ProcessRouterAdvertMessage(const Ip6::Nd::RouterAdvertMessage &aRaMessage,
const Ip6::Address & aSrcAddress);
void FindFavoredOnLinkPrefix(Ip6::Prefix &aPrefix) const;
bool ContainsOnLinkPrefix(const Ip6::Prefix &aPrefix) const;
void RemoveOnLinkPrefix(const Ip6::Prefix &aPrefix, NetDataMode aNetDataMode);
bool ContainsRoutePrefix(const Ip6::Prefix &aPrefix) const;
void RemoveRoutePrefix(const Ip6::Prefix &aPrefix, NetDataMode aNetDataMode);
void RemoveAllEntries(void);
void RemoveOrDeprecateOldEntries(TimeMilli aTimeThreshold);
TimeMilli CalculateNextStaleTime(TimeMilli aNow) const;
private:
static constexpr uint8_t kMaxEntries = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES;
struct Entry : private Clearable<Entry>, public Unequatable<Entry>
{
return mPrefix == aPrefix.mPrefix && mIsOnLinkPrefix == aPrefix.mIsOnLinkPrefix;
}
public:
enum Type : uint8_t
{
kTypeOnLink,
kTypeRoute,
};
bool IsDeprecated(void) const
{
OT_ASSERT(mIsOnLinkPrefix);
struct Matcher
{
Matcher(const Ip6::Prefix &aPrefix, Type aType)
: mPrefix(aPrefix)
, mType(aType)
{
}
return mTimeLastUpdate + TimeMilli::SecToMsec(mPreferredLifetime) <= TimerMilli::GetNow();
}
const Ip6::Prefix &mPrefix;
bool mType;
};
TimeMilli GetExpireTime(void) const { return mTimeLastUpdate + GetPrefixExpireDelay(mValidLifetime); }
TimeMilli GetStaleTime(void) const
{
uint32_t delay = OT_MIN(kRtrAdvStaleTime, mIsOnLinkPrefix ? mPreferredLifetime : mValidLifetime);
void InitFrom(const Ip6::Nd::PrefixInfoOption &aPio);
void InitFrom(const Ip6::Nd::RouteInfoOption &aRio);
bool IsOnLinkPrefix(void) const { return (mType == kTypeOnLink); }
const Ip6::Prefix &GetPrefix(void) const { return mPrefix; }
const TimeMilli & GetLastUpdateTime(void) const { return mLastUpdateTime; }
uint32_t GetValidLifetime(void) const { return mValidLifetime; }
void ClearValidLifetime(void) { mValidLifetime = 0; }
TimeMilli GetExpireTime(void) const;
TimeMilli GetStaleTime(void) const;
bool operator==(const Entry &aOther) const;
bool Matches(const Matcher &aMatcher) const;
return mTimeLastUpdate + TimeMilli::SecToMsec(delay);
}
// Methods to use when `IsOnLinkPrefix()`
uint32_t GetPreferredLifetime(void) const { return mPreferredLifetime; }
void ClearPreferredLifetime(void) { mPreferredLifetime = 0; }
bool IsDeprecated(void) const;
void AdoptValidAndPreferredLiftimesFrom(const Entry &aEntry);
static uint32_t GetPrefixExpireDelay(uint32_t aValidLifetime);
// Method to use when `!IsOnlinkPrefix()`
RoutePreference GetRoutePreference(void) const { return mRoutePreference; }
private:
static uint32_t CalculateExpireDelay(uint32_t aValidLifetime);
Ip6::Prefix mPrefix;
TimeMilli mLastUpdateTime;
uint32_t mValidLifetime;
uint32_t mPreferredLifetime; // Applicable when prefix is on-link.
RoutePreference mRoutePreference; // Applicable when prefix is not on-link
Type mType;
};
typedef Array<Entry, kMaxEntries> EntryArray;
void RemovePrefix(const Ip6::Prefix &aPrefix, Entry::Type aType, NetDataMode aNetDataMode);
void ProcessPrefixInfoOption(const Ip6::Nd::PrefixInfoOption &aPio);
void ProcessRouteInfoOption(const Ip6::Nd::RouteInfoOption &aRio);
static void HandleTimer(Timer &aTimer);
void HandleTimer(void);
void RemoveExpiredEntries(void);
void SignalTableChanged(void);
static void HandleSignalTask(Tasklet &aTasklet);
EntryArray mEntries;
TimerMilli mTimer;
Tasklet mSignalTask;
};
typedef Array<Ip6::Prefix, kMaxOmrPrefixNum> OmrPrefixArray;
typedef Array<ExternalPrefix, kMaxDiscoveredPrefixNum> ExternalPrefixArray;
class OmrPrefix // An OMR Prefix
{
public:
static constexpr uint16_t kInfoStringSize = 60;
typedef String<kInfoStringSize> InfoString;
void Init(const Ip6::Prefix &aPrefix, RoutePreference aPreference);
void InitFrom(NetworkData::OnMeshPrefixConfig &aOnMeshPrefixConfig);
const Ip6::Prefix &GetPrefix(void) const { return mPrefix; }
RoutePreference GetPreference(void) const { return mPreference; }
void SetPreference(RoutePreference aPreference) { mPreference = aPreference; }
bool Matches(const Ip6::Prefix &aPrefix) const { return mPrefix == aPrefix; }
bool IsFavoredOver(const OmrPrefix &aOther) const;
InfoString ToString(void) const;
private:
Ip6::Prefix mPrefix;
RoutePreference mPreference;
};
typedef Array<OmrPrefix, kMaxOmrPrefixNum> OmrPrefixArray;
void EvaluateState(void);
void Start(void);
void Stop(void);
void HandleNotifierEvents(Events aEvents);
bool IsInitialized(void) const { return mInfraIfIndex != 0; }
bool IsInitialized(void) const { return mInfraIf.IsInitialized(); }
bool IsEnabled(void) const { return mIsEnabled; }
Error LoadOrGenerateRandomBrUlaPrefix(void);
void GenerateOmrPrefix(void);
Error LoadOrGenerateRandomOnLinkPrefix(void);
void GenerateOnLinkPrefix(void);
const Ip6::Prefix *EvaluateOnLinkPrefix(void);
void EvaluateOnLinkPrefix(void);
#if OPENTHREAD_CONFIG_BORDER_ROUTING_NAT64_ENABLE
void GenerateNat64Prefix(void);
@ -333,17 +407,13 @@ private:
Error PublishLocalOmrPrefix(void);
void UnpublishLocalOmrPrefix(void);
bool IsOmrPrefixAddedToLocalNetworkData(void) const;
Error AddExternalRoute(const Ip6::Prefix &aPrefix, RoutePreference aRoutePreference, bool aNat64 = false);
void RemoveExternalRoute(const Ip6::Prefix &aPrefix);
Error PublishExternalRoute(const Ip6::Prefix &aPrefix, RoutePreference aRoutePreference, bool aNat64 = false);
void UnpublishExternalRoute(const Ip6::Prefix &aPrefix);
void StartRouterSolicitationDelay(void);
Error SendRouterSolicitation(void);
void SendRouterAdvertisement(const OmrPrefixArray &aNewOmrPrefixes, const Ip6::Prefix *aNewOnLinkPrefix);
void SendRouterAdvertisement(const OmrPrefixArray &aNewOmrPrefixes);
bool IsRouterSolicitationInProgress(void) const;
#if OPENTHREAD_CONFIG_BORDER_ROUTING_VICARIOUS_RS_ENABLE
static void HandleVicariousRouterSolicitTimer(Timer &aTimer);
void HandleVicariousRouterSolicitTimer(void);
#endif
static void HandleRouterSolicitTimer(Timer &aTimer);
void HandleRouterSolicitTimer(void);
static void HandleDiscoveredPrefixInvalidTimer(Timer &aTimer);
@ -355,18 +425,17 @@ private:
static void HandleOnLinkPrefixDeprecateTimer(Timer &aTimer);
void DeprecateOnLinkPrefix(void);
void HandleRouterSolicit(const Ip6::Address &aSrcAddress, const uint8_t *aBuffer, uint16_t aBufferLength);
void HandleRouterAdvertisement(const Ip6::Address &aSrcAddress, const uint8_t *aBuffer, uint16_t aBufferLength);
bool UpdateDiscoveredOnLinkPrefix(const RouterAdv::PrefixInfoOption &aPio);
void UpdateDiscoveredOmrPrefix(const RouterAdv::RouteInfoOption &aRio);
void InvalidateDiscoveredPrefixes(const Ip6::Prefix *aPrefix = nullptr, bool aIsOnLinkPrefix = true);
void InvalidateAllDiscoveredPrefixes(void);
void HandleRouterSolicit(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress);
void HandleRouterAdvertisement(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress);
bool ShouldProcessPrefixInfoOption(const Ip6::Nd::PrefixInfoOption &aPio, const Ip6::Prefix &aPrefix);
bool ShouldProcessRouteInfoOption(const Ip6::Nd::RouteInfoOption &aRio, const Ip6::Prefix &aPrefix);
void HandleDiscoveredPrefixTableChanged(void);
bool NetworkDataContainsOmrPrefix(const Ip6::Prefix &aPrefix) const;
bool UpdateRouterAdvMessage(const RouterAdv::RouterAdvMessage *aRouterAdvMessage);
void UpdateRouterAdvertHeader(const Ip6::Nd::RouterAdvertMessage *aRouterAdvertMessage);
void ResetDiscoveredPrefixStaleTimer(void);
static bool IsValidBrUlaPrefix(const Ip6::Prefix &aBrUlaPrefix);
static bool IsValidOnLinkPrefix(const RouterAdv::PrefixInfoOption &aPio);
static bool IsValidOnLinkPrefix(const Ip6::Nd::PrefixInfoOption &aPio);
static bool IsValidOnLinkPrefix(const Ip6::Prefix &aOnLinkPrefix);
// Indicates whether the Routing Manager is running (started).
@ -376,13 +445,7 @@ private:
// Manager will be stopped if we are disabled.
bool mIsEnabled;
// Indicates whether the infra interface is running. The Routing
// Manager will be stopped when the Infra interface is not running.
bool mInfraIfIsRunning;
// The index of the infra interface on which Router Advertisement
// messages will be sent.
uint32_t mInfraIfIndex;
InfraIf mInfraIf;
// The /48 BR ULA prefix loaded from local persistent storage or
// randomly generated if none is found in persistent storage.
@ -399,6 +462,10 @@ private:
// advertised on infra link.
OmrPrefixArray mAdvertisedOmrPrefixes;
// The currently favored (smallest) discovered on-link prefix.
// Prefix length of zero indicates there is none.
Ip6::Prefix mFavoredDiscoveredOnLinkPrefix;
// The on-link prefix loaded from local persistent storage or
// randomly generated if non is found in persistent storage.
Ip6::Prefix mLocalOnLinkPrefix;
@ -416,29 +483,20 @@ private:
// True if the local NAT64 prefix is advertised in Thread network.
bool mIsAdvertisingLocalNat64Prefix;
// The array of prefixes discovered on the infra link. Those
// prefixes consist of on-link prefix(es) and OMR prefixes
// advertised by BRs in another Thread Network which is connected to
// the same infra link.
ExternalPrefixArray mDiscoveredPrefixes;
DiscoveredPrefixTable mDiscoveredPrefixTable;
// The RA header and parameters for the infra interface.
// This value is initialized with `RouterAdvMessage::SetToDefault`
// and updated with RA messages initiated from infra interface.
RouterAdv::RouterAdvMessage mRouterAdvMessage;
TimeMilli mTimeRouterAdvMessageLastUpdate;
bool mLearntRouterAdvMessageFromHost;
Ip6::Nd::RouterAdvertMessage::Header mRouterAdvertHeader;
TimeMilli mTimeRouterAdvMessageLastUpdate;
bool mLearntRouterAdvMessageFromHost;
TimerMilli mDiscoveredPrefixInvalidTimer;
TimerMilli mDiscoveredPrefixStaleTimer;
uint32_t mRouterAdvertisementCount;
TimeMilli mLastRouterAdvertisementSendTime;
#if OPENTHREAD_CONFIG_BORDER_ROUTING_VICARIOUS_RS_ENABLE
TimerMilli mVicariousRouterSolicitTimer;
TimeMilli mTimeVicariousRouterSolicitStart;
#endif
TimerMilli mRouterSolicitTimer;
TimeMilli mTimeRouterSolicitStart;
uint8_t mRouterSolicitCount;

View File

@ -310,6 +310,27 @@ public:
*/
IndexType IndexOf(const Type &aElement) const { return static_cast<IndexType>(&aElement - &mElements[0]); }
/**
* This method removes an element from the array.
*
* The @p aElement MUST be from the array, otherwise the behavior of this method is undefined.
*
* To remove @p aElement, it is replaced by the last element in array, so the order of items in the array can
* change after a call to this method.
*
* The method uses assignment `=` operator on `Type` to copy the last element in place of @p aElement.
*
*/
void Remove(Type &aElement)
{
Type *lastElement = PopBack();
if (lastElement != &aElement)
{
aElement = *lastElement;
}
}
/**
* This method finds the first match of a given entry in the array.
*
@ -430,6 +451,32 @@ public:
return FindMatching(aIndicator) != nullptr;
}
/**
* This template method removes the first element in the array matching a given indicator.
*
* This method behaves similar to `Remove()`, i.e., the matched element (if found) is replaced with the last element
* in the array (using `=` operator on `Type`). So the order of items in the array can change after a call to this
* method.
*
* The template type `Indicator` specifies the type of @p aIndicator object which is used to match against elements
* in the array. To check that an element matches the given indicator, the `Matches()` method is invoked on each
* `Type` element in the array. The `Matches()` method should be provided by `Type` class accordingly:
*
* bool Type::Matches(const Indicator &aIndicator) const
*
* @param[in] aIndicator An indicator to match with elements in the array.
*
*/
template <typename Indicator> void RemoveMatching(const Indicator &aIndicator)
{
Type *entry = FindMatching(aIndicator);
if (entry != nullptr)
{
Remove(*entry);
}
}
/**
* This method overloads assignment `=` operator to copy elements from another array into the array.
*

View File

@ -972,6 +972,11 @@ template <> inline BorderRouter::RoutingManager &Instance::Get(void)
{
return mRoutingManager;
}
template <> inline BorderRouter::InfraIf &Instance::Get(void)
{
return mRoutingManager.mInfraIf;
}
#endif
#if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE

View File

@ -146,15 +146,15 @@ const char *SettingsBase::KeyToString(Key aKey)
"NetworkInfo", // (3) kKeyNetworkInfo
"ParentInfo", // (4) kKeyParentInfo
"ChildInfo", // (5) kKeyChildInfo
"", // (6) kKeyReserved
"", // (6) Removed (previously auto-start).
"SlaacIidSecretKey", // (7) kKeySlaacIidSecretKey
"DadInfo", // (8) kKeyDadInfo
"LegacyOmrPrefix", // (9) kKeyLegacyOmrPrefix
"OnLinkPrefix", // (10) kKeyOnLinkPrefix
"", // (9) Removed (previously OMR prefix).
"", // (10) Removed (previously on-link prefix).
"SrpEcdsaKey", // (11) kKeySrpEcdsaKey
"SrpClientInfo", // (12) kKeySrpClientInfo
"SrpServerInfo", // (13) kKeySrpServerInfo
"LegacyNat64Prefix", // (14) kKeyLegacyNat64Prefix
"", // (14) Removed (previously NAT64 prefix)
"BrUlaPrefix", // (15) kKeyBrUlaPrefix
};
@ -163,15 +163,11 @@ const char *SettingsBase::KeyToString(Key aKey)
static_assert(3 == kKeyNetworkInfo, "kKeyNetworkInfo value is incorrect");
static_assert(4 == kKeyParentInfo, "kKeyParentInfo value is incorrect");
static_assert(5 == kKeyChildInfo, "kKeyChildInfo value is incorrect");
static_assert(6 == kKeyReserved, "kKeyReserved value is incorrect");
static_assert(7 == kKeySlaacIidSecretKey, "kKeySlaacIidSecretKey value is incorrect");
static_assert(8 == kKeyDadInfo, "kKeyDadInfo value is incorrect");
static_assert(9 == kKeyLegacyOmrPrefix, "kKeyLegacyOmrPrefix value is incorrect");
static_assert(10 == kKeyOnLinkPrefix, "kKeyOnLinkPrefix value is incorrect");
static_assert(11 == kKeySrpEcdsaKey, "kKeySrpEcdsaKey value is incorrect");
static_assert(12 == kKeySrpClientInfo, "kKeySrpClientInfo value is incorrect");
static_assert(13 == kKeySrpServerInfo, "kKeySrpServerInfo value is incorrect");
static_assert(14 == kKeyLegacyNat64Prefix, "kKeyLegacyNat64Prefix value is incorrect");
static_assert(15 == kKeyBrUlaPrefix, "kKeyBrUlaPrefix value is incorrect");
static_assert(kLastKey == kKeyBrUlaPrefix, "kLastKey is not valid");
@ -435,9 +431,6 @@ void Settings::Log(Action aAction, Error aError, Key aKey, const void *aValue)
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
case kKeyBrUlaPrefix:
case kKeyLegacyOmrPrefix:
case kKeyOnLinkPrefix:
case kKeyLegacyNat64Prefix:
LogPrefix(aAction, aKey, *reinterpret_cast<const Ip6::Prefix *>(aValue));
break;
#endif

View File

@ -112,15 +112,11 @@ public:
kKeyNetworkInfo = OT_SETTINGS_KEY_NETWORK_INFO,
kKeyParentInfo = OT_SETTINGS_KEY_PARENT_INFO,
kKeyChildInfo = OT_SETTINGS_KEY_CHILD_INFO,
kKeyReserved = OT_SETTINGS_KEY_RESERVED,
kKeySlaacIidSecretKey = OT_SETTINGS_KEY_SLAAC_IID_SECRET_KEY,
kKeyDadInfo = OT_SETTINGS_KEY_DAD_INFO,
kKeyLegacyOmrPrefix = OT_SETTINGS_KEY_LEGACY_OMR_PREFIX,
kKeyOnLinkPrefix = OT_SETTINGS_KEY_ON_LINK_PREFIX,
kKeySrpEcdsaKey = OT_SETTINGS_KEY_SRP_ECDSA_KEY,
kKeySrpClientInfo = OT_SETTINGS_KEY_SRP_CLIENT_INFO,
kKeySrpServerInfo = OT_SETTINGS_KEY_SRP_SERVER_INFO,
kKeyLegacyNat64Prefix = OT_SETTINGS_KEY_LEGACY_NAT64_PREFIX,
kKeyBrUlaPrefix = OT_SETTINGS_KEY_BR_ULA_PREFIX,
};
@ -583,37 +579,7 @@ public:
private:
BrUlaPrefix(void) = default;
};
/**
* This class defines constants and types for legacy OMR prefix settings.
*
*/
class LegacyOmrPrefix
{
public:
static constexpr Key kKey = kKeyLegacyOmrPrefix; ///< The associated key.
typedef Ip6::Prefix ValueType; ///< The associated value type.
private:
LegacyOmrPrefix(void) = default;
};
/**
* This class defines constants and types for on-link prefix settings.
*
*/
class OnLinkPrefix
{
public:
static constexpr Key kKey = kKeyOnLinkPrefix; ///< The associated key.
typedef Ip6::Prefix ValueType; ///< The associated value type.
private:
OnLinkPrefix(void) = default;
};
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
#endif
#if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
/**

View File

@ -94,6 +94,13 @@ void TimeTicker::HandleTimer(void)
Get<AddressResolver>().HandleTimeTick();
}
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
if (mReceivers & Mask(kNetworkDataNotifier))
{
Get<NetworkData::Notifier>().HandleTimeTick();
}
#endif
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
if (mReceivers & Mask(kChildSupervisor))
{

View File

@ -71,6 +71,7 @@ public:
kIp6FragmentReassembler, ///< `Ip6::Ip6` (handling of fragmented messages)
kDuaManager, ///< `DuaManager`
kMlrManager, ///< `MlrManager`
kNetworkDataNotifier, ///< `NetworkData::Notifier`
kNumReceivers, ///< Number of receivers.
};

View File

@ -55,6 +55,32 @@
#define OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE 0
#endif
/**
* @def OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
*
* Define to 1 to enable mechanism on a Border Router which provides IP connectivity to request router role upgrade.
*
* This config is applicable on an `OPENTHREAD_FTD` build and when `OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE` is also
* enabled.
*
* A Border Router is considered to provide external IP connectivity if at least one of the below conditions hold:
*
* - It has added at least one external route entry.
* - It has added at least one prefix entry with default-route and on-mesh flags set.
* - It has added at least one domain prefix (domain and on-mesh flags set).
*
* A Border Router which provides IP connectivity and is acting as a REED is eligible to request a router role upgrade
* by sending an "Address Solicit" request to leader with status reason `BorderRouterRequest`. This reason is used when
* the number of active routers in the Thread mesh is above the threshold, and only if the number of existing eligible
* BRs (determined from the Thread Network Data) that are acting as router is less than two. This mechanism allows up
* to two eligible Border Routers to request router role upgrade when the number of routers is already above the
* threshold.
*
*/
#ifndef OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
#define OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE 1
#endif
/**
* @def OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
*
@ -75,16 +101,6 @@
#define OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES 8
#endif
/**
* @def OPENTHREAD_CONFIG_BORDER_ROUTING_VICARIOUS_RS_ENABLE
*
* Define to 1 to enable Border Routing Vicarious Router Solicitation.
*
*/
#ifndef OPENTHREAD_CONFIG_BORDER_ROUTING_VICARIOUS_RS_ENABLE
#define OPENTHREAD_CONFIG_BORDER_ROUTING_VICARIOUS_RS_ENABLE 1
#endif
/**
* @def OPENTHREAD_CONFIG_BORDER_ROUTING_NAT64_ENABLE
*

View File

@ -499,4 +499,26 @@
#define OPENTHREAD_CONFIG_MAC_SCAN_DURATION 300
#endif
/**
* @def OPENTHREAD_CONFIG_MAC_BEACON_PAYLOAD_PARSING_ENABLE
*
* This setting configures if the beacon payload parsing needs to be enabled in MAC. This is optional and is disabled by
* default because Thread 1.2.1 has removed support for beacon payloads.
*
*/
#ifndef OPENTHREAD_CONFIG_MAC_BEACON_PAYLOAD_PARSING_ENABLE
#define OPENTHREAD_CONFIG_MAC_BEACON_PAYLOAD_PARSING_ENABLE 0
#endif
/**
* @def OPENTHREAD_CONFIG_MAC_OUTGOING_BEACON_PAYLOAD_ENABLE
*
* This setting configures if the beacon payload needs to be enabled in outgoing beacon frames. This is optional and is
* disabled by default because Thread 1.2.1 has removed support for beacon payloads.
*
*/
#ifndef OPENTHREAD_CONFIG_MAC_OUTGOING_BEACON_PAYLOAD_ENABLE
#define OPENTHREAD_CONFIG_MAC_OUTGOING_BEACON_PAYLOAD_ENABLE 0
#endif
#endif // CONFIG_MAC_H_

View File

@ -35,6 +35,7 @@
#ifndef CONFIG_NETDATA_PUBLISHER_H_
#define CONFIG_NETDATA_PUBLISHER_H_
#include "config/border_router.h"
#include "config/srp_server.h"
/**
@ -48,7 +49,8 @@
*
*/
#ifndef OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
#define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
#define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE \
(OPENTHREAD_CONFIG_SRP_SERVER_ENABLE || OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE)
#endif
/**
@ -149,7 +151,13 @@
*
*/
#ifndef OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
#define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES \
(OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES + 5)
#else
#define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES 3
#endif
#endif
#endif // CONFIG_NETDATA_PUBLISHER_H_

View File

@ -623,4 +623,8 @@
#error "OPENTHREAD_CONFIG_PLATFORM_CSL_UNCERT was removed and no longer supported"
#endif
#ifdef OPENTHREAD_CONFIG_BORDER_ROUTING_VICARIOUS_RS_ENABLE
#error "OPENTHREAD_CONFIG_BORDER_ROUTING_VICARIOUS_RS_ENABLE was removed and no longer supported"
#endif
#endif // OPENTHREAD_CORE_CONFIG_CHECK_H_

View File

@ -123,11 +123,6 @@ exit:
StopPolling();
break;
case kErrorAlready:
LogDebg("Data poll tx requested when a previous data request still in send queue.");
ScheduleNextPoll(kUsePreviousPollPeriod);
break;
default:
LogWarn("Unexpected error %s requesting data poll", ErrorToString(error));
ScheduleNextPoll(kRecalculatePollPeriod);

View File

@ -164,6 +164,7 @@ public:
* @param[in] aCallback A pointer to a function called on completion of a scanned channel.
*
* @retval kErrorNone Successfully started scanning the channel.
* @retval kErrorBusy The radio is performing energy scanning.
* @retval kErrorNotImplemented The radio doesn't support energy scanning.
* @retval kErrorInvalidState If the raw link-layer isn't enabled.
*

View File

@ -210,6 +210,11 @@ Error Mac::ConvertBeaconToActiveScanResult(const RxFrame *aBeaconFrame, ActiveSc
{
Error error = kErrorNone;
Address address;
#if OPENTHREAD_CONFIG_MAC_BEACON_PAYLOAD_PARSING_ENABLE
const BeaconPayload *beaconPayload = nullptr;
const Beacon * beacon = nullptr;
uint16_t payloadLength;
#endif
memset(&aResult, 0, sizeof(ActiveScanResult));
@ -229,6 +234,23 @@ Error Mac::ConvertBeaconToActiveScanResult(const RxFrame *aBeaconFrame, ActiveSc
aResult.mRssi = aBeaconFrame->GetRssi();
aResult.mLqi = aBeaconFrame->GetLqi();
#if OPENTHREAD_CONFIG_MAC_BEACON_PAYLOAD_PARSING_ENABLE
payloadLength = aBeaconFrame->GetPayloadLength();
beacon = reinterpret_cast<const Beacon *>(aBeaconFrame->GetPayload());
beaconPayload = reinterpret_cast<const BeaconPayload *>(beacon->GetPayload());
if ((payloadLength >= (sizeof(*beacon) + sizeof(*beaconPayload))) && beacon->IsValid() && beaconPayload->IsValid())
{
aResult.mVersion = beaconPayload->GetProtocolVersion();
aResult.mIsJoinable = beaconPayload->IsJoiningPermitted();
aResult.mIsNative = beaconPayload->IsNative();
IgnoreError(AsCoreType(&aResult.mNetworkName).Set(beaconPayload->GetNetworkName()));
VerifyOrExit(IsValidUtf8String(aResult.mNetworkName.m8), error = kErrorParse);
aResult.mExtendedPanId = beaconPayload->GetExtendedPanId();
}
#endif
LogBeacon("Received");
exit:
@ -482,7 +504,7 @@ Error Mac::RequestDataPollTransmission(void)
Error error = kErrorNone;
VerifyOrExit(IsEnabled(), error = kErrorInvalidState);
VerifyOrExit(!IsActiveOrPending(kOperationTransmitPoll), error = kErrorAlready);
VerifyOrExit(!IsActiveOrPending(kOperationTransmitPoll));
// We ensure data frame and data poll tx requests are handled in the
// order they are requested. So if we have a pending direct data frame
@ -715,6 +737,10 @@ TxFrame *Mac::PrepareBeacon(void)
TxFrame *frame;
uint16_t fcf;
Beacon * beacon = nullptr;
#if OPENTHREAD_CONFIG_MAC_OUTGOING_BEACON_PAYLOAD_ENABLE
uint8_t beaconLength;
BeaconPayload *beaconPayload = nullptr;
#endif
#if OPENTHREAD_CONFIG_MULTI_RADIO
OT_ASSERT(!mTxBeaconRadioLinks.IsEmpty());
@ -732,6 +758,30 @@ TxFrame *Mac::PrepareBeacon(void)
beacon = reinterpret_cast<Beacon *>(frame->GetPayload());
beacon->Init();
#if OPENTHREAD_CONFIG_MAC_OUTGOING_BEACON_PAYLOAD_ENABLE
beaconLength = sizeof(*beacon);
beaconPayload = reinterpret_cast<BeaconPayload *>(beacon->GetPayload());
beaconPayload->Init();
if (IsJoinable())
{
beaconPayload->SetJoiningPermitted();
}
else
{
beaconPayload->ClearJoiningPermitted();
}
beaconPayload->SetNetworkName(Get<MeshCoP::NetworkNameManager>().GetNetworkName().GetAsData());
beaconPayload->SetExtendedPanId(Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId());
beaconLength += sizeof(*beaconPayload);
frame->SetPayloadLength(beaconLength);
#endif
LogBeacon("Sending");
return frame;

View File

@ -228,7 +228,6 @@ public:
* This method requests transmission of a data poll (MAC Data Request) frame.
*
* @retval kErrorNone Data poll transmission request is scheduled successfully.
* @retval kErrorAlready MAC is busy sending earlier poll transmission request.
* @retval kErrorInvalidState The MAC layer is not enabled.
*
*/

View File

@ -43,6 +43,7 @@
#include "common/const_cast.hpp"
#include "common/encoding.hpp"
#include "mac/mac_types.hpp"
#include "meshcop/network_name.hpp"
namespace ot {
namespace Mac {
@ -1482,6 +1483,145 @@ private:
uint8_t mPendingAddressSpec;
} OT_TOOL_PACKED_END;
/**
* This class implements IEEE 802.15.4 Beacon Payload generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class BeaconPayload
{
public:
static constexpr uint8_t kProtocolId = 3; ///< Thread Protocol ID.
static constexpr uint8_t kProtocolVersion = 2; ///< Thread Protocol version.
static constexpr uint8_t kVersionOffset = 4; ///< Version field bit offset.
static constexpr uint8_t kVersionMask = 0xf << kVersionOffset; ///< Version field mask.
static constexpr uint8_t kNativeFlag = 1 << 3; ///< Native Commissioner flag.
static constexpr uint8_t kJoiningFlag = 1 << 0; ///< Joining Permitted flag.
/**
* This method initializes the Beacon Payload.
*
*/
void Init(void)
{
mProtocolId = kProtocolId;
mFlags = kProtocolVersion << kVersionOffset;
}
/**
* This method indicates whether or not the beacon appears to be a valid Thread Beacon Payload.
*
* @retval TRUE If the beacon appears to be a valid Thread Beacon Payload.
* @retval FALSE If the beacon does not appear to be a valid Thread Beacon Payload.
*
*/
bool IsValid(void) const { return (mProtocolId == kProtocolId); }
/**
* This method returns the Protocol ID value.
*
* @returns the Protocol ID value.
*
*/
uint8_t GetProtocolId(void) const { return mProtocolId; }
/**
* This method returns the Protocol Version value.
*
* @returns The Protocol Version value.
*
*/
uint8_t GetProtocolVersion(void) const { return mFlags >> kVersionOffset; }
/**
* This method indicates whether or not the Native Commissioner flag is set.
*
* @retval TRUE If the Native Commissioner flag is set.
* @retval FALSE If the Native Commissioner flag is not set.
*
*/
bool IsNative(void) const { return (mFlags & kNativeFlag) != 0; }
/**
* This method clears the Native Commissioner flag.
*
*/
void ClearNative(void) { mFlags &= ~kNativeFlag; }
/**
* This method sets the Native Commissioner flag.
*
*/
void SetNative(void) { mFlags |= kNativeFlag; }
/**
* This method indicates whether or not the Joining Permitted flag is set.
*
* @retval TRUE If the Joining Permitted flag is set.
* @retval FALSE If the Joining Permitted flag is not set.
*
*/
bool IsJoiningPermitted(void) const { return (mFlags & kJoiningFlag) != 0; }
/**
* This method clears the Joining Permitted flag.
*
*/
void ClearJoiningPermitted(void) { mFlags &= ~kJoiningFlag; }
/**
* This method sets the Joining Permitted flag.
*
*/
void SetJoiningPermitted(void)
{
mFlags |= kJoiningFlag;
#if OPENTHREAD_CONFIG_MAC_JOIN_BEACON_VERSION != 2 // check against kProtocolVersion
mFlags &= ~kVersionMask;
mFlags |= OPENTHREAD_CONFIG_MAC_JOIN_BEACON_VERSION << kVersionOffset;
#endif
}
/**
* This method gets the Network Name field.
*
* @returns The Network Name field as `NameData`.
*
*/
MeshCoP::NameData GetNetworkName(void) const { return MeshCoP::NameData(mNetworkName, sizeof(mNetworkName)); }
/**
* This method sets the Network Name field.
*
* @param[in] aNameData The Network Name (as a `NameData`).
*
*/
void SetNetworkName(const MeshCoP::NameData &aNameData) { aNameData.CopyTo(mNetworkName, sizeof(mNetworkName)); }
/**
* This method returns the Extended PAN ID field.
*
* @returns The Extended PAN ID field.
*
*/
const otExtendedPanId &GetExtendedPanId(void) const { return mExtendedPanId; }
/**
* This method sets the Extended PAN ID field.
*
* @param[in] aExtPanId An Extended PAN ID.
*
*/
void SetExtendedPanId(const otExtendedPanId &aExtPanId) { mExtendedPanId = aExtPanId; }
private:
uint8_t mProtocolId;
uint8_t mFlags;
char mNetworkName[MeshCoP::NetworkName::kMaxSize];
otExtendedPanId mExtendedPanId;
} OT_TOOL_PACKED_END;
/**
* This class implements CSL IE data structure.
*

View File

@ -572,6 +572,7 @@ public:
* @param[in] aScanDuration The duration, in milliseconds, for the channel to be scanned.
*
* @retval kErrorNone Successfully started scanning the channel.
* @retval kErrorBusy The radio is performing energy scanning.
* @retval kErrorInvalidState The radio was disabled or transmitting.
* @retval kErrorNotImplemented Energy scan is not supported by radio link.
*

View File

@ -379,6 +379,7 @@ public:
* @param[in] aScanDuration The duration, in milliseconds, for the channel to be scanned.
*
* @retval kErrorNone Successfully started scanning the channel.
* @retval kErrorBusy The radio is performing energy scanning.
* @retval kErrorInvalidState The radio was disabled or transmitting.
* @retval kErrorNotImplemented Energy scan is not supported (applicable in link-raw/radio mode only).
*

View File

@ -588,7 +588,7 @@ void BorderAgent::Start(void)
mState = kStateStarted;
mUdpProxyPort = 0;
LogInfo("Border Agent start listening on port %d", kBorderAgentUdpPort);
LogInfo("Border Agent start listening on port %u", GetUdpPort());
exit:
if (error != kErrorNone)

View File

@ -43,6 +43,7 @@
#include "common/log.hpp"
#include "mac/mac_types.hpp"
#include "meshcop/meshcop_tlvs.hpp"
#include "meshcop/timestamp.hpp"
#include "thread/mle_tlvs.hpp"
namespace ot {
@ -69,10 +70,12 @@ Error Dataset::Info::GenerateRandom(Instance &aInstance)
Clear();
mActiveTimestamp = 1;
mChannel = preferredChannels.ChooseRandomChannel();
mChannelMask = supportedChannels.GetMask();
mPanId = Mac::GenerateRandomPanId();
mActiveTimestamp.mSeconds = 1;
mActiveTimestamp.mTicks = 0;
mActiveTimestamp.mAuthoritative = false;
mChannel = preferredChannels.ChooseRandomChannel();
mChannelMask = supportedChannels.GetMask();
mPanId = Mac::GenerateRandomPanId();
AsCoreType(&mSecurityPolicy).SetToDefault();
SuccessOrExit(error = AsCoreType(&mNetworkKey).GenerateRandom());
@ -193,7 +196,7 @@ void Dataset::ConvertTo(Info &aDatasetInfo) const
switch (cur->GetType())
{
case Tlv::kActiveTimestamp:
aDatasetInfo.SetActiveTimestamp(As<ActiveTimestampTlv>(cur)->GetTimestamp().GetSeconds());
aDatasetInfo.SetActiveTimestamp(As<ActiveTimestampTlv>(cur)->GetTimestamp());
break;
case Tlv::kChannel:
@ -237,7 +240,7 @@ void Dataset::ConvertTo(Info &aDatasetInfo) const
break;
case Tlv::kPendingTimestamp:
aDatasetInfo.SetPendingTimestamp(As<PendingTimestampTlv>(cur)->GetTimestamp().GetSeconds());
aDatasetInfo.SetPendingTimestamp(As<PendingTimestampTlv>(cur)->GetTimestamp());
break;
case Tlv::kPskc:
@ -286,20 +289,18 @@ Error Dataset::SetFrom(const Info &aDatasetInfo)
if (aDatasetInfo.IsActiveTimestampPresent())
{
Timestamp timestamp;
Timestamp activeTimestamp;
timestamp.Clear();
timestamp.SetSeconds(aDatasetInfo.GetActiveTimestamp());
IgnoreError(SetTlv(Tlv::kActiveTimestamp, timestamp));
aDatasetInfo.GetActiveTimestamp(activeTimestamp);
IgnoreError(SetTlv(Tlv::kActiveTimestamp, activeTimestamp));
}
if (aDatasetInfo.IsPendingTimestampPresent())
{
Timestamp timestamp;
Timestamp pendingTimestamp;
timestamp.Clear();
timestamp.SetSeconds(aDatasetInfo.GetPendingTimestamp());
IgnoreError(SetTlv(Tlv::kPendingTimestamp, timestamp));
aDatasetInfo.GetPendingTimestamp(pendingTimestamp);
IgnoreError(SetTlv(Tlv::kPendingTimestamp, pendingTimestamp));
}
if (aDatasetInfo.IsDelayPresent())

View File

@ -203,7 +203,7 @@ public:
* @returns The Active Timestamp in the Dataset.
*
*/
uint64_t GetActiveTimestamp(void) const { return mActiveTimestamp; }
void GetActiveTimestamp(Timestamp &aTimestamp) const { aTimestamp.SetFromTimestamp(mActiveTimestamp); }
/**
* This method sets the Active Timestamp in the Dataset.
@ -211,9 +211,9 @@ public:
* @param[in] aTimestamp A Timestamp value.
*
*/
void SetActiveTimestamp(uint64_t aTimestamp)
void SetActiveTimestamp(const Timestamp &aTimestamp)
{
mActiveTimestamp = aTimestamp;
aTimestamp.ConvertTo(mActiveTimestamp);
mComponents.mIsActiveTimestampPresent = true;
}
@ -234,7 +234,7 @@ public:
* @returns The Pending Timestamp in the Dataset.
*
*/
uint64_t GetPendingTimestamp(void) const { return mPendingTimestamp; }
void GetPendingTimestamp(Timestamp &aTimestamp) const { aTimestamp.SetFromTimestamp(mPendingTimestamp); }
/**
* This method sets the Pending Timestamp in the Dataset.
@ -242,9 +242,9 @@ public:
* @param[in] aTimestamp A Timestamp value.
*
*/
void SetPendingTimestamp(uint64_t aTimestamp)
void SetPendingTimestamp(const Timestamp &aTimestamp)
{
mPendingTimestamp = aTimestamp;
aTimestamp.ConvertTo(mPendingTimestamp);
mComponents.mIsPendingTimestampPresent = true;
}

View File

@ -41,6 +41,7 @@
#include "common/locator_getters.hpp"
#include "common/log.hpp"
#include "common/random.hpp"
#include "meshcop/timestamp.hpp"
namespace ot {
namespace MeshCoP {
@ -193,9 +194,17 @@ void DatasetUpdater::HandleNotifierEvents(Events aEvents)
{
Finish(kErrorNone);
}
else if (requestedDataset.GetActiveTimestamp() <= dataset.GetActiveTimestamp())
else
{
Finish(kErrorAlready);
Timestamp requestedDatasetTimestamp;
Timestamp activeDatasetTimestamp;
requestedDataset.GetActiveTimestamp(requestedDatasetTimestamp);
dataset.GetActiveTimestamp(activeDatasetTimestamp);
if (Timestamp::Compare(requestedDatasetTimestamp, activeDatasetTimestamp) <= 0)
{
Finish(kErrorAlready);
}
}
}

View File

@ -38,13 +38,23 @@
namespace ot {
namespace MeshCoP {
void Timestamp::ConvertTo(otTimestamp &aTimestamp) const
{
aTimestamp.mSeconds = GetSeconds();
aTimestamp.mTicks = GetTicks();
aTimestamp.mAuthoritative = GetAuthoritative();
}
void Timestamp::SetFromTimestamp(const otTimestamp &aTimestamp)
{
SetSeconds(aTimestamp.mSeconds);
SetTicks(aTimestamp.mTicks);
SetAuthoritative(aTimestamp.mAuthoritative);
}
int Timestamp::Compare(const Timestamp *aFirst, const Timestamp *aSecond)
{
int rval;
uint64_t firstSeconds;
uint64_t secondSeconds;
uint16_t firstTicks;
uint16_t secondTicks;
int rval;
if (aFirst == nullptr)
{
@ -62,22 +72,46 @@ int Timestamp::Compare(const Timestamp *aFirst, const Timestamp *aSecond)
// Both are non-null.
firstSeconds = aFirst->GetSeconds();
secondSeconds = aSecond->GetSeconds();
rval = Compare(*aFirst, *aSecond);
exit:
return rval;
}
int Timestamp::Compare(const Timestamp &aFirst, const Timestamp &aSecond)
{
int rval;
uint64_t firstSeconds;
uint64_t secondSeconds;
uint16_t firstTicks;
uint16_t secondTicks;
bool firstAuthoritative;
bool secondAuthoritative;
firstSeconds = aFirst.GetSeconds();
secondSeconds = aSecond.GetSeconds();
if (firstSeconds != secondSeconds)
{
ExitNow(rval = (firstSeconds > secondSeconds) ? 1 : -1);
}
firstTicks = aFirst->GetTicks();
secondTicks = aSecond->GetTicks();
firstTicks = aFirst.GetTicks();
secondTicks = aSecond.GetTicks();
if (firstTicks != secondTicks)
{
ExitNow(rval = (firstTicks > secondTicks) ? 1 : -1);
}
firstAuthoritative = aFirst.GetAuthoritative();
secondAuthoritative = aSecond.GetAuthoritative();
if (firstAuthoritative != secondAuthoritative)
{
ExitNow(rval = firstAuthoritative ? 1 : -1);
}
rval = 0;
exit:

View File

@ -39,6 +39,7 @@
#include <string.h>
#include <openthread/dataset.h>
#include <openthread/platform/toolchain.h>
#include "common/clearable.hpp"
@ -59,6 +60,18 @@ OT_TOOL_PACKED_BEGIN
class Timestamp : public Clearable<Timestamp>
{
public:
/**
* This method converts the timestamp to `otTimestamp`.
*
*/
void ConvertTo(otTimestamp &aTimestamp) const;
/**
* This method sets the timestamp from `otTimestamp`.
*
*/
void SetFromTimestamp(const otTimestamp &aTimestamp);
/**
* This method returns the Seconds value.
*
@ -127,6 +140,15 @@ public:
*/
void AdvanceRandomTicks(void);
/**
* This method indicates whether the timestamp indicates an MLE Orphan Announce message.
*
* @retval TRUE The timestamp indicates an Orphan Announce message.
* @retval FALSE If the timestamp does not indicate an Orphan Announce message.
*
*/
bool IsOrphanTimestamp(void) const { return GetSeconds() == 0 && GetTicks() == 0 && GetAuthoritative(); }
/**
* This static method compares two timestamps.
*
@ -143,6 +165,19 @@ public:
*/
static int Compare(const Timestamp *aFirst, const Timestamp *aSecond);
/**
* This static method compares two timestamps.
*
* @param[in] aFirst A reference to the first timestamp to compare.
* @param[in] aSecond A reference to the second timestamp to compare.
*
* @retval -1 if @p aFirst is less than @p aSecond (`aFirst < aSecond`).
* @retval 0 if @p aFirst is equal to @p aSecond (`aFirst == aSecond`).
* @retval 1 if @p aFirst is greater than @p aSecond (`aFirst > aSecond`).
*
*/
static int Compare(const Timestamp &aFirst, const Timestamp &aSecond);
private:
static constexpr uint8_t kTicksOffset = 1;
static constexpr uint16_t kTicksMask = 0x7fff << kTicksOffset;

View File

@ -1409,20 +1409,7 @@ exit:
void Dso::Connection::PendingRequests::Remove(MessageId aMessageId)
{
Entry *entry = mRequests.FindMatching(aMessageId);
Entry *lastEntry;
VerifyOrExit(entry != nullptr);
// Remove last entry from the `mRequests` array, if it is not the
// `entry` we want to remove, replace `entry` with `lastEntry.
lastEntry = mRequests.PopBack();
VerifyOrExit(lastEntry != entry);
*entry = *lastEntry;
exit:
return;
mRequests.RemoveMatching(aMessageId);
}
bool Dso::Connection::PendingRequests::HasAnyTimedOut(TimeMilli aNow) const

View File

@ -65,6 +65,7 @@ Server::Server(Instance &aInstance)
, mQueryUnsubscribe(nullptr)
, mTimer(aInstance, Server::HandleTimer)
{
mCounters.Clear();
}
Error Server::Start(void)
@ -173,11 +174,19 @@ void Server::ProcessQuery(const Header &aRequestHeader, Message &aRequestMessage
#endif
// Resolve the question using query callbacks if SRP server failed to resolve the questions.
if (responseHeader.GetAnswerCount() == 0 &&
kErrorNone == ResolveByQueryCallbacks(responseHeader, *responseMessage, compressInfo, aMessageInfo))
if (responseHeader.GetAnswerCount() == 0)
{
resolveByQueryCallbacks = true;
if (kErrorNone == ResolveByQueryCallbacks(responseHeader, *responseMessage, compressInfo, aMessageInfo))
{
resolveByQueryCallbacks = true;
}
}
#if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
else
{
++mCounters.mResolvedBySrp;
}
#endif
exit:
if (error == kErrorNone && !resolveByQueryCallbacks)
@ -220,6 +229,8 @@ void Server::SendResponse(Header aHeader,
{
LogInfo("send DNS-SD reply: %s, RCODE=%d", ErrorToString(error), aResponseCode);
}
UpdateResponseCounters(aResponseCode);
}
Header::Response Server::AddQuestions(const Header & aRequestHeader,
@ -842,7 +853,7 @@ Server::QueryTransaction *Server::NewQuery(const Header & aResponseHead
continue;
}
query.Init(aResponseHeader, aResponseMessage, aCompressInfo, aMessageInfo);
query.Init(aResponseHeader, aResponseMessage, aCompressInfo, aMessageInfo, GetInstance());
ExitNow(newQuery = &query);
}
@ -1194,10 +1205,12 @@ void Server::FinalizeQuery(QueryTransaction &aQuery, Header::Response aResponseC
void Server::QueryTransaction::Init(const Header & aResponseHeader,
Message & aResponseMessage,
const NameCompressInfo &aCompressInfo,
const Ip6::MessageInfo &aMessageInfo)
const Ip6::MessageInfo &aMessageInfo,
Instance & aInstance)
{
OT_ASSERT(mResponseMessage == nullptr);
InstanceLocatorInit::Init(aInstance);
mResponseHeader = aResponseHeader;
mResponseMessage = &aResponseMessage;
mCompressInfo = aCompressInfo;
@ -1209,10 +1222,35 @@ void Server::QueryTransaction::Finalize(Header::Response aResponseMessage, Ip6::
{
OT_ASSERT(mResponseMessage != nullptr);
SendResponse(mResponseHeader, aResponseMessage, *mResponseMessage, mMessageInfo, aSocket);
Get<Server>().SendResponse(mResponseHeader, aResponseMessage, *mResponseMessage, mMessageInfo, aSocket);
mResponseMessage = nullptr;
}
void Server::UpdateResponseCounters(Header::Response aResponseCode)
{
switch (aResponseCode)
{
case UpdateHeader::kResponseSuccess:
++mCounters.mSuccessResponse;
break;
case UpdateHeader::kResponseServerFailure:
++mCounters.mServerFailureResponse;
break;
case UpdateHeader::kResponseFormatError:
++mCounters.mFormatErrorResponse;
break;
case UpdateHeader::kResponseNameError:
++mCounters.mNameErrorResponse;
break;
case UpdateHeader::kResponseNotImplemented:
++mCounters.mNotImplementedResponse;
break;
default:
++mCounters.mOtherResponse;
break;
}
}
} // namespace ServiceDiscovery
} // namespace Dns
} // namespace ot

View File

@ -67,6 +67,14 @@ class Server : public InstanceLocator, private NonCopyable
friend class Srp::Server;
public:
/**
* This class contains the counters of the DNS-SD server.
*
*/
class Counters : public otDnssdCounters, public Clearable<Counters>
{
};
/**
* This enumeration specifies a DNS-SD query type.
*
@ -155,6 +163,14 @@ public:
*/
static DnsQueryType GetQueryTypeAndName(const otDnssdQuery *aQuery, char (&aName)[Name::kMaxNameSize]);
/**
* This method returns the counters of the DNS-SD server.
*
* @returns A reference to the `Counters` instance.
*
*/
const Counters &GetCounters(void) const { return mCounters; };
private:
class NameCompressInfo : public Clearable<NameCompressInfo>
{
@ -273,7 +289,7 @@ private:
* This class contains the compress information for a dns packet.
*
*/
class QueryTransaction
class QueryTransaction : public InstanceLocatorInit
{
public:
explicit QueryTransaction(void)
@ -284,7 +300,8 @@ private:
void Init(const Header & aResponseHeader,
Message & aResponseMessage,
const NameCompressInfo &aCompressInfo,
const Ip6::MessageInfo &aMessageInfo);
const Ip6::MessageInfo &aMessageInfo,
Instance & aInstance);
bool IsValid(void) const { return mResponseMessage != nullptr; }
const Ip6::MessageInfo &GetMessageInfo(void) const { return mMessageInfo; }
const Header & GetResponseHeader(void) const { return mResponseHeader; }
@ -347,7 +364,7 @@ private:
static void IncResourceRecordCount(Header &aHeader, bool aAdditional);
static Error FindNameComponents(const char *aName, const char *aDomain, NameComponentsOffsetInfo &aInfo);
static Error FindPreviousLabel(const char *aName, uint8_t &aStart, uint8_t &aStop);
static void SendResponse(Header aHeader,
void SendResponse(Header aHeader,
Header::Response aResponseCode,
Message & aMessage,
const Ip6::MessageInfo &aMessageInfo,
@ -392,6 +409,8 @@ private:
void HandleTimer(void);
void ResetTimer(void);
void UpdateResponseCounters(Header::Response aResponseCode);
static const char kDnssdProtocolUdp[];
static const char kDnssdProtocolTcp[];
static const char kDnssdSubTypeLabel[];
@ -403,6 +422,8 @@ private:
otDnssdQuerySubscribeCallback mQuerySubscribe;
otDnssdQueryUnsubscribeCallback mQueryUnsubscribe;
TimerMilli mTimer;
Counters mCounters;
};
} // namespace ServiceDiscovery

View File

@ -1309,43 +1309,29 @@ exit:
bool Ip6::ShouldForwardToThread(const MessageInfo &aMessageInfo, bool aFromHost) const
{
OT_UNUSED_VARIABLE(aFromHost);
bool shouldForward = false;
bool rval = false;
if (aMessageInfo.GetSockAddr().IsMulticast())
if (aMessageInfo.GetSockAddr().IsMulticast() || aMessageInfo.GetSockAddr().IsLinkLocal())
{
// multicast
ExitNow(rval = true);
}
else if (aMessageInfo.GetSockAddr().IsLinkLocal())
{
// on-link link-local address
ExitNow(rval = true);
shouldForward = true;
}
else if (IsOnLink(aMessageInfo.GetSockAddr()))
{
// on-link global address
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE
ExitNow(rval = (aFromHost ||
!Get<BackboneRouter::Manager>().ShouldForwardDuaToBackbone(aMessageInfo.GetSockAddr())));
shouldForward =
(aFromHost || !Get<BackboneRouter::Manager>().ShouldForwardDuaToBackbone(aMessageInfo.GetSockAddr()));
#else
ExitNow(rval = true);
OT_UNUSED_VARIABLE(aFromHost);
shouldForward = true;
#endif
}
else if (Get<ThreadNetif>().RouteLookup(aMessageInfo.GetPeerAddr(), aMessageInfo.GetSockAddr(), nullptr) ==
kErrorNone)
{
// route
ExitNow(rval = true);
}
else
{
ExitNow(rval = false);
shouldForward = true;
}
exit:
return rval;
return shouldForward;
}
const Netif::UnicastAddress *Ip6::SelectSourceAddress(MessageInfo &aMessageInfo)

View File

@ -77,13 +77,17 @@ bool Prefix::IsEqual(const uint8_t *aPrefixBytes, uint8_t aPrefixLength) const
bool Prefix::operator<(const Prefix &aOther) const
{
bool isSmaller;
uint8_t minLength;
uint8_t matchedLength;
VerifyOrExit(GetLength() == aOther.GetLength(), isSmaller = GetLength() < aOther.GetLength());
minLength = OT_MIN(GetLength(), aOther.GetLength());
matchedLength = MatchLength(GetBytes(), aOther.GetBytes(), SizeForLength(minLength));
matchedLength = MatchLength(GetBytes(), aOther.GetBytes(), GetBytesSize());
VerifyOrExit(matchedLength < GetLength(), isSmaller = false);
if (matchedLength >= minLength)
{
isSmaller = (GetLength() < aOther.GetLength());
ExitNow();
}
isSmaller = GetBytes()[matchedLength / CHAR_BIT] < aOther.GetBytes()[matchedLength / CHAR_BIT];

View File

@ -266,8 +266,10 @@ public:
/**
* This method overloads operator `<` to compare two prefixes.
*
* A prefix with shorter length is considered smaller than the one with longer length. If the prefix lengths are
* equal, then the prefix bytes are compared directly.
* If the two prefixes have the same length N, then the bytes are compared directly (as two big-endian N-bit
* numbers). If the two prefix have different lengths, the shorter prefix is padded by `0` bit up to the longer
* prefix length N before the bytes are compared (as big-endian N-bit numbers). If all bytes are equal, the prefix
* with shorter length is considered smaller.
*
* @param[in] aOther The other prefix to compare against.
*

282
src/core/net/nd6.cpp Normal file
View File

@ -0,0 +1,282 @@
/*
* Copyright (c) 2020, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes implementations for IPv6 Neighbor Discovery (ND6).
*
*/
#include "nd6.hpp"
#include "common/as_core_type.hpp"
#include "common/code_utils.hpp"
namespace ot {
namespace Ip6 {
namespace Nd {
//----------------------------------------------------------------------------------------------------------------------
// Option::Iterator
Option::Iterator::Iterator(void)
: mOption(nullptr)
, mEnd(nullptr)
{
// An empty iterator (used to indicate `end()` of list).
}
Option::Iterator::Iterator(const void *aStart, const void *aEnd)
: mOption(nullptr)
, mEnd(reinterpret_cast<const Option *>(aEnd))
{
// Note that `Validate()` uses `mEnd` so can only be called after
// `mEnd` is set.
mOption = Validate(reinterpret_cast<const Option *>(aStart));
}
const Option *Option::Iterator::Next(const Option *aOption)
{
return reinterpret_cast<const Option *>(reinterpret_cast<const uint8_t *>(aOption) + aOption->GetSize());
}
void Option::Iterator::Advance(void)
{
mOption = (mOption != nullptr) ? Validate(Next(mOption)) : nullptr;
}
const Option *Option::Iterator::Validate(const Option *aOption) const
{
// Check if `aOption` is well-formed and fits in the range
// up to `mEnd`. Returns `aOption` if it is valid, `nullptr`
// otherwise.
return ((aOption != nullptr) && ((aOption + 1) <= mEnd) && aOption->IsValid() && (Next(aOption) <= mEnd)) ? aOption
: nullptr;
}
//----------------------------------------------------------------------------------------------------------------------
// PrefixInfoOption
void PrefixInfoOption::Init(void)
{
Clear();
SetType(kTypePrefixInfo);
SetSize(sizeof(PrefixInfoOption));
OT_UNUSED_VARIABLE(mReserved2);
}
void PrefixInfoOption::SetPrefix(const Prefix &aPrefix)
{
mPrefixLength = aPrefix.mLength;
mPrefix = AsCoreType(&aPrefix.mPrefix);
}
void PrefixInfoOption::GetPrefix(Prefix &aPrefix) const
{
aPrefix.Set(mPrefix.GetBytes(), mPrefixLength);
}
bool PrefixInfoOption::IsValid(void) const
{
return (GetSize() >= sizeof(*this)) && (mPrefixLength <= Prefix::kMaxLength) &&
(GetPreferredLifetime() <= GetValidLifetime());
}
//----------------------------------------------------------------------------------------------------------------------
// RouteInfoOption
void RouteInfoOption::Init(void)
{
Clear();
SetType(kTypeRouteInfo);
}
void RouteInfoOption::SetPreference(RoutePreference aPreference)
{
mResvdPrf &= ~kPreferenceMask;
mResvdPrf |= (NetworkData::RoutePreferenceToValue(aPreference) << kPreferenceOffset) & kPreferenceMask;
}
RoutePreference RouteInfoOption::GetPreference(void) const
{
return NetworkData::RoutePreferenceFromValue((mResvdPrf & kPreferenceMask) >> kPreferenceOffset);
}
void RouteInfoOption::SetPrefix(const Prefix &aPrefix)
{
SetLength(OptionLengthForPrefix(aPrefix.mLength));
mPrefixLength = aPrefix.mLength;
memcpy(GetPrefixBytes(), aPrefix.GetBytes(), aPrefix.GetBytesSize());
}
void RouteInfoOption::GetPrefix(Prefix &aPrefix) const
{
aPrefix.Set(GetPrefixBytes(), mPrefixLength);
}
bool RouteInfoOption::IsValid(void) const
{
return (GetSize() >= kMinSize) && (mPrefixLength <= Prefix::kMaxLength) &&
(GetLength() >= OptionLengthForPrefix(mPrefixLength)) &&
NetworkData::IsRoutePreferenceValid(GetPreference());
}
uint8_t RouteInfoOption::OptionLengthForPrefix(uint8_t aPrefixLength)
{
static constexpr uint8_t kMaxPrefixLenForOptionLen1 = 0;
static constexpr uint8_t kMaxPrefixLenForOptionLen2 = 64;
uint8_t length;
// The Option Length can be 1, 2, or 3 depending on the prefix
// length
//
// - 1 when prefix len is zero.
// - 2 when prefix len is less then or equal to 64.
// - 3 otherwise.
if (aPrefixLength == kMaxPrefixLenForOptionLen1)
{
length = 1;
}
else if (aPrefixLength <= kMaxPrefixLenForOptionLen2)
{
length = 2;
}
else
{
length = 3;
}
return length;
}
//----------------------------------------------------------------------------------------------------------------------
// RouterAdverMessage::Header
void RouterAdvertMessage::Header::SetToDefault(void)
{
OT_UNUSED_VARIABLE(mCode);
OT_UNUSED_VARIABLE(mCurHopLimit);
OT_UNUSED_VARIABLE(mReachableTime);
OT_UNUSED_VARIABLE(mRetransTimer);
Clear();
mType = Icmp::Header::kTypeRouterAdvert;
}
RoutePreference RouterAdvertMessage::Header::GetDefaultRouterPreference(void) const
{
return NetworkData::RoutePreferenceFromValue((mFlags & kPreferenceMask) >> kPreferenceOffset);
}
void RouterAdvertMessage::Header::SetDefaultRouterPreference(RoutePreference aPreference)
{
mFlags &= ~kPreferenceMask;
mFlags |= (NetworkData::RoutePreferenceToValue(aPreference) << kPreferenceOffset) & kPreferenceMask;
}
//----------------------------------------------------------------------------------------------------------------------
// RouterAdverMessage
Option *RouterAdvertMessage::AppendOption(uint16_t aOptionSize)
{
// This method appends an option with a given size to the RA
// message by reserving space in the data buffer if there is
// room. On success returns pointer to the option, on failure
// returns `nullptr`. The returned option needs to be
// initialized and populated by the caller.
Option * option = nullptr;
uint32_t newLength = mData.GetLength();
newLength += aOptionSize;
VerifyOrExit(newLength <= mMaxLength);
option = reinterpret_cast<Option *>(AsNonConst(GetDataEnd()));
mData.SetLength(static_cast<uint16_t>(newLength));
exit:
return option;
}
Error RouterAdvertMessage::AppendPrefixInfoOption(const Prefix &aPrefix,
uint32_t aValidLifetime,
uint32_t aPreferredLifetime)
{
Error error = kErrorNone;
PrefixInfoOption *pio;
pio = static_cast<PrefixInfoOption *>(AppendOption(sizeof(PrefixInfoOption)));
VerifyOrExit(pio != nullptr, error = kErrorNoBufs);
pio->Init();
pio->SetOnLinkFlag();
pio->SetAutoAddrConfigFlag();
pio->SetValidLifetime(aValidLifetime);
pio->SetPreferredLifetime(aPreferredLifetime);
pio->SetPrefix(aPrefix);
exit:
return error;
}
Error RouterAdvertMessage::AppendRouteInfoOption(const Prefix & aPrefix,
uint32_t aRouteLifetime,
RoutePreference aPreference)
{
Error error = kErrorNone;
RouteInfoOption *rio;
rio = static_cast<RouteInfoOption *>(AppendOption(RouteInfoOption::OptionSizeForPrefix(aPrefix.GetLength())));
VerifyOrExit(rio != nullptr, error = kErrorNoBufs);
rio->Init();
rio->SetRouteLifetime(aRouteLifetime);
rio->SetPreference(aPreference);
rio->SetPrefix(aPrefix);
exit:
return error;
}
//----------------------------------------------------------------------------------------------------------------------
// RouterAdvMessage
RouterSolicitMessage::RouterSolicitMessage(void)
{
mHeader.Clear();
mHeader.SetType(Icmp::Header::kTypeRouterSolicit);
}
} // namespace Nd
} // namespace Ip6
} // namespace ot

699
src/core/net/nd6.hpp Normal file
View File

@ -0,0 +1,699 @@
/*
* Copyright (c) 2020, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes definitions for IPv6 Neighbor Discovery (ND).
*
* See RFC 4861 (https://tools.ietf.org/html/rfc4861) and RFC 4191 (https://tools.ietf.org/html/rfc4191).
*
*/
#ifndef ND6_HPP_
#define ND6_HPP_
#include "openthread-core-config.h"
#include <stdint.h>
#include <openthread/netdata.h>
#include <openthread/platform/toolchain.h>
#include "common/const_cast.hpp"
#include "common/encoding.hpp"
#include "common/equatable.hpp"
#include "net/icmp6.hpp"
#include "net/ip6.hpp"
#include "thread/network_data_types.hpp"
using ot::Encoding::BigEndian::HostSwap16;
using ot::Encoding::BigEndian::HostSwap32;
namespace ot {
namespace Ip6 {
namespace Nd {
typedef NetworkData::RoutePreference RoutePreference; ///< Route Preference
/**
* This class represents the variable length options in Neighbor Discovery messages.
*
* @sa PrefixInfoOption
* @sa RouteInfoOption
*
*/
OT_TOOL_PACKED_BEGIN
class Option
{
friend class RouterAdvertMessage;
public:
enum Type : uint8_t
{
kTypePrefixInfo = 3, ///< Prefix Information Option.
kTypeRouteInfo = 24, ///< Route Information Option.
};
static constexpr uint16_t kLengthUnit = 8; ///< The unit of length in octets.
/**
* This method gets the option type.
*
* @returns The option type.
*
*/
uint8_t GetType(void) const { return mType; }
/**
* This method sets the option type.
*
* @param[in] aType The option type.
*
*
*/
void SetType(Type aType) { mType = aType; }
/**
* This method sets the length based on a given total option size in bytes.
*
* Th option must end on a 64-bit boundary, so the length is derived as `(aSize + 7) / 8 * 8`.
*
* @param[in] aSize The size of option in bytes.
*
*/
void SetSize(uint16_t aSize) { mLength = static_cast<uint8_t>((aSize + kLengthUnit - 1) / kLengthUnit); }
/**
* This method returns the size of the option in bytes.
*
* @returns The size of the option in bytes.
*
*/
uint16_t GetSize(void) const { return mLength * kLengthUnit; }
/**
* This method sets the length of the option (in unit of 8 bytes).
*
* @param[in] aLength The length of the option in unit of 8 bytes.
*
*/
void SetLength(uint8_t aLength) { mLength = aLength; }
/**
* This method returns the length of the option (in unit of 8 bytes).
*
* @returns The length of the option in unit of 8 bytes.
*
*/
uint16_t GetLength(void) const { return mLength; }
/**
* This method indicates whether or not this option is valid.
*
* @retval TRUE The option is valid.
* @retval FALSE The option is not valid.
*
*/
bool IsValid(void) const { return mLength > 0; }
private:
class Iterator : public Unequatable<Iterator>
{
public:
Iterator(void);
Iterator(const void *aStart, const void *aEnd);
const Option &operator*(void) { return *mOption; }
void operator++(void) { Advance(); }
void operator++(int) { Advance(); }
bool operator==(const Iterator &aOther) const { return mOption == aOther.mOption; }
private:
static const Option *Next(const Option *aOption);
void Advance(void);
const Option * Validate(const Option *aOption) const;
const Option *mOption;
const Option *mEnd;
};
uint8_t mType; // Type of the option.
uint8_t mLength; // Length of the option in unit of 8 octets, including the `mType` and `mLength` fields.
} OT_TOOL_PACKED_END;
/**
* This class represents the Prefix Information Option.
*
* See section 4.6.2 of RFC 4861 for definition of this option [https://tools.ietf.org/html/rfc4861#section-4.6.2]
*
*/
OT_TOOL_PACKED_BEGIN
class PrefixInfoOption : public Option, private Clearable<PrefixInfoOption>
{
public:
static constexpr Type kType = kTypePrefixInfo; ///< Prefix Information Option Type.
/**
* This method initializes the Prefix Info option with proper type and length and sets all other fields to zero.
*
*/
void Init(void);
/**
* This method indicates whether or not the on-link flag is set.
*
* @retval TRUE The on-link flag is set.
* @retval FALSE The on-link flag is not set.
*
*/
bool IsOnLinkFlagSet(void) const { return (mFlags & kOnLinkFlagMask) != 0; }
/**
* This method sets the on-link (L) flag.
*
*/
void SetOnLinkFlag(void) { mFlags |= kOnLinkFlagMask; }
/**
* This method clears the on-link (L) flag.
*
*/
void ClearOnLinkFlag(void) { mFlags &= ~kOnLinkFlagMask; }
/**
* This method indicates whether or not the autonomous address-configuration (A) flag is set.
*
* @retval TRUE The auto address-config flag is set.
* @retval FALSE The auto address-config flag is not set.
*
*/
bool IsAutoAddrConfigFlagSet(void) const { return (mFlags & kAutoConfigFlagMask) != 0; }
/**
* This method sets the autonomous address-configuration (A) flag.
*
*/
void SetAutoAddrConfigFlag(void) { mFlags |= kAutoConfigFlagMask; }
/**
* This method clears the autonomous address-configuration (A) flag.
*
*/
void ClearAutoAddrConfigFlag(void) { mFlags &= ~kAutoConfigFlagMask; }
/**
* This method sets the valid lifetime of the prefix in seconds.
*
* @param[in] aValidLifetime The valid lifetime in seconds.
*
*/
void SetValidLifetime(uint32_t aValidLifetime) { mValidLifetime = HostSwap32(aValidLifetime); }
/**
* THis method gets the valid lifetime of the prefix in seconds.
*
* @returns The valid lifetime in seconds.
*
*/
uint32_t GetValidLifetime(void) const { return HostSwap32(mValidLifetime); }
/**
* This method sets the preferred lifetime of the prefix in seconds.
*
* @param[in] aPreferredLifetime The preferred lifetime in seconds.
*
*/
void SetPreferredLifetime(uint32_t aPreferredLifetime) { mPreferredLifetime = HostSwap32(aPreferredLifetime); }
/**
* THis method returns the preferred lifetime of the prefix in seconds.
*
* @returns The preferred lifetime in seconds.
*
*/
uint32_t GetPreferredLifetime(void) const { return HostSwap32(mPreferredLifetime); }
/**
* This method sets the prefix.
*
* @param[in] aPrefix The prefix contained in this option.
*
*/
void SetPrefix(const Prefix &aPrefix);
/**
* This method gets the prefix in this option.
*
* @param[out] aPrefix Reference to a `Prefix` to return the prefix.
*
*/
void GetPrefix(Prefix &aPrefix) const;
/**
* This method indicates whether or not the option is valid.
*
* @retval TRUE The option is valid
* @retval FALSE The option is not valid.
*
*/
bool IsValid(void) const;
PrefixInfoOption(void) = delete;
private:
// Prefix Information Option
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type | Length | Prefix Length |L|A| Reserved1 |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Valid Lifetime |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Preferred Lifetime |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Reserved2 |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// + +
// | |
// + Prefix +
// | |
// + +
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
static constexpr uint8_t kAutoConfigFlagMask = 0x40; // Autonomous address-configuration flag.
static constexpr uint8_t kOnLinkFlagMask = 0x80; // On-link flag.
uint8_t mPrefixLength; // The prefix length in bits.
uint8_t mFlags; // The flags field.
uint32_t mValidLifetime; // The valid lifetime of the prefix.
uint32_t mPreferredLifetime; // The preferred lifetime of the prefix.
uint32_t mReserved2; // The reserved field.
Address mPrefix; // The prefix.
} OT_TOOL_PACKED_END;
static_assert(sizeof(PrefixInfoOption) == 32, "invalid PrefixInfoOption structure");
/**
* This class represents the Route Information Option.
*
* See section 2.3 of RFC 4191 for definition of this option. [https://tools.ietf.org/html/rfc4191#section-2.3]
*
*/
OT_TOOL_PACKED_BEGIN
class RouteInfoOption : public Option, private Clearable<RouteInfoOption>
{
public:
static constexpr uint16_t kMinSize = kLengthUnit; ///< Minimum size (in bytes) of a Route Info Option
static constexpr Type kType = kTypeRouteInfo; ///< Route Information Option Type.
/**
* This method initializes the option setting the type and clearing (setting to zero) all other fields.
*
*/
void Init(void);
/**
* This method sets the route preference.
*
* @param[in] aPreference The route preference.
*
*/
void SetPreference(RoutePreference aPreference);
/**
* This method gets the route preference.
*
* @returns The route preference.
*
*/
RoutePreference GetPreference(void) const;
/**
* This method sets the lifetime of the route in seconds.
*
* @param[in] aLifetime The lifetime of the route in seconds.
*
*/
void SetRouteLifetime(uint32_t aLifetime) { mRouteLifetime = HostSwap32(aLifetime); }
/**
* This method gets Route Lifetime in seconds.
*
* @returns The Route Lifetime in seconds.
*
*/
uint32_t GetRouteLifetime(void) const { return HostSwap32(mRouteLifetime); }
/**
* This method sets the prefix and adjusts the option length based on the prefix length.
*
* @param[in] aPrefix The prefix contained in this option.
*
*/
void SetPrefix(const Prefix &aPrefix);
/**
* This method gets the prefix in this option.
*
* @param[out] aPrefix Reference to a `Prefix` to return the prefix.
*
*/
void GetPrefix(Prefix &aPrefix) const;
/**
* This method tells whether this option is valid.
*
* @returns A boolean indicates whether this option is valid.
*
*/
bool IsValid(void) const;
/**
* This static method calculates the minimum option length for a given prefix length.
*
* The option length (which is in unit of 8 octets) can be 1, 2, or 3 depending on the prefix length. It can be 1
* for a zero prefix length, 2 if the prefix length is not greater than 64, and 3 otherwise.
*
* @param[in] aPrefixLength The prefix length (in bits).
*
* @returns The option length (in unit of 8 octet) for @p aPrefixLength.
*
*/
static uint8_t OptionLengthForPrefix(uint8_t aPrefixLength);
/**
* This static method calculates the minimum option size (in bytes) for a given prefix length.
*
* @param[in] aPrefixLength The prefix length (in bits).
*
* @returns The option size (in bytes) for @p aPrefixLength.
*
*/
static uint16_t OptionSizeForPrefix(uint8_t aPrefixLength)
{
return kLengthUnit * OptionLengthForPrefix(aPrefixLength);
}
RouteInfoOption(void) = delete;
private:
// Route Information Option
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type | Length | Prefix Length |Resvd|Prf|Resvd|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Route Lifetime |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Prefix (Variable Length) |
// . .
// . .
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
static constexpr uint8_t kPreferenceOffset = 3;
static constexpr uint8_t kPreferenceMask = 3 << kPreferenceOffset;
uint8_t * GetPrefixBytes(void) { return AsNonConst(AsConst(this)->GetPrefixBytes()); }
const uint8_t *GetPrefixBytes(void) const { return reinterpret_cast<const uint8_t *>(this) + sizeof(*this); }
uint8_t mPrefixLength; // The prefix length in bits.
uint8_t mResvdPrf; // The preference.
uint32_t mRouteLifetime; // The lifetime in seconds.
// Followed by prefix bytes (variable length).
} OT_TOOL_PACKED_END;
static_assert(sizeof(RouteInfoOption) == 8, "invalid RouteInfoOption structure");
/**
* This class represents a Router Advertisement message.
*
*/
class RouterAdvertMessage
{
public:
/**
* This class implements the RA message header.
*
* See section 2.2 of RFC 4191 [https://datatracker.ietf.org/doc/html/rfc4191]
*
*/
OT_TOOL_PACKED_BEGIN
class Header : public Equatable<Header>, private Clearable<Header>
{
public:
/**
* This constructor initializes the Router Advertisement message with
* zero router lifetime, reachable time and retransmission timer.
*
*/
Header(void) { SetToDefault(); }
/**
* This method sets the RA message to default values.
*
*/
void SetToDefault(void);
/**
* This method sets the checksum value.
*
* @param[in] aChecksum The checksum value.
*
*/
void SetChecksum(uint16_t aChecksum) { mChecksum = HostSwap16(aChecksum); }
/**
* This method sets the Router Lifetime in seconds.
*
* @param[in] aRouterLifetime The router lifetime in seconds.
*
*/
void SetRouterLifetime(uint16_t aRouterLifetime) { mRouterLifetime = HostSwap16(aRouterLifetime); }
/**
* This method gets the Router Lifetime (in seconds).
*
* Router Lifetime set to zero indicates that the sender is not a default router.
*
* @returns The router lifetime in seconds.
*
*/
uint16_t GetRouterLifetime(void) const { return HostSwap16(mRouterLifetime); }
/**
* This method sets the default router preference.
*
* @param[in] aPreference The router preference.
*
*/
void SetDefaultRouterPreference(RoutePreference aPreference);
/**
* This method gets the default router preference.
*
* @returns The router preference.
*
*/
RoutePreference GetDefaultRouterPreference(void) const;
private:
// Router Advertisement Message
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type | Code | Checksum |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Cur Hop Limit |M|O|H|Prf|Resvd| Router Lifetime |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Reachable Time |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Retrans Timer |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Options ...
// +-+-+-+-+-+-+-+-+-+-+-+-
static constexpr uint8_t kPreferenceOffset = 3;
static constexpr uint8_t kPreferenceMask = 3 << kPreferenceOffset;
uint8_t mType;
uint8_t mCode;
uint16_t mChecksum;
uint8_t mCurHopLimit;
uint8_t mFlags;
uint16_t mRouterLifetime;
uint32_t mReachableTime;
uint32_t mRetransTimer;
} OT_TOOL_PACKED_END;
static_assert(sizeof(Header) == 16, "Invalid RA `Header`");
typedef Data<kWithUint16Length> Icmp6Packet; ///< A data buffer containing an ICMPv6 packet.
/**
* This constructor initializes the RA message from a received packet data buffer.
*
* @param[in] aPacket A received packet data.
*
*/
explicit RouterAdvertMessage(const Icmp6Packet &aPacket)
: mData(aPacket)
, mMaxLength(0)
{
}
/**
* This template constructor initializes the RA message with a given header using a given buffer to store the RA
* message.
*
* @tparam kBufferSize The size of the buffer used to store the RA message.
*
* @param[in] aHeader The RA message header.
* @param[in] aBuffer The data buffer to store the RA message in.
*
*/
template <uint16_t kBufferSize>
RouterAdvertMessage(const Header &aHeader, uint8_t (&aBuffer)[kBufferSize])
: mMaxLength(kBufferSize)
{
static_assert(kBufferSize >= sizeof(Header), "Buffer for RA msg is too small");
memcpy(aBuffer, &aHeader, sizeof(Header));
mData.Init(aBuffer, sizeof(Header));
}
/**
* This method gets the RA message as an `Icmp6Packet`.
*
* @returns The RA message as an `Icmp6Packet`.
*
*/
const Icmp6Packet &GetAsPacket(void) const { return mData; }
/**
* This method indicates whether or not the RA message is valid.
*
* @retval TRUE If the RA message is valid.
* @retval FALSE If the RA message is not valid.
*
*/
bool IsValid(void) const { return (mData.GetBytes() != nullptr) && (mData.GetLength() >= sizeof(Header)); }
/**
* This method gets the RA message's header.
*
* @returns The RA message's header.
*
*/
const Header &GetHeader(void) const { return *reinterpret_cast<const Header *>(mData.GetBytes()); }
/**
* This method appends a Prefix Info Option to the RA message.
*
* The appended Prefix Info Option will have both on-link (L) and autonomous address-configuration (A) flags set.
*
* @param[in] aPrefix The prefix.
* @param[in] aValidLifetime The valid lifetime in seconds.
* @param[in] aPreferredLifetime The preferred lifetime in seconds.
*
* @retval kErrorNone Option is appended successfully.
* @retval kErrorNoBufs No more space in the buffer to append the option.
*
*/
Error AppendPrefixInfoOption(const Prefix &aPrefix, uint32_t aValidLifetime, uint32_t aPreferredLifetime);
/**
* This method appends a Route Info Option to the RA message.
*
* @param[in] aPrefix The prefix.
* @param[in] aRouteLifetime The route lifetime in seconds.
* @param[in] aPreference The route preference.
*
* @retval kErrorNone Option is appended successfully.
* @retval kErrorNoBufs No more space in the buffer to append the option.
*
*/
Error AppendRouteInfoOption(const Prefix &aPrefix, uint32_t aRouteLifetime, RoutePreference aPreference);
/**
* This method indicates whether or not the RA message contains any options.
*
* @retval TRUE If the RA message contains at least one option.
* @retval FALSE If the RA message contains no options.
*
*/
bool ContainsAnyOptions(void) const { return (mData.GetLength() > sizeof(Header)); }
// The following methods are intended to support range-based `for`
// loop iteration over `Option`s in the RA message.
Option::Iterator begin(void) const { return Option::Iterator(GetOptionStart(), GetDataEnd()); }
Option::Iterator end(void) const { return Option::Iterator(); }
private:
const uint8_t *GetOptionStart(void) const { return (mData.GetBytes() + sizeof(Header)); }
const uint8_t *GetDataEnd(void) const { return mData.GetBytes() + mData.GetLength(); }
Option * AppendOption(uint16_t aOptionSize);
Data<kWithUint16Length> mData;
uint16_t mMaxLength;
};
/**
* This class implements the Router Solicitation message.
*
* See section 4.1 of RFC 4861 for definition of this message.
* https://tools.ietf.org/html/rfc4861#section-4.1
*
*/
OT_TOOL_PACKED_BEGIN
class RouterSolicitMessage
{
public:
/**
* This constructor initializes the Router Solicitation message.
*
*/
RouterSolicitMessage(void);
private:
Icmp::Header mHeader; // The common ICMPv6 header.
} OT_TOOL_PACKED_END;
static_assert(sizeof(RouterSolicitMessage) == 8, "invalid RouterSolicitMessage structure");
} // namespace Nd
} // namespace Ip6
} // namespace ot
#endif // ND6_HPP_

View File

@ -76,10 +76,20 @@ void Client::HostInfo::SetState(ItemState aState)
}
}
void Client::HostInfo::EnableAutoAddress(void)
{
mAddresses = nullptr;
mNumAddresses = 0;
mAutoAddress = true;
LogInfo("HostInfo enabled auto address", GetNumAddresses());
}
void Client::HostInfo::SetAddresses(const Ip6::Address *aAddresses, uint8_t aNumAddresses)
{
mAddresses = aAddresses;
mNumAddresses = aNumAddresses;
mAutoAddress = false;
LogInfo("HostInfo set %d addrs", GetNumAddresses());
@ -239,12 +249,14 @@ Client::Client(Instance &aInstance)
, mState(kStateStopped)
, mTxFailureRetryCount(0)
, mShouldRemoveKeyLease(false)
, mAutoHostAddressAddedMeshLocal(false)
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
, mServiceKeyRecordEnabled(false)
#endif
, mUpdateMessageId(0)
, mRetryWaitInterval(kMinRetryWaitInterval)
, mAcceptedLeaseInterval(0)
, mTtl(0)
, mLeaseInterval(kDefaultLease)
, mKeyLeaseInterval(kDefaultKeyLease)
, mSocket(aInstance)
@ -323,6 +335,8 @@ void Client::Stop(Requester aRequester, StopMode aMode)
VerifyOrExit(GetState() != kStateStopped);
mSingleServiceMode.Disable();
// State changes:
// kAdding -> kToRefresh
// kRefreshing -> kToRefresh
@ -391,6 +405,8 @@ void Client::Pause(void)
/* (7) kRemoved -> */ kRemoved,
};
mSingleServiceMode.Disable();
// State changes:
// kAdding -> kToRefresh
// kRefreshing -> kToRefresh
@ -414,6 +430,22 @@ void Client::HandleNotifierEvents(Events aEvents)
ProcessAutoStart();
}
#endif
if (mHostInfo.IsAutoAddressEnabled())
{
Events::Flags eventFlags = (kEventIp6AddressAdded | kEventIp6AddressRemoved);
if (mAutoHostAddressAddedMeshLocal)
{
eventFlags |= kEventThreadMeshLocalAddrChanged;
}
if (aEvents.ContainsAny(eventFlags))
{
IgnoreError(UpdateHostInfoStateOnAddressChange());
UpdateState();
}
}
}
void Client::HandleRoleChanged(void)
@ -465,11 +497,37 @@ exit:
return error;
}
Error Client::EnableAutoHostAddress(void)
{
Error error = kErrorNone;
VerifyOrExit(!mHostInfo.IsAutoAddressEnabled());
SuccessOrExit(error = UpdateHostInfoStateOnAddressChange());
mHostInfo.EnableAutoAddress();
UpdateState();
exit:
return error;
}
Error Client::SetHostAddresses(const Ip6::Address *aAddresses, uint8_t aNumAddresses)
{
Error error = kErrorNone;
VerifyOrExit((aAddresses != nullptr) && (aNumAddresses > 0), error = kErrorInvalidArgs);
SuccessOrExit(error = UpdateHostInfoStateOnAddressChange());
mHostInfo.SetAddresses(aAddresses, aNumAddresses);
UpdateState();
exit:
return error;
}
Error Client::UpdateHostInfoStateOnAddressChange(void)
{
Error error = kErrorNone;
VerifyOrExit((mHostInfo.GetState() != kToRemove) && (mHostInfo.GetState() != kRemoving),
error = kErrorInvalidState);
@ -483,9 +541,6 @@ Error Client::SetHostAddresses(const Ip6::Address *aAddresses, uint8_t aNumAddre
mHostInfo.SetState(kToRefresh);
}
mHostInfo.SetAddresses(aAddresses, aNumAddresses);
UpdateState();
exit:
return error;
}
@ -659,6 +714,11 @@ void Client::ChangeHostAndServiceStates(const ItemState *aNewStates)
for (Service &service : mServices)
{
if (mSingleServiceMode.IsEnabled() && mSingleServiceMode.GetService() != &service)
{
continue;
}
service.SetState(aNewStates[service.GetState()]);
}
@ -717,9 +777,21 @@ void Client::SendUpdate(void)
Error error = kErrorNone;
Message *message = mSocket.NewMessage(0);
uint32_t length;
VerifyOrExit(message != nullptr, error = kErrorNoBufs);
SuccessOrExit(error = PrepareUpdateMessage(*message));
length = message->GetLength() + sizeof(Ip6::Udp::Header) + sizeof(Ip6::Header);
if (length >= Ip6::kMaxDatagramLength)
{
LogInfo("Msg len %u is larger than MTU, enabling single service mode", length);
mSingleServiceMode.Enable();
IgnoreError(message->SetLength(0));
SuccessOrExit(error = PrepareUpdateMessage(*message));
}
SuccessOrExit(error = mSocket.SendTo(*message, Ip6::MessageInfo()));
LogInfo("Send update");
@ -757,6 +829,7 @@ exit:
LogInfo("Failed to send update: %s", ErrorToString(error));
mSingleServiceMode.Disable();
FreeMessage(message);
SetState(kStateToRetry);
@ -831,6 +904,11 @@ Error Client::PrepareUpdateMessage(Message &aMessage)
for (Service &service : mServices)
{
SuccessOrExit(error = AppendServiceInstructions(service, aMessage, info));
if (mSingleServiceMode.IsEnabled() && (mSingleServiceMode.GetService() != nullptr))
{
break;
}
}
}
@ -911,7 +989,7 @@ Error Client::AppendServiceInstructions(Service &aService, Message &aMessage, In
// to NONE and TTL to zero (RFC 2136 - section 2.5.4).
rr.Init(Dns::ResourceRecord::kTypePtr, removing ? Dns::PtrRecord::kClassNone : Dns::PtrRecord::kClassInternet);
rr.SetTtl(removing ? 0 : mLeaseInterval);
rr.SetTtl(removing ? 0 : GetTtl());
offset = aMessage.GetLength();
SuccessOrExit(error = aMessage.Append(rr));
@ -970,7 +1048,7 @@ Error Client::AppendServiceInstructions(Service &aService, Message &aMessage, In
SuccessOrExit(error = Dns::Name::AppendPointerLabel(instanceNameOffset, aMessage));
srv.Init();
srv.SetTtl(mLeaseInterval);
srv.SetTtl(GetTtl());
srv.SetPriority(aService.GetPriority());
srv.SetWeight(aService.GetWeight());
srv.SetPort(aService.GetPort());
@ -1003,14 +1081,18 @@ Error Client::AppendServiceInstructions(Service &aService, Message &aMessage, In
}
#endif
if (mSingleServiceMode.IsEnabled())
{
mSingleServiceMode.SetService(aService);
}
exit:
return error;
}
Error Client::AppendHostDescriptionInstruction(Message &aMessage, Info &aInfo) const
Error Client::AppendHostDescriptionInstruction(Message &aMessage, Info &aInfo)
{
Error error = kErrorNone;
Dns::ResourceRecord rr;
Error error = kErrorNone;
//----------------------------------
// Host Description Instruction
@ -1023,16 +1105,37 @@ Error Client::AppendHostDescriptionInstruction(Message &aMessage, Info &aInfo) c
// AAAA RRs
rr.Init(Dns::ResourceRecord::kTypeAaaa);
rr.SetTtl(mLeaseInterval);
rr.SetLength(sizeof(Ip6::Address));
for (uint8_t index = 0; index < mHostInfo.GetNumAddresses(); index++)
if (mHostInfo.IsAutoAddressEnabled())
{
SuccessOrExit(error = AppendHostName(aMessage, aInfo));
SuccessOrExit(error = aMessage.Append(rr));
SuccessOrExit(error = aMessage.Append(mHostInfo.GetAddress(index)));
aInfo.mRecordCount++;
// Append all addresses on Thread netif excluding link-local and
// mesh-local addresses. If no address is appended, we include
// the mesh local address.
mAutoHostAddressAddedMeshLocal = true;
for (const Ip6::Netif::UnicastAddress &unicastAddress : Get<ThreadNetif>().GetUnicastAddresses())
{
if (unicastAddress.GetAddress().IsLinkLocal() ||
Get<Mle::Mle>().IsMeshLocalAddress(unicastAddress.GetAddress()))
{
continue;
}
SuccessOrExit(error = AppendAaaaRecord(unicastAddress.GetAddress(), aMessage, aInfo));
mAutoHostAddressAddedMeshLocal = false;
}
if (mAutoHostAddressAddedMeshLocal)
{
SuccessOrExit(error = AppendAaaaRecord(Get<Mle::Mle>().GetMeshLocal64(), aMessage, aInfo));
}
}
else
{
for (uint8_t index = 0; index < mHostInfo.GetNumAddresses(); index++)
{
SuccessOrExit(error = AppendAaaaRecord(mHostInfo.GetAddress(index), aMessage, aInfo));
}
}
// KEY RR
@ -1044,6 +1147,24 @@ exit:
return error;
}
Error Client::AppendAaaaRecord(const Ip6::Address &aAddress, Message &aMessage, Info &aInfo) const
{
Error error;
Dns::ResourceRecord rr;
rr.Init(Dns::ResourceRecord::kTypeAaaa);
rr.SetTtl(GetTtl());
rr.SetLength(sizeof(Ip6::Address));
SuccessOrExit(error = AppendHostName(aMessage, aInfo));
SuccessOrExit(error = aMessage.Append(rr));
SuccessOrExit(error = aMessage.Append(aAddress));
aInfo.mRecordCount++;
exit:
return error;
}
Error Client::AppendKeyRecord(Message &aMessage, Info &aInfo) const
{
Error error;
@ -1051,7 +1172,7 @@ Error Client::AppendKeyRecord(Message &aMessage, Info &aInfo) const
Crypto::Ecdsa::P256::PublicKey publicKey;
key.Init();
key.SetTtl(mLeaseInterval);
key.SetTtl(GetTtl());
key.SetFlags(Dns::KeyRecord::kAuthConfidPermitted, Dns::KeyRecord::kOwnerNonZone,
Dns::KeyRecord::kSignatoryFlagGeneral);
key.SetProtocol(Dns::KeyRecord::kProtocolDnsSec);
@ -1384,6 +1505,7 @@ void Client::ProcessResponse(Message &aMessage)
// kRemoving -> kRemoved
ChangeHostAndServiceStates(kNewStateOnUpdateDone);
mSingleServiceMode.Disable();
HandleUpdateDone();
UpdateState();
@ -1518,7 +1640,7 @@ void Client::UpdateState(void)
// host address, otherwise no need to send SRP update message.
// The exception is when removing host info where we allow
// for empty service list.
VerifyOrExit(!mServices.IsEmpty() && (mHostInfo.GetNumAddresses() > 0));
VerifyOrExit(!mServices.IsEmpty() && (mHostInfo.IsAutoAddressEnabled() || (mHostInfo.GetNumAddresses() > 0)));
// Fall through
@ -1653,6 +1775,7 @@ void Client::HandleTimer(void)
break;
case kStateUpdating:
mSingleServiceMode.Disable();
LogRetryWaitInterval();
LogInfo("Timed out, no response");
GrowRetryWaitInterval();
@ -1782,7 +1905,6 @@ Error Client::SelectUnicastEntry(DnsSrpUnicast::Origin aOrigin, DnsSrpUnicast::I
Error error = kErrorNotFound;
DnsSrpUnicast::Info unicastInfo;
NetworkData::Service::Manager::Iterator iterator;
uint16_t numServers = 0;
#if OPENTHREAD_CONFIG_SRP_CLIENT_SAVE_SELECTED_SERVER_ENABLE
Settings::SrpClientInfo savedInfo;
bool hasSavedServerInfo = false;
@ -1819,16 +1941,10 @@ Error Client::SelectUnicastEntry(DnsSrpUnicast::Origin aOrigin, DnsSrpUnicast::I
ExitNow();
}
#endif
numServers++;
// Choose a server randomly (with uniform distribution) from
// the list of servers. As we iterate through server entries,
// with probability `1/numServers`, we choose to switch the
// current selected server with the new entry. This approach
// results in a uniform/same probability of selection among
// all server entries.
// Prefer the numerically lowest server address
if ((numServers == 1) || (Random::NonCrypto::GetUint16InRange(0, numServers) == 0))
if ((error == kErrorNotFound) || (unicastInfo.mSockAddr.GetAddress() < aInfo.mSockAddr.GetAddress()))
{
aInfo = unicastInfo;
error = kErrorNone;

View File

@ -103,7 +103,7 @@ public:
* This type represents an SRP client host info.
*
*/
class HostInfo : public otSrpClientHostInfo, public Clearable<HostInfo>
class HostInfo : public otSrpClientHostInfo, private Clearable<HostInfo>
{
friend class Client;
@ -128,6 +128,15 @@ public:
*/
const char *GetName(void) const { return mName; }
/**
* This method indicates whether or not the host auto address mode is enabled.
*
* @retval TRUE If the auto address mode is enabled.
* @retval FALSE If the auto address mode is disabled.
*
*/
bool IsAutoAddressEnabled(void) const { return mAutoAddress; }
/**
* This method gets the number of host IPv6 addresses.
*
@ -158,6 +167,7 @@ public:
void SetName(const char *aName) { mName = aName; }
void SetState(ItemState aState);
void SetAddresses(const Ip6::Address *aAddresses, uint8_t aNumAddresses);
void EnableAutoAddress(void);
};
/**
@ -410,6 +420,31 @@ public:
*/
void SetCallback(Callback aCallback, void *aContext);
/**
* This method gets the TTL used in SRP update requests.
*
* Note that this is the TTL requested by the SRP client. The server may choose to accept a different TTL.
*
* By default, the TTL will equal the lease interval. Passing 0 or a value larger than the lease interval via
* `otSrpClientSetTtl()` will also cause the TTL to equal the lease interval.
*
* @returns The TTL (in seconds).
*
*/
uint32_t GetTtl(void) const { return (0 < mTtl && mTtl < mLeaseInterval) ? mTtl : mLeaseInterval; }
/**
* This method sets the TTL used in SRP update requests.
*
* Changing the TTL does not impact the TTL of already registered services/host-info.
* It only changes any future SRP update messages (i.e adding new services and/or refreshes of existing services).
*
* @param[in] aTtl The TTL (in seconds). If value is zero or greater than lease interval, the TTL is set to the
* lease interval.
*
*/
void SetTtl(uint32_t aTtl) { mTtl = aTtl; }
/**
* This method gets the lease interval used in SRP update requests.
*
@ -464,16 +499,16 @@ public:
const HostInfo &GetHostInfo(void) const { return mHostInfo; }
/**
* This function sets the host name label.
* This method sets the host name label.
*
* After a successful call to this function, `Callback` will be called to report the status of host info
* After a successful call to this method, `Callback` will be called to report the status of host info
* registration with SRP server.
*
* The host name can be set before client is started or after start but before host info is registered with server
* (host info should be in either `kToAdd` or `kRemoved`).
*
* @param[in] aName A pointer to host name label string (MUST NOT be NULL). Pointer the string buffer MUST
* persist and remain valid and constant after return from this function.
* persist and remain valid and constant after return from this method.
*
* @retval kErrorNone The host name label was set successfully.
* @retval kErrorInvalidArgs The @p aName is NULL.
@ -482,6 +517,27 @@ public:
*/
Error SetHostName(const char *aName);
/**
* This method enables auto host address mode.
*
* When enabled host IPv6 addresses are automatically set by SRP client using all the unicast addresses on Thread
* netif excluding the link-local and mesh-local addresses. If there is no valid address, then Mesh Local EID
* address is added. The SRP client will automatically re-register when/if addresses on Thread netif are updated
* (new addresses are added or existing addresses are removed).
*
* The auto host address mode can be enabled before start or during operation of SRP client except when the host
* info is being removed (client is busy handling a remove request from an call to `RemoveHostAndServices()` and
* host info still being in either `kStateToRemove` or `kStateRemoving` states).
*
* After auto host address mode is enabled, it can be disabled by a call to `SetHostAddresses()` which then
* explicitly sets the host addresses.
*
* @retval kErrorNone Successfully enabled auto host address mode.
* @retval kErrorInvalidState Host is being removed and therefore cannot enable auto host address mode.
*
*/
Error EnableAutoHostAddress(void);
/**
* This method sets/updates the list of host IPv6 address.
*
@ -493,6 +549,9 @@ public:
* After a successful call to this method, `Callback` will be called to report the status of the address
* registration with SRP server.
*
* Calling this method disables auto host address mode if it was previously enabled from a successful call to
* `EnableAutoHostAddress()`.
*
* @param[in] aAddresses A pointer to the an array containing the host IPv6 addresses.
* @param[in] aNumAddresses The number of addresses in the @p aAddresses array.
*
@ -795,6 +854,26 @@ private:
kKeepRetryInterval,
};
class SingleServiceMode
{
public:
SingleServiceMode(void)
: mEnabled(false)
, mService(nullptr)
{
}
void Enable(void) { mEnabled = true, mService = nullptr; }
void Disable(void) { mEnabled = false; }
bool IsEnabled(void) const { return mEnabled; }
Service *GetService(void) { return mService; }
void SetService(Service &aService) { mService = &aService; }
private:
bool mEnabled;
Service *mService;
};
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
class AutoStart : Clearable<AutoStart>
{
@ -859,6 +938,7 @@ private:
void Pause(void);
void HandleNotifierEvents(Events aEvents);
void HandleRoleChanged(void);
Error UpdateHostInfoStateOnAddressChange(void);
void UpdateServiceStateToRemove(Service &aService);
State GetState(void) const { return mState; }
void SetState(State aState);
@ -870,10 +950,11 @@ private:
Error PrepareUpdateMessage(Message &aMessage);
Error ReadOrGenerateKey(Crypto::Ecdsa::P256::KeyPair &aKeyPair);
Error AppendServiceInstructions(Service &aService, Message &aMessage, Info &aInfo);
Error AppendHostDescriptionInstruction(Message &aMessage, Info &aInfo) const;
Error AppendHostDescriptionInstruction(Message &aMessage, Info &aInfo);
Error AppendKeyRecord(Message &aMessage, Info &aInfo) const;
Error AppendDeleteAllRrsets(Message &aMessage) const;
Error AppendHostName(Message &aMessage, Info &aInfo, bool aDoNotCompress = false) const;
Error AppendAaaaRecord(const Ip6::Address &aAddress, Message &aMessage, Info &aInfo) const;
Error AppendUpdateLeaseOptRecord(Message &aMessage) const;
Error AppendSignature(Message &aMessage, Info &aInfo);
void UpdateRecordLengthInMessage(Dns::ResourceRecord &aRecord, uint16_t aOffset, Message &aMessage) const;
@ -913,6 +994,7 @@ private:
State mState;
uint8_t mTxFailureRetryCount : 4;
bool mShouldRemoveKeyLease : 1;
bool mAutoHostAddressAddedMeshLocal : 1;
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
bool mServiceKeyRecordEnabled : 1;
#endif
@ -922,6 +1004,7 @@ private:
TimeMilli mLeaseRenewTime;
uint32_t mAcceptedLeaseInterval;
uint32_t mTtl;
uint32_t mLeaseInterval;
uint32_t mKeyLeaseInterval;
@ -932,6 +1015,7 @@ private:
const char * mDomainName;
HostInfo mHostInfo;
LinkedList<Service> mServices;
SingleServiceMode mSingleServiceMode;
TimerMilli mTimer;
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
AutoStart mAutoStart;

View File

@ -168,6 +168,30 @@ exit:
return;
}
Server::TtlConfig::TtlConfig(void)
{
mMinTtl = kDefaultMinTtl;
mMaxTtl = kDefaultMaxTtl;
}
Error Server::SetTtlConfig(const TtlConfig &aTtlConfig)
{
Error error = kErrorNone;
VerifyOrExit(aTtlConfig.IsValid(), error = kErrorInvalidArgs);
mTtlConfig = aTtlConfig;
exit:
return error;
}
uint32_t Server::TtlConfig::GrantTtl(uint32_t aLease, uint32_t aTtl) const
{
OT_ASSERT(mMinTtl <= mMaxTtl);
return OT_MAX(mMinTtl, OT_MIN(OT_MIN(mMaxTtl, aLease), aTtl));
}
Server::LeaseConfig::LeaseConfig(void)
{
mMinLease = kDefaultMinLease;
@ -266,7 +290,6 @@ void Server::AddHost(Host &aHost)
OT_ASSERT(mHosts.FindMatching(aHost.GetFullName()) == nullptr);
IgnoreError(mHosts.Add(aHost));
}
void Server::RemoveHost(Host *aHost, RetainName aRetainName, NotifyMode aNotifyServiceHandler)
{
VerifyOrExit(aHost != nullptr);
@ -374,20 +397,21 @@ void Server::HandleServiceUpdateResult(UpdateMetadata *aUpdate, Error aError)
void Server::CommitSrpUpdate(Error aError, Host &aHost, const MessageMetadata &aMessageMetadata)
{
CommitSrpUpdate(aError, aHost, aMessageMetadata.mDnsHeader, aMessageMetadata.mMessageInfo,
aMessageMetadata.mLeaseConfig);
aMessageMetadata.mTtlConfig, aMessageMetadata.mLeaseConfig);
}
void Server::CommitSrpUpdate(Error aError, UpdateMetadata &aUpdateMetadata)
{
CommitSrpUpdate(aError, aUpdateMetadata.GetHost(), aUpdateMetadata.GetDnsHeader(),
aUpdateMetadata.IsDirectRxFromClient() ? &aUpdateMetadata.GetMessageInfo() : nullptr,
aUpdateMetadata.GetLeaseConfig());
aUpdateMetadata.GetTtlConfig(), aUpdateMetadata.GetLeaseConfig());
}
void Server::CommitSrpUpdate(Error aError,
Host & aHost,
const Dns::UpdateHeader &aDnsHeader,
const Ip6::MessageInfo * aMessageInfo,
const TtlConfig & aTtlConfig,
const LeaseConfig & aLeaseConfig)
{
Host * existingHost;
@ -395,6 +419,7 @@ void Server::CommitSrpUpdate(Error aError,
uint32_t hostKeyLease;
uint32_t grantedLease;
uint32_t grantedKeyLease;
uint32_t grantedTtl;
bool shouldFreeHost = true;
SuccessOrExit(aError);
@ -403,14 +428,17 @@ void Server::CommitSrpUpdate(Error aError,
hostKeyLease = aHost.GetKeyLease();
grantedLease = aLeaseConfig.GrantLease(hostLease);
grantedKeyLease = aLeaseConfig.GrantKeyLease(hostKeyLease);
grantedTtl = aTtlConfig.GrantTtl(grantedLease, aHost.GetTtl());
aHost.SetLease(grantedLease);
aHost.SetKeyLease(grantedKeyLease);
aHost.SetTtl(grantedTtl);
for (Service &service : aHost.mServices)
{
service.mDescription->mLease = grantedLease;
service.mDescription->mKeyLease = grantedKeyLease;
service.mDescription->mTtl = grantedTtl;
}
existingHost = mHosts.FindMatching(aHost.GetFullName());
@ -690,6 +718,8 @@ void Server::ProcessDnsUpdate(Message &aMessage, MessageMetadata &aMetadata)
// Parse lease time and validate signature.
SuccessOrExit(error = ProcessAdditionalSection(host, aMessage, aMetadata));
SuccessOrExit(error = ValidateServiceSubTypes(*host, aMetadata));
HandleUpdate(*host, aMetadata);
exit:
@ -802,6 +832,8 @@ Error Server::ProcessHostDescriptionInstruction(Host & aHost,
VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
SuccessOrExit(error = aHost.SetFullName(name));
SuccessOrExit(error = aMessage.Read(offset, aaaaRecord));
@ -816,6 +848,9 @@ Error Server::ProcessHostDescriptionInstruction(Host & aHost,
Dns::Ecdsa256KeyRecord keyRecord;
VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
SuccessOrExit(error = aMessage.Read(offset, keyRecord));
VerifyOrExit(keyRecord.IsValid(), error = kErrorParse);
@ -908,6 +943,11 @@ Error Server::ProcessServiceDiscoveryInstructions(Host & aHost,
// This RR is a "Delete an RR from an RRset" update when the CLASS is NONE.
service->mIsDeleted = (ptrRecord.GetClass() == Dns::ResourceRecord::kClassNone);
if (!service->mIsDeleted)
{
SuccessOrExit(error = aHost.ProcessTtl(ptrRecord.GetTtl()));
}
}
exit:
@ -959,6 +999,9 @@ Error Server::ProcessServiceDescriptionInstructions(Host & aHost,
uint16_t hostNameLength = sizeof(hostName);
VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
SuccessOrExit(error = aMessage.Read(offset, srvRecord));
offset += sizeof(srvRecord);
@ -971,6 +1014,7 @@ Error Server::ProcessServiceDescriptionInstructions(Host & aHost,
// Make sure that this is the first SRV RR for this service description
VerifyOrExit(desc->mPort == 0, error = kErrorFailed);
desc->mTtl = srvRecord.GetTtl();
desc->mPriority = srvRecord.GetPriority();
desc->mWeight = srvRecord.GetWeight();
desc->mPort = srvRecord.GetPort();
@ -980,6 +1024,8 @@ Error Server::ProcessServiceDescriptionInstructions(Host & aHost,
{
VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
desc = aHost.FindServiceDescription(name);
VerifyOrExit(desc != nullptr, error = kErrorFailed);
@ -1155,6 +1201,68 @@ exit:
return error;
}
Error Server::ValidateServiceSubTypes(Host &aHost, const MessageMetadata &aMetadata)
{
Error error = kErrorNone;
Host *existingHost;
// Verify that there is a matching base type service for all
// sub-type services in `aHost` (which is from the received
// and parsed SRP Update message).
for (const Service &service : aHost.GetServices())
{
if (service.IsSubType() && (aHost.FindBaseService(service.GetInstanceName()) == nullptr))
{
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
char subLabel[Dns::Name::kMaxLabelSize];
IgnoreError(service.GetServiceSubTypeLabel(subLabel, sizeof(subLabel)));
LogWarn("Message contains instance %s with subtype %s without base type", service.GetInstanceName(),
subLabel);
#endif
ExitNow(error = kErrorParse);
}
}
// SRP server must treat the update instructions for a service type
// and all its sub-types as atomic, i.e., when a service and its
// sub-types are being updated, whatever information appears in the
// SRP Update is the entirety of information about that service and
// its sub-types. Any previously registered sub-type that does not
// appear in a new SRP Update, must be removed.
//
// We go though the list of registered services for the same host
// and if the base service is included in the new SRP Update
// message, we add any previously registered service sub-type that
// does not appear in new Update message as "deleted".
existingHost = mHosts.FindMatching(aHost.GetFullName());
VerifyOrExit(existingHost != nullptr);
for (const Service &baseService : existingHost->GetServices())
{
if (baseService.IsSubType() || (aHost.FindBaseService(baseService.GetInstanceName()) == nullptr))
{
continue;
}
for (const Service &subService : existingHost->GetServices())
{
if (!subService.IsSubType() || !subService.MatchesInstanceName(baseService.GetInstanceName()))
{
continue;
}
SuccessOrExit(error = aHost.AddCopyOfServiceAsDeletedIfNotPresent(subService, aMetadata.mRxTime));
}
}
exit:
return error;
}
void Server::HandleUpdate(Host &aHost, const MessageMetadata &aMetadata)
{
Error error = kErrorNone;
@ -1180,32 +1288,36 @@ void Server::HandleUpdate(Host &aHost, const MessageMetadata &aMetadata)
continue;
}
if (aHost.FindService(service.GetServiceName(), service.GetInstanceName()) == nullptr)
{
Service *newService = aHost.AddNewService(service.GetServiceName(), service.GetInstanceName(),
service.IsSubType(), aMetadata.mRxTime);
VerifyOrExit(newService != nullptr, error = kErrorNoBufs);
newService->mDescription->mUpdateTime = aMetadata.mRxTime;
newService->mIsDeleted = true;
}
SuccessOrExit(error = aHost.AddCopyOfServiceAsDeletedIfNotPresent(service, aMetadata.mRxTime));
}
exit:
if ((error == kErrorNone) && (mServiceUpdateHandler != nullptr))
InformUpdateHandlerOrCommit(error, aHost, aMetadata);
}
void Server::InformUpdateHandlerOrCommit(Error aError, Host &aHost, const MessageMetadata &aMetadata)
{
if ((aError == kErrorNone) && (mServiceUpdateHandler != nullptr))
{
UpdateMetadata *update = UpdateMetadata::Allocate(GetInstance(), aHost, aMetadata);
mOutstandingUpdates.Push(*update);
mOutstandingUpdatesTimer.FireAtIfEarlier(update->GetExpireTime());
if (update != nullptr)
{
mOutstandingUpdates.Push(*update);
mOutstandingUpdatesTimer.FireAtIfEarlier(update->GetExpireTime());
LogInfo("SRP update handler is notified (updatedId = %u)", update->GetId());
mServiceUpdateHandler(update->GetId(), &aHost, kDefaultEventsHandlerTimeout, mServiceUpdateHandlerContext);
}
else
{
CommitSrpUpdate(error, aHost, aMetadata);
LogInfo("SRP update handler is notified (updatedId = %u)", update->GetId());
mServiceUpdateHandler(update->GetId(), &aHost, kDefaultEventsHandlerTimeout, mServiceUpdateHandlerContext);
ExitNow();
}
aError = kErrorNoBufs;
}
CommitSrpUpdate(aError, aHost, aMetadata);
exit:
return;
}
void Server::SendResponse(const Dns::UpdateHeader & aHeader,
@ -1236,6 +1348,8 @@ void Server::SendResponse(const Dns::UpdateHeader & aHeader,
LogInfo("Send success response");
}
UpdateResponseCounters(aResponseCode);
exit:
if (error != kErrorNone)
{
@ -1283,6 +1397,8 @@ void Server::SendResponse(const Dns::UpdateHeader &aHeader,
LogInfo("Send success response with granted lease: %u and key lease: %u", aLease, aKeyLease);
UpdateResponseCounters(Dns::UpdateHeader::kResponseSuccess);
exit:
if (error != kErrorNone)
{
@ -1308,11 +1424,12 @@ void Server::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessag
Error Server::ProcessMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
return ProcessMessage(aMessage, TimerMilli::GetNow(), mLeaseConfig, &aMessageInfo);
return ProcessMessage(aMessage, TimerMilli::GetNow(), mTtlConfig, mLeaseConfig, &aMessageInfo);
}
Error Server::ProcessMessage(Message & aMessage,
TimeMilli aRxTime,
const TtlConfig & aTtlConfig,
const LeaseConfig & aLeaseConfig,
const Ip6::MessageInfo *aMessageInfo)
{
@ -1321,6 +1438,7 @@ Error Server::ProcessMessage(Message & aMessage,
metadata.mOffset = aMessage.GetOffset();
metadata.mRxTime = aRxTime;
metadata.mTtlConfig = aTtlConfig;
metadata.mLeaseConfig = aLeaseConfig;
metadata.mMessageInfo = aMessageInfo;
@ -1482,6 +1600,31 @@ const char *Server::AddressModeToString(AddressMode aMode)
return kAddressModeStrings[aMode];
}
void Server::UpdateResponseCounters(Dns::UpdateHeader::Response aResponseCode)
{
switch (aResponseCode)
{
case Dns::UpdateHeader::kResponseSuccess:
++mResponseCounters.mSuccess;
break;
case Dns::UpdateHeader::kResponseServerFailure:
++mResponseCounters.mServerFailure;
break;
case Dns::UpdateHeader::kResponseFormatError:
++mResponseCounters.mFormatError;
break;
case Dns::UpdateHeader::kResponseNameExists:
++mResponseCounters.mNameExists;
break;
case Dns::UpdateHeader::kResponseRefused:
++mResponseCounters.mRefused;
break;
default:
++mResponseCounters.mOther;
break;
}
}
//---------------------------------------------------------------------------------------------------------------------
// Server::Service
@ -1540,6 +1683,18 @@ TimeMilli Server::Service::GetKeyExpireTime(void) const
return mUpdateTime + Time::SecToMsec(mDescription->mKeyLease);
}
void Server::Service::GetLeaseInfo(LeaseInfo &aLeaseInfo) const
{
TimeMilli now = TimerMilli::GetNow();
TimeMilli expireTime = GetExpireTime();
TimeMilli keyExpireTime = GetKeyExpireTime();
aLeaseInfo.mLease = Time::SecToMsec(GetLease());
aLeaseInfo.mKeyLease = Time::SecToMsec(GetKeyLease());
aLeaseInfo.mRemainingLease = (now <= expireTime) ? (expireTime - now) : 0;
aLeaseInfo.mRemainingKeyLease = (now <= keyExpireTime) ? (keyExpireTime - now) : 0;
}
bool Server::Service::MatchesInstanceName(const char *aInstanceName) const
{
return StringMatch(mDescription->mInstanceName.AsCString(), aInstanceName, kStringCaseInsensitiveMatch);
@ -1627,6 +1782,7 @@ Error Server::Service::Description::Init(const char *aInstanceName, Host &aHost)
mHost = &aHost;
mPriority = 0;
mWeight = 0;
mTtl = 0;
mPort = 0;
mLease = 0;
mKeyLease = 0;
@ -1655,6 +1811,7 @@ void Server::Service::Description::TakeResourcesFrom(Description &aDescription)
mWeight = aDescription.mWeight;
mPort = aDescription.mPort;
mTtl = aDescription.mTtl;
mLease = aDescription.mLease;
mKeyLease = aDescription.mKeyLease;
mUpdateTime = TimerMilli::GetNow();
@ -1683,6 +1840,7 @@ exit:
Server::Host::Host(Instance &aInstance, TimeMilli aUpdateTime)
: InstanceLocator(aInstance)
, mNext(nullptr)
, mTtl(0)
, mLease(0)
, mKeyLease(0)
, mUpdateTime(aUpdateTime)
@ -1739,6 +1897,38 @@ TimeMilli Server::Host::GetKeyExpireTime(void) const
return mUpdateTime + Time::SecToMsec(mKeyLease);
}
void Server::Host::GetLeaseInfo(LeaseInfo &aLeaseInfo) const
{
TimeMilli now = TimerMilli::GetNow();
TimeMilli expireTime = GetExpireTime();
TimeMilli keyExpireTime = GetKeyExpireTime();
aLeaseInfo.mLease = Time::SecToMsec(GetLease());
aLeaseInfo.mKeyLease = Time::SecToMsec(GetKeyLease());
aLeaseInfo.mRemainingLease = (now <= expireTime) ? (expireTime - now) : 0;
aLeaseInfo.mRemainingKeyLease = (now <= keyExpireTime) ? (keyExpireTime - now) : 0;
}
Error Server::Host::ProcessTtl(uint32_t aTtl)
{
// This method processes the TTL value received in a resource record.
//
// If no TTL value is stored, this method wil set the stored value to @p aTtl and return `kErrorNone`.
// If a TTL value is stored and @p aTtl equals the stored value, this method returns `kErrorNone`.
// Otherwise, this method returns `kErrorRejected`.
Error error = kErrorRejected;
VerifyOrExit(aTtl && (mTtl == 0 || mTtl == aTtl));
mTtl = aTtl;
error = kErrorNone;
exit:
return error;
}
const Server::Service *Server::Host::FindNextService(const Service *aPrevService,
Service::Flags aFlags,
const char * aServiceName,
@ -1825,6 +2015,25 @@ exit:
return;
}
Error Server::Host::AddCopyOfServiceAsDeletedIfNotPresent(const Service &aService, TimeMilli aUpdateTime)
{
Error error = kErrorNone;
Service *newService;
VerifyOrExit(FindService(aService.GetServiceName(), aService.GetInstanceName()) == nullptr);
newService =
AddNewService(aService.GetServiceName(), aService.GetInstanceName(), aService.IsSubType(), aUpdateTime);
VerifyOrExit(newService != nullptr, error = kErrorNoBufs);
newService->mDescription->mUpdateTime = aUpdateTime;
newService->mIsDeleted = true;
exit:
return error;
}
void Server::Host::FreeAllServices(void)
{
while (!mServices.IsEmpty())
@ -1850,6 +2059,7 @@ Error Server::Host::MergeServicesAndResourcesFrom(Host &aHost)
mAddresses.TakeFrom(static_cast<Heap::Array<Ip6::Address> &&>(aHost.mAddresses));
mKeyRecord = aHost.mKeyRecord;
mTtl = aHost.mTtl;
mLease = aHost.mLease;
mKeyLease = aHost.mKeyLease;
mUpdateTime = TimerMilli::GetNow();
@ -1929,6 +2139,17 @@ Server::Service *Server::Host::FindService(const char *aServiceName, const char
return AsNonConst(AsConst(this)->FindService(aServiceName, aInstanceName));
}
const Server::Service *Server::Host::FindBaseService(const char *aInstanceName) const
{
return FindNextService(/*a PrevService */ nullptr, kFlagsBaseTypeServiceOnly, /* aServiceName */ nullptr,
aInstanceName);
}
Server::Service *Server::Host::FindBaseService(const char *aInstanceName)
{
return AsNonConst(AsConst(this)->FindBaseService(aInstanceName));
}
Error Server::Host::AddIp6Address(const Ip6::Address &aIp6Address)
{
Error error = kErrorNone;
@ -1963,6 +2184,7 @@ Server::UpdateMetadata::UpdateMetadata(Instance &aInstance, Host &aHost, const M
, mExpireTime(TimerMilli::GetNow() + kDefaultEventsHandlerTimeout)
, mDnsHeader(aMessageMetadata.mDnsHeader)
, mId(Get<Server>().AllocateId())
, mTtlConfig(aMessageMetadata.mTtlConfig)
, mLeaseConfig(aMessageMetadata.mLeaseConfig)
, mHost(aHost)
, mIsDirectRxFromClient(aMessageMetadata.IsDirectRxFromClient())

View File

@ -129,6 +129,12 @@ public:
*/
typedef otSrpServerServiceUpdateId ServiceUpdateId;
/**
* The SRP server lease information of a host/service.
*
*/
typedef otSrpServerLeaseInfo LeaseInfo;
/**
* This enumeration represents the address mode used by the SRP server.
*
@ -253,6 +259,14 @@ public:
*/
Error GetServiceSubTypeLabel(char *aLabel, uint8_t aMaxSize) const;
/**
* This method returns the TTL of the service instance.
*
* @returns The TTL of the service instance.
*
*/
uint32_t GetTtl(void) const { return mDescription->mTtl; }
/**
* This method returns the port of the service instance.
*
@ -301,6 +315,22 @@ public:
*/
const Host &GetHost(void) const { return *mDescription->mHost; }
/**
* This method returns the LEASE time of the service.
*
* @returns The LEASE time in seconds.
*
*/
uint32_t GetLease(void) const { return mDescription->mLease; }
/**
* This method returns the KEY-LEASE time of the key of the service.
*
* @returns The KEY-LEASE time in seconds.
*
*/
uint32_t GetKeyLease(void) const { return mDescription->mKeyLease; }
/**
* This method returns the expire time (in milliseconds) of the service.
*
@ -317,6 +347,15 @@ public:
*/
TimeMilli GetKeyExpireTime(void) const;
/**
* This method gets the LEASE and KEY-LEASE information of a given service.
*
* @param[out] aLeaseInfo A reference to a LeaseInfo instance. It contains the LEASE time, KEY-LEASE time,
* remaining LEASE time and the remaining KEY-LEASE time.
*
*/
void GetLeaseInfo(LeaseInfo &aLeaseInfo) const;
/**
* This method indicates whether this service matches a given service instance name.
*
@ -359,6 +398,7 @@ public:
uint16_t mPriority;
uint16_t mWeight;
uint16_t mPort;
uint32_t mTtl; // The TTL in seconds.
uint32_t mLease; // The LEASE time in seconds.
uint32_t mKeyLease; // The KEY-LEASE time in seconds.
TimeMilli mUpdateTime;
@ -436,6 +476,14 @@ public:
return mAddresses.AsCArray();
}
/**
* This method returns the TTL of the host.
*
* @returns The TTL of the host.
*
*/
uint32_t GetTtl(void) const { return mTtl; }
/**
* This method returns the LEASE time of the host.
*
@ -452,6 +500,15 @@ public:
*/
uint32_t GetKeyLease(void) const { return mKeyLease; }
/**
* This method gets the LEASE and KEY-LEASE information of a given host.
*
* @param[out] aLeaseInfo A reference to a LeaseInfo instance. It contains the LEASE time, KEY-LEASE time,
* remaining LEASE time and the remaining KEY-LEASE time.
*
*/
void GetLeaseInfo(LeaseInfo &aLeaseInfo) const;
/**
* This method returns the KEY resource record of the host.
*
@ -515,16 +572,20 @@ public:
Host(Instance &aInstance, TimeMilli aUpdateTime);
~Host(void);
Error SetFullName(const char *aFullName);
void SetKeyRecord(Dns::Ecdsa256KeyRecord &aKeyRecord);
void SetLease(uint32_t aLease) { mLease = aLease; }
void SetKeyLease(uint32_t aKeyLease) { mKeyLease = aKeyLease; }
Error SetFullName(const char *aFullName);
void SetKeyRecord(Dns::Ecdsa256KeyRecord &aKeyRecord);
void SetTtl(uint32_t aTtl) { mTtl = aTtl; }
void SetLease(uint32_t aLease) { mLease = aLease; }
void SetKeyLease(uint32_t aKeyLease) { mKeyLease = aKeyLease; }
Error ProcessTtl(uint32_t aTtl);
LinkedList<Service> &GetServices(void) { return mServices; }
Service * AddNewService(const char *aServiceName,
const char *aInstanceName,
bool aIsSubType,
TimeMilli aUpdateTime);
void RemoveService(Service *aService, RetainName aRetainName, NotifyMode aNotifyServiceHandler);
Error AddCopyOfServiceAsDeletedIfNotPresent(const Service &aService, TimeMilli aUpdateTime);
void FreeAllServices(void);
void ClearResources(void);
Error MergeServicesAndResourcesFrom(Host &aHost);
@ -534,6 +595,8 @@ public:
const RetainPtr<Service::Description> FindServiceDescription(const char *aInstanceName) const;
Service * FindService(const char *aServiceName, const char *aInstanceName);
const Service * FindService(const char *aServiceName, const char *aInstanceName) const;
Service * FindBaseService(const char *aInstanceName);
const Service * FindBaseService(const char *aInstanceName) const;
Host * mNext;
Heap::String mFullName;
@ -542,12 +605,33 @@ public:
// TODO(wgtdkp): there is no necessary to save the entire resource
// record, saving only the ECDSA-256 public key should be enough.
Dns::Ecdsa256KeyRecord mKeyRecord;
uint32_t mTtl; // The TTL in seconds.
uint32_t mLease; // The LEASE time in seconds.
uint32_t mKeyLease; // The KEY-LEASE time in seconds.
TimeMilli mUpdateTime;
LinkedList<Service> mServices;
};
/**
* This class handles TTL configuration.
*
*/
class TtlConfig : public otSrpServerTtlConfig
{
friend class Server;
public:
/**
* This constructor initializes to default TTL configuration.
*
*/
TtlConfig(void);
private:
bool IsValid(void) const { return mMinTtl <= mMaxTtl; }
uint32_t GrantTtl(uint32_t aLease, uint32_t aTtl) const;
};
/**
* This class handles LEASE and KEY-LEASE configurations.
*
@ -704,6 +788,14 @@ public:
*/
State GetState(void) const { return mState; }
/**
* This method tells the port the SRP server is listening to.
*
* @returns An integer that represents the port of the server. It returns 0 if the SRP server is not running.
*
*/
uint16_t GetPort(void) const { return IsRunning() ? mPort : 0; }
/**
* This method enables/disables the SRP server.
*
@ -712,6 +804,25 @@ public:
*/
void SetEnabled(bool aEnabled);
/**
* This method returns the TTL configuration.
*
* @param[out] aTtlConfig A reference to the `TtlConfig` instance.
*
*/
void GetTtlConfig(TtlConfig &aTtlConfig) const { aTtlConfig = mTtlConfig; }
/**
* This method sets the TTL configuration.
*
* @param[in] aTtlConfig A reference to the `TtlConfig` instance.
*
* @retval kErrorNone Successfully set the TTL configuration
* @retval kErrorInvalidArgs The TTL range is not valid.
*
*/
Error SetTtlConfig(const TtlConfig &aTtlConfig);
/**
* This method returns the LEASE and KEY-LEASE configurations.
*
@ -745,6 +856,14 @@ public:
*/
const Host *GetNextHost(const Host *aHost);
/**
* This method returns the response counters of the SRP server.
*
* @returns A pointer to the response counters of the SRP server.
*
*/
const otSrpServerResponseCounters *GetResponseCounters(void) const { return &mResponseCounters; }
/**
* This method receives the service update result from service handler set by
* SetServiceHandler.
@ -758,6 +877,8 @@ public:
private:
static constexpr uint16_t kUdpPayloadSize = Ip6::kMaxDatagramLength - sizeof(Ip6::Udp::Header);
static constexpr uint32_t kDefaultMinTtl = 60u; // 1 min (in seconds).
static constexpr uint32_t kDefaultMaxTtl = 3600u * 2; // 2 hours (in seconds).
static constexpr uint32_t kDefaultMinLease = 60u * 30; // 30 min (in seconds).
static constexpr uint32_t kDefaultMaxLease = 3600u * 2; // 2 hours (in seconds).
static constexpr uint32_t kDefaultMinKeyLease = 3600u * 24; // 1 day (in seconds).
@ -780,6 +901,7 @@ private:
Dns::Zone mDnsZone;
uint16_t mOffset;
TimeMilli mRxTime;
TtlConfig mTtlConfig;
LeaseConfig mLeaseConfig;
const Ip6::MessageInfo *mMessageInfo; // Set to `nullptr` when from SRPL.
};
@ -797,6 +919,7 @@ private:
TimeMilli GetExpireTime(void) const { return mExpireTime; }
const Dns::UpdateHeader &GetDnsHeader(void) const { return mDnsHeader; }
ServiceUpdateId GetId(void) const { return mId; }
const TtlConfig & GetTtlConfig(void) const { return mTtlConfig; }
const LeaseConfig & GetLeaseConfig(void) const { return mLeaseConfig; }
Host & GetHost(void) { return mHost; }
const Ip6::MessageInfo & GetMessageInfo(void) const { return mMessageInfo; }
@ -810,6 +933,7 @@ private:
TimeMilli mExpireTime;
Dns::UpdateHeader mDnsHeader;
ServiceUpdateId mId; // The ID of this service update transaction.
TtlConfig mTtlConfig; // TTL config to use when processing the message.
LeaseConfig mLeaseConfig; // Lease config to use when processing the message.
Host & mHost; // The `UpdateMetadata` has no ownership of this host.
Ip6::MessageInfo mMessageInfo; // Valid when `mIsDirectRxFromClient` is true.
@ -831,16 +955,19 @@ private:
ServiceUpdateId AllocateId(void) { return mServiceUpdateId++; }
void InformUpdateHandlerOrCommit(Error aError, Host &aHost, const MessageMetadata &aMetadata);
void CommitSrpUpdate(Error aError, Host &aHost, const MessageMetadata &aMessageMetadata);
void CommitSrpUpdate(Error aError, UpdateMetadata &aUpdateMetadata);
void CommitSrpUpdate(Error aError,
Host & aHost,
const Dns::UpdateHeader &aDnsHeader,
const Ip6::MessageInfo * aMessageInfo,
const TtlConfig & aTtlConfig,
const LeaseConfig & aLeaseConfig);
Error ProcessMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
Error ProcessMessage(Message & aMessage,
TimeMilli aRxTime,
const TtlConfig & aTtlConfig,
const LeaseConfig & aLeaseConfig,
const Ip6::MessageInfo *aMessageInfo);
void ProcessDnsUpdate(Message &aMessage, MessageMetadata &aMetadata);
@ -853,6 +980,7 @@ private:
uint16_t aSigRdataOffset,
uint16_t aSigRdataLength,
const char * aSignerName) const;
Error ValidateServiceSubTypes(Host &aHost, const MessageMetadata &aMetadata);
Error ProcessZoneSection(const Message &aMessage, MessageMetadata &aMetadata) const;
Error ProcessHostDescriptionInstruction(Host & aHost,
const Message & aMessage,
@ -886,12 +1014,15 @@ private:
const UpdateMetadata *FindOutstandingUpdate(const MessageMetadata &aMessageMetadata) const;
static const char * AddressModeToString(AddressMode aMode);
void UpdateResponseCounters(Dns::Header::Response aResponseCode);
Ip6::Udp::Socket mSocket;
otSrpServerServiceUpdateHandler mServiceUpdateHandler;
void * mServiceUpdateHandlerContext;
Heap::String mDomain;
TtlConfig mTtlConfig;
LeaseConfig mLeaseConfig;
LinkedList<Host> mHosts;
@ -906,10 +1037,13 @@ private:
AddressMode mAddressMode;
uint8_t mAnycastSequenceNumber;
bool mHasRegisteredAnyService : 1;
otSrpServerResponseCounters mResponseCounters;
};
} // namespace Srp
DefineCoreType(otSrpServerTtlConfig, Srp::Server::TtlConfig);
DefineCoreType(otSrpServerLeaseConfig, Srp::Server::LeaseConfig);
DefineCoreType(otSrpServerHost, Srp::Server::Host);
DefineCoreType(otSrpServerService, Srp::Server::Service);

View File

@ -123,11 +123,9 @@ exit:
return error;
}
Instance &Tcp::Endpoint::GetInstance(void)
Instance &Tcp::Endpoint::GetInstance(void) const
{
struct tcpcb &tp = GetTcb();
return AsCoreType(tp.instance);
return AsNonConst(AsCoreType(GetTcb().instance));
}
const SockAddr &Tcp::Endpoint::GetLocalAddress(void) const
@ -160,7 +158,7 @@ Error Tcp::Endpoint::Bind(const SockAddr &aSockName)
struct tcpcb &tp = GetTcb();
VerifyOrExit(!AsCoreType(&aSockName.mAddress).IsUnspecified(), error = kErrorInvalidArgs);
VerifyOrExit(GetInstance().Get<Tcp>().CanBind(aSockName), error = kErrorInvalidState);
VerifyOrExit(Get<Tcp>().CanBind(aSockName), error = kErrorInvalidState);
memcpy(&tp.laddr, &aSockName.mAddress, sizeof(tp.laddr));
tp.lport = HostSwap16(aSockName.mPort);
@ -275,9 +273,7 @@ Error Tcp::Endpoint::Deinitialize(void)
{
Error error;
Tcp &tcp = GetInstance().Get<Tcp>();
SuccessOrExit(error = tcp.mEndpoints.Remove(*this));
SuccessOrExit(error = Get<Tcp>().mEndpoints.Remove(*this));
SetNext(nullptr);
SuccessOrExit(error = Abort());
@ -356,7 +352,7 @@ void Tcp::Endpoint::SetTimer(uint8_t aTimerFlag, uint32_t aDelay)
LogDebg("Endpoint %p set timer %u to %u ms", static_cast<void *>(this), static_cast<unsigned int>(timerIndex),
static_cast<unsigned int>(aDelay));
GetInstance().Get<Tcp>().mTimer.FireAtIfEarlier(newFireTime);
Get<Tcp>().mTimer.FireAtIfEarlier(newFireTime);
}
void Tcp::Endpoint::CancelTimer(uint8_t aTimerFlag)
@ -451,7 +447,7 @@ void Tcp::Endpoint::PostCallbacksAfterSend(size_t aSent, size_t aBacklogBefore)
if (backlogAfter < aBacklogBefore + aSent && mForwardProgressCallback != nullptr)
{
mPendingCallbacks |= kForwardProgressCallbackFlag;
GetInstance().Get<Tcp>().mTasklet.Post();
Get<Tcp>().mTasklet.Post();
}
}
@ -542,11 +538,9 @@ exit:
return error;
}
Instance &Tcp::Listener::GetInstance(void)
Instance &Tcp::Listener::GetInstance(void) const
{
struct tcpcb_listen *tpl = &GetTcbListen();
return AsCoreType(tpl->instance);
return AsNonConst(AsCoreType(GetTcbListen().instance));
}
Error Tcp::Listener::Listen(const SockAddr &aSockName)
@ -555,7 +549,7 @@ Error Tcp::Listener::Listen(const SockAddr &aSockName)
uint16_t port = HostSwap16(aSockName.mPort);
struct tcpcb_listen *tpl = &GetTcbListen();
VerifyOrExit(GetInstance().Get<Tcp>().CanBind(aSockName), error = kErrorInvalidState);
VerifyOrExit(Get<Tcp>().CanBind(aSockName), error = kErrorInvalidState);
memcpy(&tpl->laddr, &aSockName.mAddress, sizeof(tpl->laddr));
tpl->lport = port;
@ -580,9 +574,7 @@ Error Tcp::Listener::Deinitialize(void)
{
Error error;
Tcp &tcp = GetInstance().Get<Tcp>();
SuccessOrExit(error = tcp.mListeners.Remove(*this));
SuccessOrExit(error = Get<Tcp>().mListeners.Remove(*this));
SetNext(nullptr);
exit:
@ -812,7 +804,7 @@ bool Tcp::AutoBind(const SockAddr &aPeer, SockAddr &aToBind, bool aBindAddress,
peerInfo.Clear();
peerInfo.SetPeerAddr(aPeer.GetAddress());
netifAddress = InstanceLocator::GetInstance().Get<Ip6>().SelectSourceAddress(peerInfo);
netifAddress = Get<Ip6>().SelectSourceAddress(peerInfo);
VerifyOrExit(netifAddress != nullptr, success = false);
aToBind.GetAddress() = netifAddress->GetAddress();
}
@ -854,12 +846,12 @@ exit:
void Tcp::HandleTimer(Timer &aTimer)
{
OT_ASSERT(&aTimer == &aTimer.GetInstance().Get<Tcp>().mTimer);
OT_ASSERT(&aTimer == &aTimer.Get<Tcp>().mTimer);
LogDebg("Main TCP timer expired");
aTimer.GetInstance().Get<Tcp>().ProcessTimers();
aTimer.Get<Tcp>().ProcessTimers();
}
void Tcp::ProcessTimers()
void Tcp::ProcessTimers(void)
{
TimeMilli now = TimerMilli::GetNow();
bool pendingTimer;
@ -1014,7 +1006,7 @@ void tcplp_sys_stop_timer(struct tcpcb *aTcb, uint8_t aTimerFlag)
struct tcpcb *tcplp_sys_accept_ready(struct tcpcb_listen *aTcbListen, struct in6_addr *aAddr, uint16_t aPort)
{
Tcp::Listener & listener = Tcp::Listener::FromTcbListen(*aTcbListen);
Tcp & tcp = listener.GetInstance().Get<Tcp>();
Tcp & tcp = listener.Get<Tcp>();
struct tcpcb * rv = (struct tcpcb *)-1;
otSockAddr addr;
otTcpEndpoint * endpointPtr;
@ -1065,7 +1057,7 @@ bool tcplp_sys_accepted_connection(struct tcpcb_listen *aTcbListen,
{
Tcp::Listener &listener = Tcp::Listener::FromTcbListen(*aTcbListen);
Tcp::Endpoint &endpoint = Tcp::Endpoint::FromTcb(*aAccepted);
Tcp & tcp = endpoint.GetInstance().Get<Tcp>();
Tcp & tcp = endpoint.Get<Tcp>();
bool accepted = true;
if (listener.mAcceptDoneCallback != nullptr)

View File

@ -83,7 +83,7 @@ public:
* This class represents an endpoint of a TCP/IPv6 connection.
*
*/
class Endpoint : public otTcpEndpoint, public LinkedListEntry<Endpoint>
class Endpoint : public otTcpEndpoint, public LinkedListEntry<Endpoint>, public GetProvider<Endpoint>
{
friend class Tcp;
friend class LinkedList<Endpoint>;
@ -118,7 +118,7 @@ public:
* @returns The Instance pointer associated with this Endpoint.
*
*/
Instance &GetInstance(void);
Instance &GetInstance(void) const;
/**
* Obtains the context pointer that was associated this Endpoint upon
@ -402,7 +402,7 @@ public:
* This class represents a TCP/IPv6 listener.
*
*/
class Listener : public otTcpListener, public LinkedListEntry<Listener>
class Listener : public otTcpListener, public LinkedListEntry<Listener>, public GetProvider<Listener>
{
friend class LinkedList<Listener>;
@ -436,7 +436,7 @@ public:
* @returns The otInstance pointer associated with this Listener.
*
*/
Instance &GetInstance(void);
Instance &GetInstance(void) const;
/**
* Obtains the context pointer that was associated with this Listener upon

View File

@ -37,8 +37,10 @@
#include <openthread/config.h>
#define OT_THREAD_VERSION_INVALID 0
#define OT_THREAD_VERSION_1_1 2
#define OT_THREAD_VERSION_1_2 3
#define OT_THREAD_VERSION_1_3 4
#define OPENTHREAD_CORE_CONFIG_H_IN
@ -51,7 +53,7 @@
#endif
#ifndef OPENTHREAD_CONFIG_THREAD_VERSION
#define OPENTHREAD_CONFIG_THREAD_VERSION OT_THREAD_VERSION_1_2
#define OPENTHREAD_CONFIG_THREAD_VERSION OT_THREAD_VERSION_1_3
#endif
#include "config/announce_sender.h"

View File

@ -522,6 +522,7 @@ public:
* @param[in] aScanDuration The duration, in milliseconds, for the channel to be scanned.
*
* @retval kErrorNone Successfully started scanning the channel.
* @retval kErrorBusy The radio is performing energy scanning.
* @retval kErrorNotImplemented The radio doesn't support energy scanning.
*
*/

View File

@ -47,8 +47,12 @@ if(OT_VENDOR_EXTENSION)
target_sources(openthread-radio-cli PRIVATE ${OT_VENDOR_EXTENSION})
endif()
if(NOT DEFINED OT_MBEDTLS_RCP)
set(OT_MBEDTLS_RCP ${OT_MBEDTLS})
endif()
target_link_libraries(openthread-radio-cli
PRIVATE
${OT_MBEDTLS}
${OT_MBEDTLS_RCP}
ot-config
)

Some files were not shown because too many files have changed in this diff Show More