diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b4cb6e3b2..3c4905398 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -29,6 +29,7 @@ version: 2 updates: - package-ecosystem: "github-actions" + if: github.repository == "openthread/openthread" directory: "/" schedule: interval: "weekly" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5f3d85ab2..9ef50e54d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -233,6 +233,9 @@ jobs: - gcc_ver: 12 gcc_download_url: https://developer.arm.com/-/media/Files/downloads/gnu/12.2.rel1/binrel/arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-eabi.tar.xz gcc_extract_dir: arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-eabi + - gcc_ver: 13 + gcc_download_url: https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x86_64-arm-none-eabi.tar.xz + gcc_extract_dir: arm-gnu-toolchain-13.2.Rel1-x86_64-arm-none-eabi steps: - name: Harden Runner uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 8cce3c7f4..09f37e772 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -91,7 +91,7 @@ jobs: - name: Login to DockerHub if: success() && github.repository == 'openthread/openthread' && github.event_name != 'pull_request' - uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc # v2.2.0 + uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} diff --git a/.github/workflows/otbr.yml b/.github/workflows/otbr.yml index 62cddbf50..d964cddd9 100644 --- a/.github/workflows/otbr.yml +++ b/.github/workflows/otbr.yml @@ -86,11 +86,12 @@ jobs: export CI_ENV="$(bash <(curl -s https://codecov.io/env)) -e GITHUB_ACTIONS -e COVERAGE" echo "CI_ENV=${CI_ENV}" sudo -E ./script/test cert_suite ./tests/scripts/thread-cert/backbone/*.py || (sudo chmod a+r *.log *.json *.pcap && false) - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-thread-1-3-backbone-docker path: /tmp/coverage/ - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + retention-days: 1 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() }} with: name: thread-1-3-backbone-results @@ -103,10 +104,11 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-thread-1-3-backbone path: tmp/coverage.info + retention-days: 1 thread-border-router: runs-on: ubuntu-20.04 @@ -143,7 +145,7 @@ jobs: cert_scripts: ./tests/scripts/thread-cert/border_router/nat64/*.py packet_verification: 1 nat64: 1 - description: "nat64 openthread" + description: "nat64" - otbr_mdns: "avahi" otbr_trel: 0 cert_scripts: ./tests/scripts/thread-cert/border_router/*.py @@ -162,7 +164,7 @@ jobs: packet_verification: 1 nat64: 0 use_core_firewall: 1 - description: "core firewall" + description: "core-firewall" name: BR ${{ matrix.description }} (${{ matrix.otbr_mdns }}, TREL=${{matrix.otbr_trel}}) env: REFERENCE_DEVICE: 1 @@ -206,14 +208,15 @@ jobs: export CI_ENV="$(bash <(curl -s https://codecov.io/env)) -e GITHUB_ACTIONS -e COVERAGE" echo "CI_ENV=${CI_ENV}" sudo -E ./script/test cert_suite ${{ matrix.cert_scripts }} || (sudo chmod a+r *.log *.json *.pcap && false) - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: - name: cov-thread-border-router-docker + name: cov-br-docker-${{ matrix.description }}-${{ matrix.otbr_mdns }}-${{matrix.otbr_trel}} path: /tmp/coverage/ - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + retention-days: 1 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() }} with: - name: thread-border-router-results + name: br-results-${{ matrix.description }}-${{ matrix.otbr_mdns }}-${{matrix.otbr_trel}} path: | *.pcap *.json @@ -223,10 +226,11 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: - name: cov-thread-border-router + name: cov-br-${{ matrix.description }}-${{ matrix.otbr_mdns }}-${{matrix.otbr_trel}} path: tmp/coverage.info + retention-days: 1 upload-coverage: needs: @@ -240,9 +244,11 @@ jobs: - name: Bootstrap run: | sudo apt-get --no-install-recommends install -y lcov - - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + - uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1 with: path: coverage/ + pattern: cov-* + merge-multiple: true - name: Combine Coverage continue-on-error: true run: | @@ -253,12 +259,3 @@ jobs: with: files: final.info fail_ci_if_error: true - - delete-coverage-artifacts: - needs: upload-coverage - runs-on: ubuntu-20.04 - steps: - - uses: geekyeggo/delete-artifact@54ab544f12cdb7b71613a16a2b5a37a9ade990af # v2.0.0 - with: - name: cov-* - useGlob: true diff --git a/.github/workflows/otns.yml b/.github/workflows/otns.yml index 05ca7e32a..d21f7ad56 100644 --- a/.github/workflows/otns.yml +++ b/.github/workflows/otns.yml @@ -63,7 +63,7 @@ jobs: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 + - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version: "1.20" - name: Set up Python @@ -82,7 +82,7 @@ jobs: cd /tmp/otns ./script/test py-unittests ) - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() }} with: name: unittests-pcaps @@ -92,17 +92,18 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-otns-unittests path: tmp/coverage.info + retention-days: 1 examples: name: Examples runs-on: ubuntu-22.04 steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 + - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version: "1.20" - name: Set up Python @@ -121,7 +122,7 @@ jobs: cd /tmp/otns ./script/test py-examples ) - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() }} with: name: examples-pcaps @@ -131,7 +132,7 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-otns-examples path: tmp/coverage.info @@ -164,7 +165,7 @@ jobs: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 + - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version: "1.20" - name: Set up Python @@ -183,7 +184,7 @@ jobs: cd /tmp/otns ./script/test stress-tests ${{ matrix.suite }} ) - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() }} with: name: stress-tests-${{ matrix.suite }}-pcaps @@ -193,10 +194,11 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-otns-stress-tests-${{ matrix.suite }} path: tmp/coverage.info + retention-days: 1 upload-coverage: needs: @@ -214,9 +216,11 @@ jobs: - name: Bootstrap run: | sudo apt-get --no-install-recommends install -y lcov - - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + - uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1 with: path: coverage/ + pattern: cov-* + merge-multiple: true - name: Upload Coverage run: | script/test upload_codecov diff --git a/.github/workflows/posix.yml b/.github/workflows/posix.yml index b019a255a..efdb085f8 100644 --- a/.github/workflows/posix.yml +++ b/.github/workflows/posix.yml @@ -75,7 +75,7 @@ jobs: CRASHED=$(./script/test check_crash | tail -1) [[ $CRASHED -eq "1" ]] && echo "Crashed!" || echo "Not crashed." echo "CRASHED_RCP=$CRASHED" >> $GITHUB_ENV - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() && env.CRASHED_RCP == '1' }} with: name: core-expect-rcp @@ -84,10 +84,11 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-expects-linux-1 path: tmp/coverage.info + retention-days: 1 - name: Run TUN Mode run: | sudo rm /etc/apt/sources.list.d/* && sudo apt-get update @@ -107,13 +108,13 @@ jobs: CRASHED=$(./script/test check_crash | tail -1) [[ $CRASHED -eq "1" ]] && echo "Crashed!" || echo "Not crashed." echo "CRASHED_TUN=$CRASHED" >> $GITHUB_ENV - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() && env.CRASHED_TUN == '1' }} with: name: core-expect-linux path: | ./ot-core-dump/* - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() }} with: name: syslog-expect-linux @@ -121,10 +122,11 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-expects-linux-2 path: tmp/coverage.info + retention-days: 1 thread-cert: runs-on: ubuntu-20.04 @@ -153,7 +155,7 @@ jobs: - name: Run run: | MAX_JOBS=$(getconf _NPROCESSORS_ONLN) ./script/test cert_suite ./tests/scripts/thread-cert/Cert_*.py ./tests/scripts/thread-cert/test_*.py - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() }} with: name: thread-cert @@ -161,7 +163,7 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-thread-cert path: tmp/coverage.info @@ -211,10 +213,11 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-pty-linux-${{ matrix.DAEMON }} path: tmp/coverage.info + retention-days: 1 pty-macos: name: pty-macos OT_DAEMON=${{ matrix.OT_DAEMON }} @@ -278,10 +281,11 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-rcp-stack-reset path: tmp/coverage.info + retention-days: 1 upload-coverage: needs: @@ -301,9 +305,11 @@ jobs: - name: Bootstrap run: | sudo apt-get --no-install-recommends install -y lcov - - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + - uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1 with: path: coverage/ + pattern: cov-* + merge-multiple: true - name: Combine Coverage run: | script/test combine_coverage @@ -312,17 +318,3 @@ jobs: with: files: final.info fail_ci_if_error: true - - delete-coverage-artifacts: - needs: upload-coverage - runs-on: ubuntu-20.04 - steps: - - name: Harden Runner - uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 - with: - egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - - uses: geekyeggo/delete-artifact@54ab544f12cdb7b71613a16a2b5a37a9ade990af # v2.0.0 - with: - name: cov-* - useGlob: true diff --git a/.github/workflows/simulation-1.1.yml b/.github/workflows/simulation-1.1.yml index 3705ceb4d..eedc18ca6 100644 --- a/.github/workflows/simulation-1.1.yml +++ b/.github/workflows/simulation-1.1.yml @@ -76,7 +76,7 @@ jobs: - name: Run run: | ./script/test cert_suite ./tests/scripts/thread-cert/Cert_*.py ./tests/scripts/thread-cert/test_*.py - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() }} with: name: packet-verification-pcaps @@ -86,10 +86,11 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-packet-verification path: tmp/coverage.info + retention-days: 1 cli-ftd: runs-on: ubuntu-20.04 @@ -121,7 +122,7 @@ jobs: - name: Run run: | ./script/test cert_suite ./tests/scripts/thread-cert/Cert_*.py ./tests/scripts/thread-cert/test_*.py - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() }} with: name: cli-ftd-thread-cert @@ -129,10 +130,11 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-cli-ftd path: tmp/coverage.info + retention-days: 1 cli-mtd: name: cli-mtd MESSAGE_USE_HEAP=${{ matrix.message_use_heap }} @@ -171,7 +173,7 @@ jobs: - name: Run run: | ./script/test cert_suite ./tests/scripts/thread-cert/Cert_*.py ./tests/scripts/thread-cert/test_*.py - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() }} with: name: cli-mtd-thread-cert @@ -179,10 +181,11 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-cli-mtd-${{ matrix.message_use_heap }} path: tmp/coverage.info + retention-days: 1 cli-time-sync: runs-on: ubuntu-20.04 @@ -214,7 +217,7 @@ jobs: - name: Run run: | ./script/test cert_suite ./tests/scripts/thread-cert/Cert_*.py ./tests/scripts/thread-cert/test_*.py - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() }} with: name: cli-time-sync-thread-cert @@ -222,10 +225,11 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-cli-time-sync path: tmp/coverage.info + retention-days: 1 expects: runs-on: ubuntu-20.04 @@ -254,7 +258,7 @@ jobs: CRASHED=$(./script/test check_crash | tail -1) [[ $CRASHED -eq "1" ]] && echo "Crashed!" || echo "Not crashed." echo "CRASHED_CLI=$CRASHED" >> $GITHUB_ENV - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() && env.CRASHED_CLI == '1' }} with: name: core-expect-cli @@ -263,10 +267,11 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-expects path: tmp/coverage.info + retention-days: 1 ot-commissioner: runs-on: ubuntu-22.04 @@ -312,10 +317,11 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-ot-commissioner path: tmp/coverage.info + retention-days: 1 multiple-instance: runs-on: ubuntu-20.04 @@ -343,7 +349,7 @@ jobs: - name: Run run: | ./script/test cert_suite ./tests/scripts/thread-cert/Cert_*.py ./tests/scripts/thread-cert/test_*.py - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() }} with: name: ot_testing @@ -351,10 +357,11 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-multiple-instance path: tmp/coverage.info + retention-days: 1 upload-coverage: needs: @@ -378,9 +385,11 @@ jobs: - name: Bootstrap run: | sudo apt-get --no-install-recommends install -y lcov - - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + - uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1 with: path: coverage/ + pattern: cov-* + merge-multiple: true - name: Combine Coverage run: | script/test combine_coverage @@ -389,17 +398,3 @@ jobs: with: files: final.info fail_ci_if_error: true - - delete-coverage-artifacts: - needs: upload-coverage - runs-on: ubuntu-20.04 - steps: - - name: Harden Runner - uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 - with: - egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - - uses: geekyeggo/delete-artifact@54ab544f12cdb7b71613a16a2b5a37a9ade990af # v2.0.0 - with: - name: cov-* - useGlob: true diff --git a/.github/workflows/simulation-1.2.yml b/.github/workflows/simulation-1.2.yml index d88be6c5c..7e94ff8d4 100644 --- a/.github/workflows/simulation-1.2.yml +++ b/.github/workflows/simulation-1.2.yml @@ -95,12 +95,12 @@ jobs: CRASHED=$(./script/test check_crash | tail -1) [[ $CRASHED -eq "1" ]] && echo "Crashed!" || echo "Not crashed." echo "CRASHED=$CRASHED" >> $GITHUB_ENV - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() }} with: name: thread-1-3-${{ matrix.compiler.c }}-${{ matrix.arch }}-pcaps path: "*.pcap" - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() && env.CRASHED == '1' }} with: name: core-packet-verification-thread-1-3 @@ -109,10 +109,11 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage "${{ matrix.compiler.gcov }}" - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-thread-1-3-${{ matrix.compiler.c }}-${{ matrix.arch }} path: tmp/coverage.info + retention-days: 1 packet-verification-low-power: runs-on: ubuntu-20.04 @@ -165,14 +166,14 @@ jobs: CRASHED=$(./script/test check_crash | tail -1) [[ $CRASHED -eq "1" ]] && echo "Crashed!" || echo "Not crashed." echo "CRASHED=$CRASHED" >> $GITHUB_ENV - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() }} with: name: packet-verification-low-power-pcaps path: | *.pcap *.json - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() && env.CRASHED == '1' }} with: name: core-packet-verification-low-power @@ -181,10 +182,11 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-packet-verification-low-power path: tmp/coverage.info + retention-days: 1 packet-verification-1-1-on-1-3: runs-on: ubuntu-20.04 @@ -218,7 +220,7 @@ jobs: - name: Run run: | ./script/test cert_suite ./tests/scripts/thread-cert/Cert_*.py ./tests/scripts/thread-cert/test_*.py - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() }} with: name: packet-verification-1.1-on-1.3-pcaps @@ -228,10 +230,11 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-packet-verification-1-1-on-1-3 path: tmp/coverage.info + retention-days: 1 expects: runs-on: ubuntu-20.04 @@ -262,7 +265,7 @@ jobs: CRASHED=$(./script/test check_crash | tail -1) [[ $CRASHED -eq "1" ]] && echo "Crashed!" || echo "Not crashed." echo "CRASHED=$CRASHED" >> $GITHUB_ENV - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() && env.CRASHED == '1' }} with: name: core-expect-1-3 @@ -271,10 +274,11 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-expects path: tmp/coverage.info + retention-days: 1 thread-1-3-posix: runs-on: ubuntu-20.04 @@ -320,12 +324,12 @@ jobs: CRASHED=$(./script/test check_crash | tail -1) [[ $CRASHED -eq "1" ]] && echo "Crashed!" || echo "Not crashed." echo "CRASHED=$CRASHED" >> $GITHUB_ENV - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() }} with: name: thread-1-3-posix-pcaps path: "*.pcap" - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: ${{ failure() && env.CRASHED == '1' }} with: name: core-thread-1-3-posix @@ -334,10 +338,11 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-thread-1-3-posix path: tmp/coverage.info + retention-days: 1 upload-coverage: needs: @@ -359,9 +364,11 @@ jobs: - name: Bootstrap run: | sudo apt-get --no-install-recommends install -y lcov - - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + - uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1 with: path: coverage/ + pattern: cov-* + merge-multiple: true - name: Combine Coverage run: | script/test combine_coverage @@ -370,17 +377,3 @@ jobs: with: files: final.info fail_ci_if_error: true - - delete-coverage-artifacts: - needs: upload-coverage - runs-on: ubuntu-20.04 - steps: - - name: Harden Runner - uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 - with: - egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - - uses: geekyeggo/delete-artifact@54ab544f12cdb7b71613a16a2b5a37a9ade990af # v2.0.0 - with: - name: cov-* - useGlob: true diff --git a/.github/workflows/toranj.yml b/.github/workflows/toranj.yml index 16e9e92e8..bb69395da 100644 --- a/.github/workflows/toranj.yml +++ b/.github/workflows/toranj.yml @@ -111,11 +111,12 @@ jobs: if: "matrix.TORANJ_RADIO != 'multi'" run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 if: "matrix.TORANJ_RADIO != 'multi'" with: name: cov-toranj-cli-${{ matrix.TORANJ_RADIO }} path: tmp/coverage.info + retention-days: 1 toranj-unittest: name: toranj-unittest @@ -174,9 +175,11 @@ jobs: - name: Bootstrap run: | sudo apt-get --no-install-recommends install -y lcov - - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + - uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1 with: path: coverage/ + pattern: cov-* + merge-multiple: true - name: Combine Coverage run: | script/test combine_coverage @@ -185,17 +188,3 @@ jobs: with: files: final.info fail_ci_if_error: true - - delete-coverage-artifacts: - needs: upload-coverage - runs-on: ubuntu-20.04 - steps: - - name: Harden Runner - uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 - with: - egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - - uses: geekyeggo/delete-artifact@54ab544f12cdb7b71613a16a2b5a37a9ade990af # v2.0.0 - with: - name: cov-* - useGlob: true diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index 1df2df537..70293674f 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -93,11 +93,11 @@ jobs: - name: Generate Coverage run: | ./script/test generate_coverage gcc - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 with: name: cov-unit-tests path: tmp/coverage.info - + retention-days: 1 upload-coverage: needs: unit-tests @@ -114,9 +114,11 @@ jobs: - name: Bootstrap run: | sudo apt-get --no-install-recommends install -y lcov - - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + - uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1 with: path: coverage/ + pattern: cov-* + merge-multiple: true - name: Combine Coverage run: | script/test combine_coverage @@ -125,17 +127,3 @@ jobs: with: files: final.info fail_ci_if_error: true - - delete-coverage-artifacts: - needs: upload-coverage - runs-on: ubuntu-20.04 - steps: - - name: Harden Runner - uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 - with: - egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - - uses: geekyeggo/delete-artifact@54ab544f12cdb7b71613a16a2b5a37a9ade990af # v2.0.0 - with: - name: cov-* - useGlob: true diff --git a/README.md b/README.md index 0c4a4f58a..ba4fb108e 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ More information about Thread can be found at [threadgroup.org](http://threadgro # Who supports OpenThread? -AmazonARMCascodaEeroEspressifGoogleInfineonMMB NetworksNabu CasaNanoleafNordicNXPQorvoQualcommSamsungSilicon LabsSTMicroelectronicsSynopsysTelink SemiconductorTexas InstrumentsZephyr Project +AmazonAqaraARMCascodaEeroEspressifGoogleInfineonMMB NetworksNabu CasaNanoleafNordicNXPQorvoQualcommSamsungSilicon LabsSTMicroelectronicsSynopsysTelink SemiconductorTexas InstrumentsZephyr Project # Getting started diff --git a/doc/images/ot-contrib-aqara.png b/doc/images/ot-contrib-aqara.png new file mode 100644 index 000000000..7fed68475 Binary files /dev/null and b/doc/images/ot-contrib-aqara.png differ diff --git a/doc/ot_api_doc.h b/doc/ot_api_doc.h index 84e48c800..3863a5a73 100644 --- a/doc/ot_api_doc.h +++ b/doc/ot_api_doc.h @@ -53,6 +53,7 @@ * @defgroup api-net IPv6 Networking * @{ * + * @defgroup api-ble-secure BLE Secure * @defgroup api-dns DNS * @defgroup api-dnssd-server DNS-SD Server * @defgroup api-icmp6 ICMPv6 @@ -168,6 +169,7 @@ * @{ * * @defgroup plat-alarm Alarm + * @defgroup plat-ble BLE * @defgroup plat-crypto Crypto - Platform * @defgroup plat-dns DNS - Platform * @defgroup plat-entropy Entropy diff --git a/doc/ot_config_doc.h b/doc/ot_config_doc.h new file mode 100644 index 000000000..16909d6bd --- /dev/null +++ b/doc/ot_config_doc.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2023, 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 + * @brief + * This file defines the Doxygen group structure for OpenThread documentation. + */ + +/** + * @defgroup config Config Variables + * @brief + * This module lists all OpenThread configuration variables. + * + * @{ + * + * @defgroup config-announce-sender Announce Sender + * @defgroup config-backbone-router Backbone Router Services + * @defgroup config-border-agent Border Agent + * @defgroup config-border-router Border Router + * @defgroup config-border-routing Border Routing Manager + * @defgroup config-channel-manager Channel Manager + * @defgroup config-channel-monitor Channel Monitor + * @defgroup config-child-supervision Child Supervision + * @defgroup config-coap CoAP + * @defgroup config-commissioner Commissioner + * @defgroup config-crypto Crypto Backend Library + * @defgroup config-dataset-updater Dataset Updater + * @defgroup config-dhcpv6-client DHCPv6 Client + * @defgroup config-dhcpv6-server DHCPv6 Server + * @defgroup config-diag DIAG Service + * @defgroup config-dns-client DNS Client + * @defgroup config-dns-dso DNS Stateful Operations + * @defgroup config-dnssd-server DNS-SD Server + * @defgroup config-history-tracker History Tracker + * @defgroup config-ip6 IP6 Service + * @defgroup config-joiner Joiner + * @defgroup config-link-metrics-manager Link Metrics Manager + * @defgroup config-link-quality Link Quality + * @defgroup config-link-raw Link Raw Service + * @defgroup config-logging Logging Service + * @defgroup config-mac MAC + * @defgroup config-mesh-diag Mesh Diagnostic + * @defgroup config-mesh-forwarder Mesh Forwarder + * @defgroup config-misc Miscellaneous Constants + * @defgroup config-mle MLE Service + * @defgroup config-nat64 NAT64 + * @defgroup config-netdata-publisher Network Data Publisher + * @defgroup config-network-diagnostic Network Diagnostics + * @defgroup config-parent-search Parent Search + * @defgroup config-ping-sender Ping Sender + * @defgroup config-platform Platform Specific Services + * @defgroup config-power-calibration Power Calibration + * @defgroup config-radio-link Radio Links + * @defgroup config-secure-transport Secure Transport + * @defgroup config-sntp-client SNTP Client + * @defgroup config-srp-client SRP Client + * @defgroup config-srp-server SRP Server + * @defgroup config-time-sync Time Sync Service + * @defgroup config-tmf Thread Management Framework Service + * + * @} + * + */ diff --git a/etc/cmake/options.cmake b/etc/cmake/options.cmake index 45e079dc5..ecb2d52d3 100644 --- a/etc/cmake/options.cmake +++ b/etc/cmake/options.cmake @@ -230,6 +230,7 @@ ot_option(OT_PING_SENDER OPENTHREAD_CONFIG_PING_SENDER_ENABLE "ping sender" ${OT ot_option(OT_PLATFORM_BOOTLOADER_MODE OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE "platform bootloader mode") ot_option(OT_PLATFORM_KEY_REF OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE "platform key reference secure storage") ot_option(OT_PLATFORM_NETIF OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE "platform netif") +ot_option(OT_PLATFORM_POWER_CALIBRATION OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE "power calibration") ot_option(OT_PLATFORM_UDP OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE "platform UDP") ot_option(OT_REFERENCE_DEVICE OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE "test harness reference device") ot_option(OT_SERVICE OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE "Network Data service") @@ -322,6 +323,7 @@ ot_multi_option(OT_POWER_SUPPLY OT_POWER_SUPPLY_VALUES OPENTHREAD_CONFIG_DEVICE_ ot_int_option(OT_MLE_MAX_CHILDREN OPENTHREAD_CONFIG_MLE_MAX_CHILDREN "set maximum number of children") ot_int_option(OT_RCP_RESTORATION_MAX_COUNT OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT "set max RCP restoration count") +ot_int_option(OT_RCP_TX_WAIT_TIME_SECS OPENTHREAD_SPINEL_CONFIG_RCP_TX_WAIT_TIME_SECS "set RCP TX wait TIME in seconds") # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/platforms/simulation/trel.c b/examples/platforms/simulation/trel.c index 3413c9351..cfc34ac9b 100644 --- a/examples/platforms/simulation/trel.c +++ b/examples/platforms/simulation/trel.c @@ -73,10 +73,11 @@ static uint16_t sPortOffset = 0; static bool sEnabled = false; static uint16_t sUdpPort; -static bool sServiceRegistered = false; -static uint16_t sServicePort; -static uint8_t sServiceTxtLength; -static char sServiceTxtData[TREL_MAX_SERVICE_TXT_DATA_LEN]; +static bool sServiceRegistered = false; +static uint16_t sServicePort; +static uint8_t sServiceTxtLength; +static char sServiceTxtData[TREL_MAX_SERVICE_TXT_DATA_LEN]; +static otPlatTrelCounters sCounters; #if DEBUG_LOG static void dumpBuffer(const void *aBuffer, uint16_t aLength) @@ -388,6 +389,8 @@ void otPlatTrelSend(otInstance *aInstance, #if DEBUG_LOG fprintf(stderr, "\r\n[trel-sim] otPlatTrelSend(len:%u, port:%u)\r\n", aUdpPayloadLen, aDestSockAddr->mPort); #endif + ++sCounters.mTxPackets; + sCounters.mTxBytes += aUdpPayloadLen; } //--------------------------------------------------------------------------------------------------------------------- @@ -473,6 +476,18 @@ void platformTrelProcess(otInstance *aInstance, const fd_set *aReadFdSet, const } } +const otPlatTrelCounters *otPlatTrelGetCounters(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return &sCounters; +} + +void otPlatTrelResetCounters(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + memset(&sCounters, 0, sizeof(sCounters)); +} + //--------------------------------------------------------------------------------------------------------------------- // This is added for RCP build to be built ok diff --git a/include/openthread/border_routing.h b/include/openthread/border_routing.h index 5236f0d9d..afd2d7e5f 100644 --- a/include/openthread/border_routing.h +++ b/include/openthread/border_routing.h @@ -124,7 +124,7 @@ typedef struct otBorderRoutingPrefixTableEntry */ typedef struct otPdProcessedRaInfo { - uint32_t mNumPlatformRaReceived; ///< The number of platform generated RA handled by ProcessPlatfromGeneratedRa. + uint32_t mNumPlatformRaReceived; ///< The number of platform generated RA handled by ProcessPlatformGeneratedRa. uint32_t mNumPlatformPioProcessed; ///< The number of PIO processed for adding OMR prefixes. uint32_t mLastPlatformRaMsec; ///< The timestamp of last processed RA message. } otPdProcessedRaInfo; diff --git a/include/openthread/coap.h b/include/openthread/coap.h index 4b7149adb..d5d02060b 100644 --- a/include/openthread/coap.h +++ b/include/openthread/coap.h @@ -357,7 +357,7 @@ typedef void (*otCoapResponseHandler)(void *aContext, typedef void (*otCoapRequestHandler)(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); /** - * Pointer is called when a CoAP message with an block-wise transfer option is received. + * Pointer is called when a CoAP message with a block-wise transfer option is received. * * Is available when OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE configuration * is enabled. diff --git a/include/openthread/dns_client.h b/include/openthread/dns_client.h index 0fd345804..49dcdfdb3 100644 --- a/include/openthread/dns_client.h +++ b/include/openthread/dns_client.h @@ -408,7 +408,7 @@ otError otDnsBrowseResponseGetServiceName(const otDnsBrowseResponse *aResponse, * MUST only be used from `otDnsBrowseCallback`. * * The response may include multiple service instance records. @p aIndex can be used to iterate through the list. Index - * zero gives the the first record. When we reach end of the list, `OT_ERROR_NOT_FOUND` is returned. + * zero gives the first record. When we reach end of the list, `OT_ERROR_NOT_FOUND` is returned. * * Note that this function gets the service instance label and not the full service instance name which is of the form * `..`. diff --git a/include/openthread/dnssd_server.h b/include/openthread/dnssd_server.h index 98f83d694..c008e3266 100644 --- a/include/openthread/dnssd_server.h +++ b/include/openthread/dnssd_server.h @@ -147,20 +147,33 @@ typedef enum OT_DNSSD_QUERY_TYPE_RESOLVE_HOST = 3, ///< Service type resolve hostname. } otDnssdQueryType; +/** + * Represents the count of queries, responses, failures handled by upstream DNS server. + * + * Requires `OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE`. + */ +typedef struct otUpstreamDnsCounters +{ + uint32_t mQueries; ///< The number of queries forwarded. + uint32_t mResponses; ///< The number of responses forwarded. + uint32_t mFailures; ///< The number of upstream DNS failures. +} otUpstreamDnsCounters; + /** * 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 + 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 resolved by the local SRP server. + otUpstreamDnsCounters mUpstreamDnsCounters; ///< The number of queries, responses, + ///< failures handled by upstream DNS server. } otDnssdCounters; /** diff --git a/include/openthread/history_tracker.h b/include/openthread/history_tracker.h index 08dc8d9c2..72a0c4a2d 100644 --- a/include/openthread/history_tracker.h +++ b/include/openthread/history_tracker.h @@ -426,8 +426,8 @@ const otHistoryTrackerExternalRouteInfo *otHistoryTrackerIterateExternalRouteHis /** * Converts a given entry age to a human-readable string. * - * The entry age string follows the format "::." for hours, minutes, seconds and millisecond (if - * shorter than one day) or "
days ::." (if longer than one day). + * The entry age string follows the format `hours:minutes:seconds:milliseconds` (if + * shorter than one day) or `days:hours:minutes:seconds`(if longer than one day). * * If the resulting string does not fit in @p aBuffer (within its @p aSize characters), the string will be truncated * but the outputted string is always null-terminated. diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 3a668cffe..1a97f96e5 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (383) +#define OPENTHREAD_API_VERSION (389) /** * @addtogroup api-instance diff --git a/include/openthread/ip6.h b/include/openthread/ip6.h index 8301ff93d..cb4d12491 100644 --- a/include/openthread/ip6.h +++ b/include/openthread/ip6.h @@ -52,12 +52,13 @@ extern "C" { * */ -#define OT_IP6_PREFIX_SIZE 8 ///< Size of an IPv6 prefix (bytes) -#define OT_IP6_PREFIX_BITSIZE (OT_IP6_PREFIX_SIZE * 8) ///< Size of an IPv6 prefix (bits) -#define OT_IP6_IID_SIZE 8 ///< Size of an IPv6 Interface Identifier (bytes) -#define OT_IP6_ADDRESS_SIZE 16 ///< Size of an IPv6 address (bytes) -#define OT_IP6_HEADER_SIZE 40 ///< Size of an IPv6 header (bytes) -#define OT_IP6_HEADER_PROTO_OFFSET 6 ///< Offset of the proto field in the IPv6 header (bytes) +#define OT_IP6_PREFIX_SIZE 8 ///< Size of an IPv6 prefix (bytes) +#define OT_IP6_PREFIX_BITSIZE (OT_IP6_PREFIX_SIZE * 8) ///< Size of an IPv6 prefix (bits) +#define OT_IP6_IID_SIZE 8 ///< Size of an IPv6 Interface Identifier (bytes) +#define OT_IP6_ADDRESS_SIZE 16 ///< Size of an IPv6 address (bytes) +#define OT_IP6_ADDRESS_BITSIZE (OT_IP6_ADDRESS_SIZE * 8) ///< Size of an IPv6 address (bits) +#define OT_IP6_HEADER_SIZE 40 ///< Size of an IPv6 header (bytes) +#define OT_IP6_HEADER_PROTO_OFFSET 6 ///< Offset of the proto field in the IPv6 header (bytes) /** * @struct otIp6InterfaceIdentifier diff --git a/include/openthread/platform/trel.h b/include/openthread/platform/trel.h index b372fded5..f9e068f77 100644 --- a/include/openthread/platform/trel.h +++ b/include/openthread/platform/trel.h @@ -197,6 +197,35 @@ void otPlatTrelSend(otInstance *aInstance, */ extern void otPlatTrelHandleReceived(otInstance *aInstance, uint8_t *aBuffer, uint16_t aLength); +/** + * Represents a group of TREL related counters in the platform layer. + * + */ +typedef struct otPlatTrelCounters +{ + uint64_t mTxPackets; ///< Number of packets successfully transmitted through TREL. + uint64_t mTxBytes; ///< Sum of size of packets successfully transmitted through TREL. + uint64_t mTxFailure; ///< Number of packet transmission failures through TREL. + uint64_t mRxPackets; ///< Number of packets received through TREL. + uint64_t mRxBytes; ///< Sum of size of packets received through TREL. +} otPlatTrelCounters; + +/** + * Gets the pointer to the TREL counters in the platform layer. + * + * @param[in] aInstance The OpenThread instance structure. + * + */ +const otPlatTrelCounters *otPlatTrelGetCounters(otInstance *aInstance); + +/** + * Resets the TREL counters in the platform layer. + * + * @param[in] aInstance The OpenThread instance structure. + * + */ +void otPlatTrelResetCounters(otInstance *aInstance); + /** * @} * diff --git a/include/openthread/tcp.h b/include/openthread/tcp.h index caa0d4efd..649a4b472 100644 --- a/include/openthread/tcp.h +++ b/include/openthread/tcp.h @@ -231,7 +231,7 @@ typedef void (*otTcpDisconnected)(otTcpEndpoint *aEndpoint, otTcpDisconnectedRea /** * Represents a TCP endpoint. * - * An TCP endpoint acts an endpoint of TCP connection. It can be used to + * A TCP endpoint acts an endpoint of TCP connection. It can be used to * initiate TCP connections, and, once a TCP connection is established, send * data to and receive data from the connection peer. * diff --git a/include/openthread/thread.h b/include/openthread/thread.h index cb0d6bda2..b077001e4 100644 --- a/include/openthread/thread.h +++ b/include/openthread/thread.h @@ -238,7 +238,7 @@ typedef void (*otDetachGracefullyCallback)(void *aContext); * @param[in] aEnabled TRUE if Thread is enabled, FALSE otherwise. * * @retval OT_ERROR_NONE Successfully started Thread protocol operation. - * @retval OT_ERROR_INVALID_STATE The network interface was not not up. + * @retval OT_ERROR_INVALID_STATE The network interface was not up. * */ otError otThreadSetEnabled(otInstance *aInstance, bool aEnabled); diff --git a/include/openthread/trel.h b/include/openthread/trel.h index 2358ea26a..e9a0bf00a 100644 --- a/include/openthread/trel.h +++ b/include/openthread/trel.h @@ -39,6 +39,7 @@ #include #include #include +#include "openthread/platform/trel.h" #ifdef __cplusplus extern "C" { @@ -123,6 +124,16 @@ void otTrelInitPeerIterator(otInstance *aInstance, otTrelPeerIterator *aIterator */ const otTrelPeer *otTrelGetNextPeer(otInstance *aInstance, otTrelPeerIterator *aIterator); +/** + * Returns the number of TREL peers. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @returns The number of TREL peers. + * + */ +uint16_t otTrelGetNumberOfPeers(otInstance *aInstance); + /** * Sets the filter mode (enables/disables filtering). * @@ -149,6 +160,30 @@ void otTrelSetFilterEnabled(otInstance *aInstance, bool aEnable); */ bool otTrelIsFilterEnabled(otInstance *aInstance); +/** + * Represents a group of TREL related counters. + * + */ +typedef otPlatTrelCounters otTrelCounters; + +/** + * Gets the TREL counters. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @returns A pointer to the TREL counters. + * + */ +const otTrelCounters *otTrelGetCounters(otInstance *aInstance); + +/** + * Resets the TREL counters. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + */ +void otTrelResetCounters(otInstance *aInstance); + /** * @} * diff --git a/script/check-scan-build b/script/check-scan-build index ef723faad..7e6ad30ff 100755 --- a/script/check-scan-build +++ b/script/check-scan-build @@ -69,6 +69,7 @@ OT_BUILD_OPTIONS=( "-DOT_PING_SENDER=ON" "-DOT_PLATFORM=external" "-DOT_RCP_RESTORATION_MAX_COUNT=2" + "-DOT_RCP_TX_WAIT_TIME_SECS=5" "-DOT_REFERENCE_DEVICE=ON" "-DOT_SERVICE=ON" "-DOT_SLAAC=ON" diff --git a/script/cmake-build b/script/cmake-build index e457bfcd1..5ed2e4e4b 100755 --- a/script/cmake-build +++ b/script/cmake-build @@ -102,6 +102,7 @@ OT_POSIX_SIM_COMMON_OPTIONS=( "-DOT_NETDIAG_CLIENT=ON" "-DOT_PING_SENDER=ON" "-DOT_RCP_RESTORATION_MAX_COUNT=2" + "-DOT_RCP_TX_WAIT_TIME_SECS=5" "-DOT_REFERENCE_DEVICE=ON" "-DOT_SERVICE=ON" "-DOT_SNTP_CLIENT=ON" diff --git a/src/cli/BUILD.gn b/src/cli/BUILD.gn index b7ef7312a..318a4d0b9 100644 --- a/src/cli/BUILD.gn +++ b/src/cli/BUILD.gn @@ -57,6 +57,8 @@ openthread_cli_sources = [ "cli_network_data.hpp", "cli_output.cpp", "cli_output.hpp", + "cli_ping.cpp", + "cli_ping.hpp", "cli_srp_client.cpp", "cli_srp_client.hpp", "cli_srp_server.cpp", diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index 022de520b..f36439f26 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -46,6 +46,7 @@ set(COMMON_SOURCES cli_mac_filter.cpp cli_network_data.cpp cli_output.cpp + cli_ping.cpp cli_srp_client.cpp cli_srp_server.cpp cli_tcat.cpp diff --git a/src/cli/README.md b/src/cli/README.md index 20df53e0d..262b9f567 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -40,6 +40,7 @@ Done - [counters](#counters) - [csl](#csl) - [dataset](README_DATASET.md) +- [debug](#debug) - [delaytimermin](#delaytimermin) - [detach](#detach) - [deviceprops](#deviceprops) @@ -1049,6 +1050,52 @@ Set time sync parameters Done ``` +### debug + +Executes a series of CLI commands to gather information about the device and thread network. This is intended for debugging. + +The output will display each executed CLI command preceded by "\$", followed by the corresponding command's generated output. + +The generated output encompasses the following information: + +- Version +- Current state +- RLOC16, extended MAC address +- Unicast and multicast IPv6 address list +- Channel +- PAN ID and extended PAN ID +- Network Data +- Partition ID +- Leader Data + +If the device is operating as FTD: + +- Child and neighbor table +- Router table and next hop Info +- Address cache table +- Registered MTD child IPv6 address +- Device properties + +If the device supports and acts as an SRP client: + +- SRP client state +- SRP client services and host info + +If the device supports and acts as an SRP sever: + +- SRP server state and address mode +- SRP server registered hosts and services + +If the device supports TREL: + +- TREL status and peer table + +If the device supports and acts as a border router: + +- BR state +- BR prefixes (OMR, on-link, NAT64) +- Discovered prefix table + ### delaytimermin Get the minimal delay timer (in seconds). diff --git a/src/cli/README_BR.md b/src/cli/README_BR.md index dcc174cfa..189de8a6f 100644 --- a/src/cli/README_BR.md +++ b/src/cli/README_BR.md @@ -12,6 +12,7 @@ Usage : `br [command] ...` - [nat64prefix](#nat64prefix) - [omrprefix](#omrprefix) - [onlinkprefix](#onlinkprefix) +- [pd](#pd) - [prefixtable](#prefixtable) - [rioprf](#rioprf) - [routeprf](#routeprf) @@ -33,6 +34,7 @@ disable enable omrprefix onlinkprefix +pd prefixtable rioprf routeprf @@ -176,6 +178,36 @@ fd14:1078:b3d5:b0b0:0:0::/96 Done ``` +### pd + +Usage: `br pd [enable|disable]` + +Enable/Disable the DHCPv6 PD. + +```bash +> br pd enable +Done + +> br pd disable +Done +``` + +Usage: `br pd state` + +Get the state of DHCPv6 PD. + +`OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE` is required. + +- `disabled`: DHCPv6 PD is disabled on the border router. +- `stopped`: DHCPv6 PD in enabled but won't try to request and publish a prefix. +- `running`: DHCPv6 PD is enabled and will try to request and publish a prefix. + +```bash +> br pd state +running +Done +``` + ### prefixtable Usage: `br prefixtable` diff --git a/src/cli/README_HISTORY.md b/src/cli/README_HISTORY.md index 3fa681a27..21f2dc5e3 100644 --- a/src/cli/README_HISTORY.md +++ b/src/cli/README_HISTORY.md @@ -345,7 +345,7 @@ Usage `history router [list] []` Print the route table history. Each item provides: -- Event (`Added`, `Removed`, `NextHopChnaged`, `CostChanged`) +- Event (`Added`, `Removed`, `NextHopChanged`, `CostChanged`) - Router ID and RLOC16 of router - Next Hop (Router ID and RLOC16) - `none` if no next hop. - Path cost (old `->` new) - `inf` to indicate infinite path cost. diff --git a/src/cli/README_SRP.md b/src/cli/README_SRP.md index ce2139fb7..0ad7dd489 100644 --- a/src/cli/README_SRP.md +++ b/src/cli/README_SRP.md @@ -98,7 +98,7 @@ Routes: Services: 44970 5d c002 s 8400 Done -srp client start fded:5114:8263:1fe1:68bc:ec03:c1ad:9325 49154 +> srp client start fded:5114:8263:1fe1:68bc:ec03:c1ad:9325 49154 Done ``` diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index c1443aec7..eecfeecf2 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -101,6 +101,7 @@ Interpreter::Interpreter(Instance *aInstance, otCliOutputCallback aCallback, voi : OutputImplementer(aCallback, aContext) , Output(aInstance, *this) , mCommandIsPending(false) + , mInternalDebugCommand(false) , mTimer(*aInstance, HandleTimer, this) #if OPENTHREAD_FTD || OPENTHREAD_MTD #if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE @@ -151,6 +152,9 @@ Interpreter::Interpreter(Instance *aInstance, otCliOutputCallback aCallback, voi #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE , mTcat(aInstance, *this) #endif +#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE + , mPing(aInstance, *this) +#endif #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE , mLocateInProgress(false) #endif @@ -166,6 +170,16 @@ Interpreter::Interpreter(Instance *aInstance, otCliOutputCallback aCallback, voi void Interpreter::OutputResult(otError aError) { + if (mInternalDebugCommand) + { + if (aError != OT_ERROR_NONE) + { + OutputLine("Error %u: %s", aError, otThreadErrorToString(aError)); + } + + ExitNow(); + } + OT_ASSERT(mCommandIsPending); VerifyOrExit(aError != OT_ERROR_PENDING); @@ -314,24 +328,30 @@ void Interpreter::ProcessLine(char *aBuf) OT_ASSERT(aBuf != nullptr); - // Ignore the command if another command is pending. - VerifyOrExit(!mCommandIsPending, args[0].Clear()); - mCommandIsPending = true; + if (!mInternalDebugCommand) + { + // Ignore the command if another command is pending. + VerifyOrExit(!mCommandIsPending, args[0].Clear()); + mCommandIsPending = true; - VerifyOrExit(StringLength(aBuf, kMaxLineLength) <= kMaxLineLength - 1, error = OT_ERROR_PARSE); + VerifyOrExit(StringLength(aBuf, kMaxLineLength) <= kMaxLineLength - 1, error = OT_ERROR_PARSE); + } SuccessOrExit(error = Utils::CmdLineParser::ParseCmd(aBuf, args, kMaxArgs)); VerifyOrExit(!args[0].IsEmpty(), mCommandIsPending = false); - LogInput(args); + if (!mInternalDebugCommand) + { + LogInput(args); #if OPENTHREAD_CONFIG_DIAG_ENABLE - if (otDiagIsEnabled(GetInstancePtr()) && (args[0] != "diag") && (args[0] != "factoryreset")) - { - OutputLine("under diagnostics mode, execute 'diag stop' before running any other commands."); - ExitNow(error = OT_ERROR_INVALID_STATE); - } + if (otDiagIsEnabled(GetInstancePtr()) && (args[0] != "diag") && (args[0] != "factoryreset")) + { + OutputLine("under diagnostics mode, execute 'diag stop' before running any other commands."); + ExitNow(error = OT_ERROR_INVALID_STATE); + } #endif + } error = ProcessCommand(args); @@ -430,57 +450,6 @@ otError Interpreter::ParseJoinerDiscerner(Arg &aArg, otJoinerDiscerner &aDiscern return error; } -#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE - -otError Interpreter::ParsePingInterval(const Arg &aArg, uint32_t &aInterval) -{ - otError error = OT_ERROR_NONE; - const char *string = aArg.GetCString(); - const uint32_t msFactor = 1000; - uint32_t factor = msFactor; - - aInterval = 0; - - while (*string) - { - if ('0' <= *string && *string <= '9') - { - // In the case of seconds, change the base of already calculated value. - if (factor == msFactor) - { - aInterval *= 10; - } - - aInterval += static_cast(*string - '0') * factor; - - // In the case of milliseconds, change the multiplier factor. - if (factor != msFactor) - { - factor /= 10; - } - } - else if (*string == '.') - { - // Accept only one dot character. - VerifyOrExit(factor == msFactor, error = OT_ERROR_INVALID_ARGS); - - // Start analyzing hundreds of milliseconds. - factor /= 10; - } - else - { - ExitNow(error = OT_ERROR_INVALID_ARGS); - } - - string++; - } - -exit: - return error; -} - -#endif // OPENTHREAD_CONFIG_PING_SENDER_ENABLE - otError Interpreter::ParsePreference(const Arg &aArg, otRoutePreference &aPreference) { otError error = OT_ERROR_NONE; @@ -4132,7 +4101,7 @@ template <> otError Interpreter::Process(Arg aArgs[]) * @par api_copy * #otThreadSetLinkMode * @cparam mode [@ca{rdn}] - * - `-`: -: no flags set (rx-off-when-idle, minimal Thread device, stable network data) + * - `-`: no flags set (rx-off-when-idle, minimal Thread device, stable network data) * - `r`: rx-on-when-idle * - `d`: Full Thread Device * - `n`: Full Network Data @@ -5533,55 +5502,6 @@ template <> otError Interpreter::Process(Arg *aArgs) #endif #if OPENTHREAD_CONFIG_PING_SENDER_ENABLE - -void Interpreter::HandlePingReply(const otPingSenderReply *aReply, void *aContext) -{ - static_cast(aContext)->HandlePingReply(aReply); -} - -void Interpreter::HandlePingReply(const otPingSenderReply *aReply) -{ - OutputFormat("%u bytes from ", static_cast(aReply->mSize + sizeof(otIcmp6Header))); - OutputIp6Address(aReply->mSenderAddress); - OutputLine(": icmp_seq=%u hlim=%u time=%ums", aReply->mSequenceNumber, aReply->mHopLimit, aReply->mRoundTripTime); -} - -void Interpreter::HandlePingStatistics(const otPingSenderStatistics *aStatistics, void *aContext) -{ - static_cast(aContext)->HandlePingStatistics(aStatistics); -} - -void Interpreter::HandlePingStatistics(const otPingSenderStatistics *aStatistics) -{ - OutputFormat("%u packets transmitted, %u packets received.", aStatistics->mSentCount, aStatistics->mReceivedCount); - - if ((aStatistics->mSentCount != 0) && !aStatistics->mIsMulticast && - aStatistics->mReceivedCount <= aStatistics->mSentCount) - { - uint32_t packetLossRate = - 1000 * (aStatistics->mSentCount - aStatistics->mReceivedCount) / aStatistics->mSentCount; - - OutputFormat(" Packet loss = %lu.%u%%.", ToUlong(packetLossRate / 10), - static_cast(packetLossRate % 10)); - } - - if (aStatistics->mReceivedCount != 0) - { - uint32_t avgRoundTripTime = 1000 * aStatistics->mTotalRoundTripTime / aStatistics->mReceivedCount; - - OutputFormat(" Round-trip min/avg/max = %u/%u.%u/%u ms.", aStatistics->mMinRoundTripTime, - static_cast(avgRoundTripTime / 1000), static_cast(avgRoundTripTime % 1000), - aStatistics->mMaxRoundTripTime); - } - - OutputNewLine(); - - if (!mPingIsAsync) - { - OutputResult(OT_ERROR_NONE); - } -} - /** * @cli ping * @code @@ -5617,108 +5537,7 @@ void Interpreter::HandlePingStatistics(const otPingSenderStatistics *aStatistics * Note: The command will return InvalidState when the preferred NAT64 prefix is unavailable. * @sa otPingSenderPing */ -template <> otError Interpreter::Process(Arg aArgs[]) -{ - otError error = OT_ERROR_NONE; - otPingSenderConfig config; - bool async = false; - bool nat64SynthesizedAddress; - - /** - * @cli ping stop - * @code - * ping stop - * Done - * @endcode - * @par - * Stop sending ICMPv6 Echo Requests. - * @sa otPingSenderStop - */ - if (aArgs[0] == "stop") - { - otPingSenderStop(GetInstancePtr()); - ExitNow(); - } - else if (aArgs[0] == "async") - { - async = true; - aArgs++; - } - - memset(&config, 0, sizeof(config)); - - if (aArgs[0] == "-I") - { - SuccessOrExit(error = aArgs[1].ParseAsIp6Address(config.mSource)); - -#if !OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE - VerifyOrExit(otIp6HasUnicastAddress(GetInstancePtr(), &config.mSource), error = OT_ERROR_INVALID_ARGS); -#endif - aArgs += 2; - } - - if (aArgs[0] == "-m") - { - config.mMulticastLoop = true; - aArgs++; - } - - SuccessOrExit(error = ParseToIp6Address(GetInstancePtr(), aArgs[0], config.mDestination, nat64SynthesizedAddress)); - if (nat64SynthesizedAddress) - { - OutputFormat("Pinging synthesized IPv6 address: "); - OutputIp6AddressLine(config.mDestination); - } - - if (!aArgs[1].IsEmpty()) - { - SuccessOrExit(error = aArgs[1].ParseAsUint16(config.mSize)); - } - - if (!aArgs[2].IsEmpty()) - { - SuccessOrExit(error = aArgs[2].ParseAsUint16(config.mCount)); - } - - if (!aArgs[3].IsEmpty()) - { - SuccessOrExit(error = ParsePingInterval(aArgs[3], config.mInterval)); - } - - if (!aArgs[4].IsEmpty()) - { - SuccessOrExit(error = aArgs[4].ParseAsUint8(config.mHopLimit)); - config.mAllowZeroHopLimit = (config.mHopLimit == 0); - } - - if (!aArgs[5].IsEmpty()) - { - uint32_t timeout; - - SuccessOrExit(error = ParsePingInterval(aArgs[5], timeout)); - VerifyOrExit(timeout <= NumericLimits::kMax, error = OT_ERROR_INVALID_ARGS); - config.mTimeout = static_cast(timeout); - } - - VerifyOrExit(aArgs[6].IsEmpty(), error = OT_ERROR_INVALID_ARGS); - - config.mReplyCallback = Interpreter::HandlePingReply; - config.mStatisticsCallback = Interpreter::HandlePingStatistics; - config.mCallbackContext = this; - - SuccessOrExit(error = otPingSenderPing(GetInstancePtr(), &config)); - - mPingIsAsync = async; - - if (!async) - { - error = OT_ERROR_PENDING; - } - -exit: - return error; -} - +template <> otError Interpreter::Process(Arg aArgs[]) { return mPing.Process(aArgs); } #endif // OPENTHREAD_CONFIG_PING_SENDER_ENABLE /** @@ -7243,6 +7062,124 @@ template <> otError Interpreter::Process(Arg aArgs[]) return error; } +/** + * @cli debug + * @par + * Executes a series of CLI commands to gather information about the device and thread network. This is intended for + * debugging. + * The output will display each executed CLI command preceded by `$`, followed by the corresponding command's + * generated output. + * The generated output encompasses the following information: + * - Version + * - Current state + * - RLOC16, extended MAC address + * - Unicast and multicast IPv6 address list + * - Channel + * - PAN ID and extended PAN ID + * - Network Data + * - Partition ID + * - Leader Data + * @par + * If the device is operating as FTD: + * - Child and neighbor table + * - Router table and next hop info + * - Address cache table + * - Registered MTD child IPv6 address + * - Device properties + * @par + * If the device supports and acts as an SRP client: + * - SRP client state + * - SRP client services and host info + * @par + * If the device supports and acts as an SRP sever: + * - SRP server state and address mode + * - SRP server registered hosts and services + * @par + * If the device supports TREL: + * - TREL status and peer table + * @par + * If the device supports and acts as a border router: + * - BR state + * - BR prefixes (OMR, on-link, NAT64) + * - Discovered prefix table + */ +template <> otError Interpreter::Process(Arg aArgs[]) +{ + static constexpr uint16_t kMaxDebugCommandSize = 30; + + static const char *const kDebugCommands[] = { + "version", + "state", + "rloc16", + "extaddr", + "ipaddrs", + "ipmaddrs", + "channel", + "panid", + "extpanid", + "netdata show", + "netdata show -x", + "partitionid", + "leaderdata", +#if OPENTHREAD_FTD + "child table", + "childip", + "neighbor table", + "router table", + "nexthop", + "eidcache", +#if OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE + "deviceprops", +#endif +#endif // OPENTHREAD_FTD +#if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE + "srp client state", + "srp client host", + "srp client service", + "srp client server", +#endif +#if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE + "srp server state", + "srp server addrmode", + "srp server host", + "srp server service", +#endif +#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE + "trel", + "trel peers", +#endif +#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE + "br state", + "br omrprefix", + "br onlinkprefix", + "br prefixtable", +#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE + "br nat64prefix", +#endif +#endif + "bufferinfo", + }; + + char commandString[kMaxDebugCommandSize]; + + OT_UNUSED_VARIABLE(aArgs); + + mInternalDebugCommand = true; + + for (const char *debugCommand : kDebugCommands) + { + strncpy(commandString, debugCommand, sizeof(commandString) - 1); + commandString[sizeof(commandString) - 1] = '\0'; + + OutputLine("$ %s", commandString); + ProcessLine(commandString); + } + + mInternalDebugCommand = false; + + return OT_ERROR_NONE; +} + #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE template <> otError Interpreter::Process(Arg aArgs[]) { return mTcat.Process(aArgs); } #endif @@ -7665,6 +7602,41 @@ template <> otError Interpreter::Process(Arg aArgs[]) } } } + /** + * @cli trel counters + * @code + * trel counters + * Inbound: Packets 32 Bytes 4000 + * Outbound: Packets 4 Bytes 320 Failures 1 + * Done + * @endcode + * @par api_copy + * #otTrelGetCounters + */ + else if (aArgs[0] == "counters") + { + if (aArgs[1].IsEmpty()) + { + OutputTrelCounters(*otTrelGetCounters(GetInstancePtr())); + } + /** + * @cli trel counters reset + * @code + * trel counters reset + * Done + * @endcode + * @par api_copy + * #otTrelResetCounters + */ + else if ((aArgs[1] == "reset") && aArgs[2].IsEmpty()) + { + otTrelResetCounters(GetInstancePtr()); + } + else + { + error = OT_ERROR_INVALID_ARGS; + } + } else { error = OT_ERROR_INVALID_ARGS; @@ -7673,6 +7645,19 @@ template <> otError Interpreter::Process(Arg aArgs[]) exit: return error; } + +void Interpreter::OutputTrelCounters(const otTrelCounters &aCounters) +{ + Uint64StringBuffer u64StringBuffer; + + OutputFormat("Inbound: Packets %s ", Uint64ToString(aCounters.mRxPackets, u64StringBuffer)); + OutputLine("Bytes %s", Uint64ToString(aCounters.mRxBytes, u64StringBuffer)); + + OutputFormat("Outbound: Packets %s ", Uint64ToString(aCounters.mTxPackets, u64StringBuffer)); + OutputFormat("Bytes %s ", Uint64ToString(aCounters.mTxBytes, u64StringBuffer)); + OutputLine("Failures %s", Uint64ToString(aCounters.mTxFailure, u64StringBuffer)); +} + #endif template <> otError Interpreter::Process(Arg aArgs[]) @@ -8345,6 +8330,7 @@ otError Interpreter::ProcessCommand(Arg aArgs[]) CmdEntry("csl"), #endif CmdEntry("dataset"), + CmdEntry("debug"), #if OPENTHREAD_FTD CmdEntry("delaytimermin"), #endif diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index f95759e71..94798f22a 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -69,6 +69,7 @@ #include "cli/cli_mac_filter.hpp" #include "cli/cli_network_data.hpp" #include "cli/cli_output.hpp" +#include "cli/cli_ping.hpp" #include "cli/cli_srp_client.hpp" #include "cli/cli_srp_server.hpp" #include "cli/cli_tcat.hpp" @@ -117,6 +118,7 @@ class Interpreter : public OutputImplementer, public Output friend class Joiner; friend class LinkMetrics; friend class NetworkData; + friend class PingSender; friend class SrpClient; friend class SrpServer; #endif @@ -382,9 +384,6 @@ class Interpreter : public OutputImplementer, public Output void OutputPrompt(void); void OutputResult(otError aError); -#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE - otError ParsePingInterval(const Arg &aArg, uint32_t &aInterval); -#endif static otError ParseJoinerDiscerner(Arg &aArg, otJoinerDiscerner &aDiscerner); #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE static otError ParsePrefix(Arg aArgs[], otBorderRouterConfig &aConfig); @@ -458,10 +457,6 @@ class Interpreter : public OutputImplementer, public Output void OutputMultiRadioInfo(const otMultiRadioNeighborInfo &aMultiRadioInfo); #endif -#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE - static void HandlePingReply(const otPingSenderReply *aReply, void *aContext); - static void HandlePingStatistics(const otPingSenderStatistics *aStatistics, void *aContext); -#endif static void HandleActiveScanResult(otActiveScanResult *aResult, void *aContext); static void HandleEnergyScanResult(otEnergyScanResult *aResult, void *aContext); static void HandleLinkPcapReceive(const otRadioFrame *aFrame, bool aIsTx, void *aContext); @@ -483,6 +478,9 @@ class Interpreter : public OutputImplementer, public Output void OutputChildTableEntry(uint8_t aIndentSize, const otNetworkDiagChildEntry &aChildEntry); #endif +#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE + void OutputTrelCounters(const otTrelCounters &aCounters); +#endif #if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE void OutputNat64Counters(const otNat64Counters &aCounters); #endif @@ -494,10 +492,6 @@ class Interpreter : public OutputImplementer, public Output static void HandleSntpResponse(void *aContext, uint64_t aTime, otError aResult); #endif -#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE - void HandlePingReply(const otPingSenderReply *aReply); - void HandlePingStatistics(const otPingSenderStatistics *aStatistics); -#endif void HandleActiveScanResult(otActiveScanResult *aResult); void HandleEnergyScanResult(otEnergyScanResult *aResult); void HandleLinkPcapReceive(const otRadioFrame *aFrame, bool aIsTx); @@ -533,6 +527,7 @@ class Interpreter : public OutputImplementer, public Output UserCommandsEntry mUserCommands[kMaxUserCommandEntries]; bool mCommandIsPending; + bool mInternalDebugCommand; TimerMilliContext mTimer; @@ -598,11 +593,11 @@ class Interpreter : public OutputImplementer, public Output #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE Tcat mTcat; #endif -#endif // OPENTHREAD_FTD || OPENTHREAD_MTD - #if OPENTHREAD_CONFIG_PING_SENDER_ENABLE - bool mPingIsAsync : 1; + PingSender mPing; #endif +#endif // OPENTHREAD_FTD || OPENTHREAD_MTD + #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE bool mLocateInProgress : 1; #endif diff --git a/src/cli/cli_br.cpp b/src/cli/cli_br.cpp index bd4d0dfe5..9c77c7d07 100644 --- a/src/cli/cli_br.cpp +++ b/src/cli/cli_br.cpp @@ -435,6 +435,66 @@ template <> otError Br::Process(Arg aArgs[]) return error; } +#if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE +template <> otError Br::Process(Arg aArgs[]) +{ + otError error = OT_ERROR_NONE; + + /** + * @cli br pd (enable,disable) + * @code + * br pd enable + * Done + * @endcode + * @code + * br pd disable + * Done + * @endcode + * @cparam br pd @ca{enable|disable} + * @par api_copy + * #otBorderRoutingDhcp6PdSetEnabled + * + */ + if (Interpreter::GetInterpreter().ProcessEnableDisable(aArgs, otBorderRoutingDhcp6PdSetEnabled) == OT_ERROR_NONE) + { + } + /** + * @cli br pd state + * @code + * br pd state + * running + * Done + * @endcode + * @par api_copy + * #otBorderRoutingDhcp6PdGetState + */ + else if (aArgs[0] == "state") + { + static const char *const kDhcpv6PdStateStrings[] = { + "disabled", // (0) OT_BORDER_ROUTING_DHCP6_PD_STATE_DISABLED + "stopped", // (1) OT_BORDER_ROUTING_DHCP6_PD_STATE_STOPPED + "running", // (2) OT_BORDER_ROUTING_DHCP6_PD_STATE_RUNNING + }; + + static_assert(0 == OT_BORDER_ROUTING_DHCP6_PD_STATE_DISABLED, + "OT_BORDER_ROUTING_DHCP6_PD_STATE_DISABLED value is not expected!"); + static_assert(1 == OT_BORDER_ROUTING_DHCP6_PD_STATE_STOPPED, + "OT_BORDER_ROUTING_DHCP6_PD_STATE_STOPPED value is not expected!"); + static_assert(2 == OT_BORDER_ROUTING_DHCP6_PD_STATE_RUNNING, + "OT_BORDER_ROUTING_DHCP6_PD_STATE_RUNNING value is not expected!"); + + OutputLine("%s", Stringify(otBorderRoutingDhcp6PdGetState(GetInstancePtr()), kDhcpv6PdStateStrings)); + } + else + { + ExitNow(error = OT_ERROR_INVALID_COMMAND); + } + +exit: + return error; +} +#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE + /** * @cli br routers * @code @@ -638,6 +698,9 @@ otError Br::Process(Arg aArgs[]) #endif CmdEntry("omrprefix"), CmdEntry("onlinkprefix"), +#if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE + CmdEntry("pd"), +#endif CmdEntry("prefixtable"), CmdEntry("rioprf"), CmdEntry("routeprf"), diff --git a/src/cli/cli_config.h b/src/cli/cli_config.h index ac9b5e1cc..0eb9b2d08 100644 --- a/src/cli/cli_config.h +++ b/src/cli/cli_config.h @@ -196,4 +196,14 @@ #define OPENTHREAD_CONFIG_CLI_REGISTER_IP6_RECV_CALLBACK 0 #endif +/** + * @def OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE + * + * Define to 1 to enable BLE secure support. + * + */ +#ifndef OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE +#define OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE 0 +#endif + #endif // CONFIG_CLI_H_ diff --git a/src/cli/cli_history.cpp b/src/cli/cli_history.cpp index b44a74fc3..82d75557a 100644 --- a/src/cli/cli_history.cpp +++ b/src/cli/cli_history.cpp @@ -71,6 +71,62 @@ otError History::ParseArgs(Arg aArgs[], bool &aIsList, uint16_t &aNumEntries) co return aArgs[0].IsEmpty() ? OT_ERROR_NONE : OT_ERROR_INVALID_ARGS; } +/** + * @cli history ipaddr + * @code + * history ipaddr + * | Age | Event | Address / Prefix Length | Origin |Scope| P | V | R | + * +----------------------+---------+---------------------------------------------+--------+-----+---+---+---+ + * | 00:00:04.991 | Removed | 2001:dead:beef:cafe:c4cb:caba:8d55:e30b/64 | slaac | 14 | Y | Y | N | + * | 00:00:44.647 | Added | 2001:dead:beef:cafe:c4cb:caba:8d55:e30b/64 | slaac | 14 | Y | Y | N | + * | 00:01:07.199 | Added | fd00:0:0:0:0:0:0:1/64 | manual | 14 | Y | Y | N | + * | 00:02:17.885 | Added | fdde:ad00:beef:0:0:ff:fe00:fc00/64 | thread | 3 | N | Y | N | + * | 00:02:17.885 | Added | fdde:ad00:beef:0:0:ff:fe00:5400/64 | thread | 3 | N | Y | Y | + * | 00:02:20.107 | Removed | fdde:ad00:beef:0:0:ff:fe00:5400/64 | thread | 3 | N | Y | Y | + * | 00:02:21.575 | Added | fdde:ad00:beef:0:0:ff:fe00:5400/64 | thread | 3 | N | Y | Y | + * | 00:02:21.575 | Added | fdde:ad00:beef:0:ecea:c4fc:ad96:4655/64 | thread | 3 | N | Y | N | + * | 00:02:23.904 | Added | fe80:0:0:0:3c12:a4d2:fbe0:31ad/64 | thread | 2 | Y | Y | N | + * Done + * @endcode + * @code + * history ipaddr list 5 + * 00:00:20.327 -> event:Removed address:2001:dead:beef:cafe:c4cb:caba:8d55:e30b prefixlen:64 origin:slaac scope:14 preferred:yes valid:yes rloc:no + * 00:00:59.983 -> event:Added address:2001:dead:beef:cafe:c4cb:caba:8d55:e30b prefixlen:64 origin:slaac scope:14 preferred:yes valid:yes rloc:no + * 00:01:22.535 -> event:Added address:fd00:0:0:0:0:0:0:1 prefixlen:64 origin:manual scope:14 preferred:yes valid:yes rloc:no + * 00:02:33.221 -> event:Added address:fdde:ad00:beef:0:0:ff:fe00:fc00 prefixlen:64 origin:thread scope:3 preferred:no valid:yes rloc:no + * 00:02:33.221 -> event:Added address:fdde:ad00:beef:0:0:ff:fe00:5400 prefixlen:64 origin:thread scope:3 preferred:no valid:yes rloc:yes + * Done + * @endcode + * @cparam history ipaddr [@ca{list}] [@ca{num-entries}] + * * Use the `list` option to display the output in list format. Otherwise, + * the output is shown in table format. + * * Use the `num-entries` option to limit the output to the number of + * most-recent entries specified. If this option is not used, all stored + * entries are shown in the output. + * @par + * Displays the unicast IPv6 address history in table or list format. + * @par + * Each table or list entry provides: + * * Age: Time elapsed since the command was issued, and given in the format: + * `hours`:`minutes`:`seconds`:`milliseconds` + * * Event: Possible values are `Added` or `Removed`. + * * Address/Prefix Length: Unicast address with its prefix length (in bits). + * * Origin: Possible value are `thread`, `slaac`, `dhcp6`, or `manual`. + * * Scope: IPv6 address scope. + * * P: Preferred flag. + * * V: Valid flag. + * * RLOC (R): This flag indicates if the IPv6 address is a routing locator. + * @note + * All commands under `history` require the `OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE` + * feature to be enabled. + * @sa otHistoryTrackerEntryAgeToString + * @sa otHistoryTrackerIterateUnicastAddressHistory + */ template <> otError History::Process(Arg aArgs[]) { otError error; @@ -134,6 +190,54 @@ template <> otError History::Process(Arg aArgs[]) return error; } +/** + * @cli history ipmaddr + * @code + * history ipmaddr + * | Age | Event | Multicast Address | Origin | + * +----------------------+--------------+-----------------------------------------+--------+ + * | 00:00:08.592 | Unsubscribed | ff05:0:0:0:0:0:0:1 | Manual | + * | 00:01:25.353 | Subscribed | ff05:0:0:0:0:0:0:1 | Manual | + * | 00:01:54.953 | Subscribed | ff03:0:0:0:0:0:0:2 | Thread | + * | 00:01:54.953 | Subscribed | ff02:0:0:0:0:0:0:2 | Thread | + * | 00:01:59.329 | Subscribed | ff33:40:fdde:ad00:beef:0:0:1 | Thread | + * | 00:01:59.329 | Subscribed | ff32:40:fdde:ad00:beef:0:0:1 | Thread | + * | 00:02:01.129 | Subscribed | ff03:0:0:0:0:0:0:fc | Thread | + * | 00:02:01.129 | Subscribed | ff03:0:0:0:0:0:0:1 | Thread | + * | 00:02:01.129 | Subscribed | ff02:0:0:0:0:0:0:1 | Thread | + * Done + * @endcode + * @code + * history ipmaddr list + * 00:00:25.447 -> event:Unsubscribed address:ff05:0:0:0:0:0:0:1 origin:Manual + * 00:01:42.208 -> event:Subscribed address:ff05:0:0:0:0:0:0:1 origin:Manual + * 00:02:11.808 -> event:Subscribed address:ff03:0:0:0:0:0:0:2 origin:Thread + * 00:02:11.808 -> event:Subscribed address:ff02:0:0:0:0:0:0:2 origin:Thread + * 00:02:16.184 -> event:Subscribed address:ff33:40:fdde:ad00:beef:0:0:1 origin:Thread + * 00:02:16.184 -> event:Subscribed address:ff32:40:fdde:ad00:beef:0:0:1 origin:Thread + * 00:02:17.984 -> event:Subscribed address:ff03:0:0:0:0:0:0:fc origin:Thread + * 00:02:17.984 -> event:Subscribed address:ff03:0:0:0:0:0:0:1 origin:Thread + * 00:02:17.984 -> event:Subscribed address:ff02:0:0:0:0:0:0:1 origin:Thread + * Done + * @endcode + * @cparam history ipmaddr [@ca{list}] [@ca{num-entries}] + * * Use the `list` option to display the output in list format. Otherwise, + * the output is shown in table format. + * * Use the `num-entries` option to limit the output to the number of + * most-recent entries specified. If this option is not used, all stored + * entries are shown in the output. + * @par + * Displays the multicast IPv6 address history in table or list format. + * @par + * Each table or list entry provides: + * * Age: Time elapsed since the command was issued, and given in the format: + * `hours`:`minutes`:`seconds`:`milliseconds` + * * Event: Possible values are `Subscribed` or `Unsubscribed`. + * * Multicast Address + * * Origin: Possible values are `Thread` or `Manual`. + * @sa otHistoryTrackerEntryAgeToString + * @sa otHistoryTrackerIterateMulticastAddressHistory + */ template <> otError History::Process(Arg aArgs[]) { static const char *const kEventStrings[] = { @@ -191,6 +295,62 @@ template <> otError History::Process(Arg aArgs[]) return error; } +/** + * @cli history neighbor + * @code + * history neighbor + * | Age | Type | Event | Extended Address | RLOC16 | Mode | Ave RSS | + * +----------------------+--------+-----------+------------------+--------+------+---------+ + * | 00:00:29.233 | Child | Added | ae5105292f0b9169 | 0x8404 | - | -20 | + * | 00:01:38.368 | Child | Removed | ae5105292f0b9169 | 0x8401 | - | -20 | + * | 00:04:27.181 | Child | Changed | ae5105292f0b9169 | 0x8401 | - | -20 | + * | 00:04:51.236 | Router | Added | 865c7ca38a5fa960 | 0x9400 | rdn | -20 | + * | 00:04:51.587 | Child | Removed | 865c7ca38a5fa960 | 0x8402 | rdn | -20 | + * | 00:05:22.764 | Child | Changed | ae5105292f0b9169 | 0x8401 | rn | -20 | + * | 00:06:40.764 | Child | Added | 4ec99efc874a1841 | 0x8403 | r | -20 | + * | 00:06:44.060 | Child | Added | 865c7ca38a5fa960 | 0x8402 | rdn | -20 | + * | 00:06:49.515 | Child | Added | ae5105292f0b9169 | 0x8401 | - | -20 | + * Done + * @endcode + * @code + * history neighbor list + * 00:00:34.753 -> type:Child event:Added extaddr:ae5105292f0b9169 rloc16:0x8404 mode:- rss:-20 + * 00:01:43.888 -> type:Child event:Removed extaddr:ae5105292f0b9169 rloc16:0x8401 mode:- rss:-20 + * 00:04:32.701 -> type:Child event:Changed extaddr:ae5105292f0b9169 rloc16:0x8401 mode:- rss:-20 + * 00:04:56.756 -> type:Router event:Added extaddr:865c7ca38a5fa960 rloc16:0x9400 mode:rdn rss:-20 + * 00:04:57.107 -> type:Child event:Removed extaddr:865c7ca38a5fa960 rloc16:0x8402 mode:rdn rss:-20 + * 00:05:28.284 -> type:Child event:Changed extaddr:ae5105292f0b9169 rloc16:0x8401 mode:rn rss:-20 + * 00:06:46.284 -> type:Child event:Added extaddr:4ec99efc874a1841 rloc16:0x8403 mode:r rss:-20 + * 00:06:49.580 -> type:Child event:Added extaddr:865c7ca38a5fa960 rloc16:0x8402 mode:rdn rss:-20 + * 00:06:55.035 -> type:Child event:Added extaddr:ae5105292f0b9169 rloc16:0x8401 mode:- rss:-20 + * Done + * @endcode + * @cparam history neighbor [@ca{list}] [@ca{num-entries}] + * * Use the `list` option to display the output in list format. Otherwise, + * the output is shown in table format. + * * Use the `num-entries` option to limit the output to the number of + * most-recent entries specified. If this option is not used, all stored + * entries are shown in the output. + * @par + * Displays the neighbor history in table or list format. + * @par + * Each table or list entry provides: + * * Age: Time elapsed since the command was issued, and given in the format: + * `hours`:`minutes`:`seconds`:`milliseconds` + * * Type: `Child` or `Router`. + * * Event: Possible values are `Added`, `Removed`, or `Changed`. + * * Extended Address + * * RLOC16 + * * Mode: MLE link mode. Possible values: + * * `-`: no flags set (rx-off-when-idle, minimal Thread device, + * stable network data). + * * `r`: rx-on-when-idle + * * `d`: Full Thread Device. + * * `n`: Full Network Data + * * Ave RSS: Average number of frames (in dBm) received from the neighbor at the + * time the entry was recorded. + * @sa otHistoryTrackerIterateNeighborHistory + */ template <> otError History::Process(Arg aArgs[]) { static const char *const kEventString[] = { @@ -256,6 +416,87 @@ template <> otError History::Process(Arg aArgs[]) return error; } +/** + * @cli history router + * @code + * history router + * | Age | Event | ID (RLOC16) | Next Hop | Path Cost | + * +----------------------+----------------+-------------+-------------+------------+ + * | 00:00:05.258 | NextHopChanged | 7 (0x1c00) | 34 (0x8800) | inf -> 3 | + * | 00:00:08.604 | NextHopChanged | 34 (0x8800) | 34 (0x8800) | inf -> 2 | + * | 00:00:08.604 | Added | 7 (0x1c00) | none | inf -> inf | + * | 00:00:11.931 | Added | 34 (0x8800) | none | inf -> inf | + * | 00:00:14.948 | Removed | 59 (0xec00) | none | inf -> inf | + * | 00:00:14.948 | Removed | 54 (0xd800) | none | inf -> inf | + * | 00:00:14.948 | Removed | 34 (0x8800) | none | inf -> inf | + * | 00:00:14.948 | Removed | 7 (0x1c00) | none | inf -> inf | + * | 00:00:54.795 | NextHopChanged | 59 (0xec00) | 34 (0x8800) | 1 -> 5 | + * | 00:02:33.735 | NextHopChanged | 54 (0xd800) | none | 15 -> inf | + * | 00:03:10.915 | CostChanged | 54 (0xd800) | 34 (0x8800) | 13 -> 15 | + * | 00:03:45.716 | NextHopChanged | 54 (0xd800) | 34 (0x8800) | 15 -> 13 | + * | 00:03:46.188 | CostChanged | 54 (0xd800) | 59 (0xec00) | 13 -> 15 | + * | 00:04:19.124 | CostChanged | 54 (0xd800) | 59 (0xec00) | 11 -> 13 | + * | 00:04:52.008 | CostChanged | 54 (0xd800) | 59 (0xec00) | 9 -> 11 | + * | 00:05:23.176 | CostChanged | 54 (0xd800) | 59 (0xec00) | 7 -> 9 | + * | 00:05:51.081 | CostChanged | 54 (0xd800) | 59 (0xec00) | 5 -> 7 | + * | 00:06:48.721 | CostChanged | 54 (0xd800) | 59 (0xec00) | 3 -> 5 | + * | 00:07:13.792 | NextHopChanged | 54 (0xd800) | 59 (0xec00) | 1 -> 3 | + * | 00:09:28.681 | NextHopChanged | 7 (0x1c00) | 34 (0x8800) | inf -> 3 | + * | 00:09:31.882 | Added | 7 (0x1c00) | none | inf -> inf | + * | 00:09:51.240 | NextHopChanged | 54 (0xd800) | 54 (0xd800) | inf -> 1 | + * | 00:09:54.204 | Added | 54 (0xd800) | none | inf -> inf | + * | 00:10:20.645 | NextHopChanged | 34 (0x8800) | 34 (0x8800) | inf -> 2 | + * | 00:10:24.242 | NextHopChanged | 59 (0xec00) | 59 (0xec00) | inf -> 1 | + * | 00:10:24.242 | Added | 34 (0x8800) | none | inf -> inf | + * | 00:10:41.900 | NextHopChanged | 59 (0xec00) | none | 1 -> inf | + * | 00:10:42.480 | Added | 3 (0x0c00) | 3 (0x0c00) | inf -> inf | + * | 00:10:43.614 | Added | 59 (0xec00) | 59 (0xec00) | inf -> 1 | + * Done + * @endcode + * @code + * history router list 20 + * 00:00:06.959 -> event:NextHopChanged router:7(0x1c00) nexthop:34(0x8800) old-cost:inf new-cost:3 + * 00:00:10.305 -> event:NextHopChanged router:34(0x8800) nexthop:34(0x8800) old-cost:inf new-cost:2 + * 00:00:10.305 -> event:Added router:7(0x1c00) nexthop:none old-cost:inf new-cost:inf + * 00:00:13.632 -> event:Added router:34(0x8800) nexthop:none old-cost:inf new-cost:inf + * 00:00:16.649 -> event:Removed router:59(0xec00) nexthop:none old-cost:inf new-cost:inf + * 00:00:16.649 -> event:Removed router:54(0xd800) nexthop:none old-cost:inf new-cost:inf + * 00:00:16.649 -> event:Removed router:34(0x8800) nexthop:none old-cost:inf new-cost:inf + * 00:00:16.649 -> event:Removed router:7(0x1c00) nexthop:none old-cost:inf new-cost:inf + * 00:00:56.496 -> event:NextHopChanged router:59(0xec00) nexthop:34(0x8800) old-cost:1 new-cost:5 + * 00:02:35.436 -> event:NextHopChanged router:54(0xd800) nexthop:none old-cost:15 new-cost:inf + * 00:03:12.616 -> event:CostChanged router:54(0xd800) nexthop:34(0x8800) old-cost:13 new-cost:15 + * 00:03:47.417 -> event:NextHopChanged router:54(0xd800) nexthop:34(0x8800) old-cost:15 new-cost:13 + * 00:03:47.889 -> event:CostChanged router:54(0xd800) nexthop:59(0xec00) old-cost:13 new-cost:15 + * 00:04:20.825 -> event:CostChanged router:54(0xd800) nexthop:59(0xec00) old-cost:11 new-cost:13 + * 00:04:53.709 -> event:CostChanged router:54(0xd800) nexthop:59(0xec00) old-cost:9 new-cost:11 + * 00:05:24.877 -> event:CostChanged router:54(0xd800) nexthop:59(0xec00) old-cost:7 new-cost:9 + * 00:05:52.782 -> event:CostChanged router:54(0xd800) nexthop:59(0xec00) old-cost:5 new-cost:7 + * 00:06:50.422 -> event:CostChanged router:54(0xd800) nexthop:59(0xec00) old-cost:3 new-cost:5 + * 00:07:15.493 -> event:NextHopChanged router:54(0xd800) nexthop:59(0xec00) old-cost:1 new-cost:3 + * 00:09:30.382 -> event:NextHopChanged router:7(0x1c00) nexthop:34(0x8800) old-cost:inf new-cost:3 + * Done + * @endcode + * @cparam history router [@ca{list}] [@ca{num-entries}] + * * Use the `list` option to display the output in list format. Otherwise, + * the output is shown in table format. + * * Use the `num-entries` option to limit the output to the number of + * most-recent entries specified. If this option is not used, all stored + * entries are shown in the output. + * @par + * Displays the route-table history in table or list format. + * @par + * Each table or list entry provides: + * * Age: Time elapsed since the command was issued, and given in the format: + * `hours`:`minutes`:`seconds`:`milliseconds` + * * Event: Possible values are `Added`, `Removed`, `NextHopChanged`, or `CostChanged`. + * * ID (RLOC16): Router ID and RLOC16 of the router. + * * Next Hop: Router ID and RLOC16 of the next hop. If there is no next hop, + * `none` is shown. + * * Path Cost: old cost `->` new cost. A value of `inf` indicates an infinite + * path cost. + * @sa otHistoryTrackerIterateRouterHistory + */ template <> otError History::Process(Arg aArgs[]) { static const char *const kEventString[] = { @@ -342,6 +583,61 @@ template <> otError History::Process(Arg aArgs[]) return error; } +/** + * @cli history netinfo + * @code + * history netinfo + * | Age | Role | Mode | RLOC16 | Partition ID | + * +----------------------+----------+------+--------+--------------+ + * | 00:00:10.069 | router | rdn | 0x6000 | 151029327 | + * | 00:02:09.337 | child | rdn | 0x2001 | 151029327 | + * | 00:02:09.338 | child | rdn | 0x2001 | 151029327 | + * | 00:07:40.806 | child | - | 0x2001 | 151029327 | + * | 00:07:42.297 | detached | - | 0x6000 | 0 | + * | 00:07:42.968 | disabled | - | 0x6000 | 0 | + * Done + * @endcode + * @code + * history netinfo list + * 00:00:59.467 -> role:router mode:rdn rloc16:0x6000 partition-id:151029327 + * 00:02:58.735 -> role:child mode:rdn rloc16:0x2001 partition-id:151029327 + * 00:02:58.736 -> role:child mode:rdn rloc16:0x2001 partition-id:151029327 + * 00:08:30.204 -> role:child mode:- rloc16:0x2001 partition-id:151029327 + * 00:08:31.695 -> role:detached mode:- rloc16:0x6000 partition-id:0 + * 00:08:32.366 -> role:disabled mode:- rloc16:0x6000 partition-id:0 + * Done + * @endcode + * @code + * history netinfo 2 + * | Age | Role | Mode | RLOC16 | Partition ID | + * +----------------------+----------+------+--------+--------------+ + * | 00:02:05.451 | router | rdn | 0x6000 | 151029327 | + * | 00:04:04.719 | child | rdn | 0x2001 | 151029327 | + * Done + * @endcode + * @cparam history netinfo [@ca{list}] [@ca{num-entries}] + * * Use the `list` option to display the output in list format. Otherwise, + * the output is shown in table format. + * * Use the `num-entries` option to limit the output to the number of + * most-recent entries specified. If this option is not used, all stored + * entries are shown in the output. + * @par + * Displays the network info history in table or list format. + * @par + * Each table or list entry provides: + * * Age: Time elapsed since the command was issued, and given in the format: + * `hours`:`minutes`:`seconds`:`milliseconds` + * * Role: Device role. Possible values are `router`, `child`, `detached`, or `disabled`. + * * Mode: MLE link mode. Possible values: + * * `-`: no flags set (rx-off-when-idle, minimal Thread device, + * stable network data). + * * `r`: rx-on-when-idle + * * `d`: Full Thread Device. + * * `n`: Full Network Data + * * RLOC16 + * * Partition ID. + * @sa otHistoryTrackerIterateNetInfoHistory + */ template <> otError History::Process(Arg aArgs[]) { otError error; @@ -385,10 +681,324 @@ template <> otError History::Process(Arg aArgs[]) return error; } +/** + * @cli history rx + * @code + * history rx + * | Age | Type | Len | Chksum | Sec | Prio | RSS |Dir | Neighb | Radio | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | UDP | 50 | 0xbd26 | no | net | -20 | RX | 0x4800 | 15.4 | + * | 00:00:07.640 | src: [fe80:0:0:0:d03d:d3e7:cc5e:7cd7]:19788 | + * | | dst: [ff02:0:0:0:0:0:0:1]:19788 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | HopOpts | 44 | 0x0000 | yes | norm | -20 | RX | 0x4800 | 15.4 | + * | 00:00:09.263 | src: [fdde:ad00:beef:0:0:ff:fe00:4800]:0 | + * | | dst: [ff03:0:0:0:0:0:0:2]:0 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | UDP | 12 | 0x3f7d | yes | net | -20 | RX | 0x4800 | 15.4 | + * | 00:00:09.302 | src: [fdde:ad00:beef:0:0:ff:fe00:4800]:61631 | + * | | dst: [fdde:ad00:beef:0:0:ff:fe00:4801]:61631 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | ICMP6(EchoReqst) | 16 | 0x942c | yes | norm | -20 | RX | 0x4800 | 15.4 | + * | 00:00:09.304 | src: [fdde:ad00:beef:0:ac09:a16b:3204:dc09]:0 | + * | | dst: [fdde:ad00:beef:0:dc0e:d6b3:f180:b75b]:0 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | HopOpts | 44 | 0x0000 | yes | norm | -20 | RX | 0x4800 | 15.4 | + * | 00:00:09.304 | src: [fdde:ad00:beef:0:0:ff:fe00:4800]:0 | + * | | dst: [ff03:0:0:0:0:0:0:2]:0 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | UDP | 50 | 0x2e37 | no | net | -20 | RX | 0x4800 | 15.4 | + * | 00:00:21.622 | src: [fe80:0:0:0:d03d:d3e7:cc5e:7cd7]:19788 | + * | | dst: [ff02:0:0:0:0:0:0:1]:19788 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | UDP | 50 | 0xe177 | no | net | -20 | RX | 0x4800 | 15.4 | + * | 00:00:26.640 | src: [fe80:0:0:0:d03d:d3e7:cc5e:7cd7]:19788 | + * | | dst: [ff02:0:0:0:0:0:0:1]:19788 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | UDP | 165 | 0x82ee | yes | net | -20 | RX | 0x4800 | 15.4 | + * | 00:00:30.000 | src: [fe80:0:0:0:d03d:d3e7:cc5e:7cd7]:19788 | + * | | dst: [fe80:0:0:0:a4a5:bbac:a8e:bd07]:19788 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | UDP | 93 | 0x52df | no | net | -20 | RX | unknwn | 15.4 | + * | 00:00:30.480 | src: [fe80:0:0:0:d03d:d3e7:cc5e:7cd7]:19788 | + * | | dst: [fe80:0:0:0:a4a5:bbac:a8e:bd07]:19788 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | UDP | 50 | 0x5ccf | no | net | -20 | RX | unknwn | 15.4 | + * | 00:00:30.772 | src: [fe80:0:0:0:d03d:d3e7:cc5e:7cd7]:19788 | + * | | dst: [ff02:0:0:0:0:0:0:1]:19788 | + * Done + * @endcode + * @code + * history rx list 4 + * 00:00:13.368 + type:UDP len:50 checksum:0xbd26 sec:no prio:net rss:-20 from:0x4800 radio:15.4 + src:[fe80:0:0:0:d03d:d3e7:cc5e:7cd7]:19788 + dst:[ff02:0:0:0:0:0:0:1]:19788 + * 00:00:14.991 + type:HopOpts len:44 checksum:0x0000 sec:yes prio:norm rss:-20 from:0x4800 radio:15.4 + src:[fdde:ad00:beef:0:0:ff:fe00:4800]:0 + dst:[ff03:0:0:0:0:0:0:2]:0 + * 00:00:15.030 + type:UDP len:12 checksum:0x3f7d sec:yes prio:net rss:-20 from:0x4800 radio:15.4 + src:[fdde:ad00:beef:0:0:ff:fe00:4800]:61631 + dst:[fdde:ad00:beef:0:0:ff:fe00:4801]:61631 + * 00:00:15.032 + type:ICMP6(EchoReqst) len:16 checksum:0x942c sec:yes prio:norm rss:-20 from:0x4800 radio:15.4 + src:[fdde:ad00:beef:0:ac09:a16b:3204:dc09]:0 + dst:[fdde:ad00:beef:0:dc0e:d6b3:f180:b75b]:0 + * Done + * @endcode + * @cparam history rx [@ca{list}] [@ca{num-entries}] + * * Use the `list` option to display the output in list format. Otherwise, + * the output is shown in table format. + * * Use the `num-entries` option to limit the output to the number of + * most-recent entries specified. If this option is not used, all stored + * entries are shown in the output. + * @par + * Displays the IPv6 message RX history in table or list format. + * @par + * Each table or list entry provides: + * * Age: Time elapsed since the command was issued, and given in the format: + * `hours`:`minutes`:`seconds`:`milliseconds` + * * Type: + * * IPv6 message type, such as `UDP`, `TCP`, `HopOpts`, and `ICMP6` (and its subtype). + * * `src`: Source IPv6 address and port number. + * * `dst`: Destination IPv6 address and port number (port number is valid + for UDP/TCP, otherwise it is 0). + * * Len: IPv6 payload length (excluding the IPv6 header). + * * Chksum: Message checksum (valid for UDP, TCP, or ICMP6 messages). + * * Sec: Indicates if link-layer security was used. + * * Prio: Message priority. Possible values are `low`, `norm`, `high`, or + * `net` (for Thread control messages). + * * RSS: Received Signal Strength (in dBm), averaged over all received fragment + * frames that formed the message. For TX history, `NA` (not applicable) + is displayed. + * * Dir: Shows whether the message was sent (`TX`) or received (`RX`). A failed + * transmission is indicated with `TX-F` in table format or + * `tx-success:no` in list format. Examples of a failed transmission + * include a `tx`getting aborted and no `ack` getting sent from the peer for + * any of the message fragments. + * * Neighb: Short address (RLOC16) of the neighbor with whom the message was + * sent/received. If the frame was broadcast, it is shown as + * `bcast` in table format or `0xffff` in list format. If the short + * address of the neighbor is not available, it is shown as `unknwn` in + * table format or `0xfffe` in list format. + * * Radio: Radio link on which the message was sent/received (useful when + `OPENTHREAD_CONFIG_MULTI_RADIO` is enabled). Can be `15.4`, `trel`, + or `all` (if sent on all radio links). + * @sa otHistoryTrackerIterateRxHistory + */ template <> otError History::Process(Arg aArgs[]) { return ProcessRxTxHistory(kRx, aArgs); } +/** + * @cli history rxtx + * @code + * history rxtx + * | Age | Type | Len | Chksum | Sec | Prio | RSS |Dir | Neighb | Radio | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | HopOpts | 44 | 0x0000 | yes | norm | -20 | RX | 0x0800 | 15.4 | + * | 00:00:09.267 | src: [fdde:ad00:beef:0:0:ff:fe00:800]:0 | + * | | dst: [ff03:0:0:0:0:0:0:2]:0 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | UDP | 12 | 0x6c6b | yes | net | -20 | RX | 0x0800 | 15.4 | + * | 00:00:09.290 | src: [fdde:ad00:beef:0:0:ff:fe00:800]:61631 | + * | | dst: [fdde:ad00:beef:0:0:ff:fe00:801]:61631 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | ICMP6(EchoReqst) | 16 | 0xc6a2 | yes | norm | -20 | RX | 0x0800 | 15.4 | + * | 00:00:09.292 | src: [fdde:ad00:beef:0:efe8:4910:cf95:dee9]:0 | + * | | dst: [fdde:ad00:beef:0:af4c:3644:882a:3698]:0 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | ICMP6(EchoReply) | 16 | 0xc5a2 | yes | norm | NA | TX | 0x0800 | 15.4 | + * | 00:00:09.292 | src: [fdde:ad00:beef:0:af4c:3644:882a:3698]:0 | + * | | dst: [fdde:ad00:beef:0:efe8:4910:cf95:dee9]:0 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | UDP | 50 | 0xaa0d | yes | net | NA | TX | 0x0800 | 15.4 | + * | 00:00:09.294 | src: [fdde:ad00:beef:0:0:ff:fe00:801]:61631 | + * | | dst: [fdde:ad00:beef:0:0:ff:fe00:800]:61631 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | HopOpts | 44 | 0x0000 | yes | norm | -20 | RX | 0x0800 | 15.4 | + * | 00:00:09.296 | src: [fdde:ad00:beef:0:0:ff:fe00:800]:0 | + * | | dst: [ff03:0:0:0:0:0:0:2]:0 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | UDP | 50 | 0xc1d8 | no | net | -20 | RX | 0x0800 | 15.4 | + * | 00:00:09.569 | src: [fe80:0:0:0:54d9:5153:ffc6:df26]:19788 | + * | | dst: [ff02:0:0:0:0:0:0:1]:19788 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | UDP | 50 | 0x3cb1 | no | net | -20 | RX | 0x0800 | 15.4 | + * | 00:00:16.519 | src: [fe80:0:0:0:54d9:5153:ffc6:df26]:19788 | + * | | dst: [ff02:0:0:0:0:0:0:1]:19788 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | UDP | 50 | 0xeda0 | no | net | -20 | RX | 0x0800 | 15.4 | + * | 00:00:20.599 | src: [fe80:0:0:0:54d9:5153:ffc6:df26]:19788 | + * | | dst: [ff02:0:0:0:0:0:0:1]:19788 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | UDP | 165 | 0xbdfa | yes | net | -20 | RX | 0x0800 | 15.4 | + * | 00:00:21.059 | src: [fe80:0:0:0:54d9:5153:ffc6:df26]:19788 | + * | | dst: [fe80:0:0:0:8893:c2cc:d983:1e1c]:19788 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | UDP | 64 | 0x1c11 | no | net | NA | TX | 0x0800 | 15.4 | + * | 00:00:21.062 | src: [fe80:0:0:0:8893:c2cc:d983:1e1c]:19788 | + * | | dst: [fe80:0:0:0:54d9:5153:ffc6:df26]:19788 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | UDP | 93 | 0xedff | no | net | -20 | RX | unknwn | 15.4 | + * | 00:00:21.474 | src: [fe80:0:0:0:54d9:5153:ffc6:df26]:19788 | + * | | dst: [fe80:0:0:0:8893:c2cc:d983:1e1c]:19788 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | UDP | 44 | 0xd383 | no | net | NA | TX | bcast | 15.4 | + * | 00:00:21.811 | src: [fe80:0:0:0:8893:c2cc:d983:1e1c]:19788 | + * | | dst: [ff02:0:0:0:0:0:0:2]:19788 | + * Done + * @endcode + * @code + * history rxtx list 5 + * 00:00:02.100 + type:UDP len:50 checksum:0xd843 sec:no prio:net rss:-20 from:0x0800 radio:15.4 + src:[fe80:0:0:0:54d9:5153:ffc6:df26]:19788 + dst:[ff02:0:0:0:0:0:0:1]:19788 + * 00:00:15.331 + type:HopOpts len:44 checksum:0x0000 sec:yes prio:norm rss:-20 from:0x0800 radio:15.4 + src:[fdde:ad00:beef:0:0:ff:fe00:800]:0 + dst:[ff03:0:0:0:0:0:0:2]:0 + * 00:00:15.354 + type:UDP len:12 checksum:0x6c6b sec:yes prio:net rss:-20 from:0x0800 radio:15.4 + src:[fdde:ad00:beef:0:0:ff:fe00:800]:61631 + dst:[fdde:ad00:beef:0:0:ff:fe00:801]:61631 + * 00:00:15.356 + type:ICMP6(EchoReqst) len:16 checksum:0xc6a2 sec:yes prio:norm rss:-20 from:0x0800 radio:15.4 + src:[fdde:ad00:beef:0:efe8:4910:cf95:dee9]:0 + dst:[fdde:ad00:beef:0:af4c:3644:882a:3698]:0 + * 00:00:15.356 + type:ICMP6(EchoReply) len:16 checksum:0xc5a2 sec:yes prio:norm tx-success:yes to:0x0800 radio:15.4 + src:[fdde:ad00:beef:0:af4c:3644:882a:3698]:0 + dst:[fdde:ad00:beef:0:efe8:4910:cf95:dee9]:0 + * Done + * @endcode + * @cparam history rxtx [@ca{list}] [@ca{num-entries}] + * * Use the `list` option to display the output in list format. Otherwise, + * the output is shown in table format. + * * Use the `num-entries` option to limit the output to the number of + * most-recent entries specified. If this option is not used, all stored + * entries are shown in the output. + * @par + * Displays the combined IPv6 message RX and TX history in table or list format. + * @par + * Each table or list entry provides: + * * Age: Time elapsed since the command was issued, and given in the format: + * `hours`:`minutes`:`seconds`:`milliseconds` + * * Type: + * * IPv6 message type, such as `UDP`, `TCP`, `HopOpts`, and `ICMP6` (and its subtype). + * * `src`: Source IPv6 address and port number. + * * `dst`: Destination IPv6 address and port number (port number is valid + for UDP/TCP, otherwise it is 0). + * * Len: IPv6 payload length (excluding the IPv6 header). + * * Chksum: Message checksum (valid for UDP, TCP, or ICMP6 messages). + * * Sec: Indicates if link-layer security was used. + * * Prio: Message priority. Possible values are `low`, `norm`, `high`, or + * `net` (for Thread control messages). + * * RSS: Received Signal Strength (in dBm), averaged over all received fragment + * frames that formed the message. For TX history, `NA` (not applicable) + is displayed. + * * Dir: Shows whether the message was sent (`TX`) or received (`RX`). A failed + * transmission is indicated with `TX-F` in table format or + * `tx-success:no` in list format. Examples of a failed transmission + * include a `tx`getting aborted and no `ack` getting sent from the peer for + * any of the message fragments. + * * Neighb: Short address (RLOC16) of the neighbor with whom the message was + * sent/received. If the frame was broadcast, it is shown as + * `bcast` in table format or `0xffff` in list format. If the short + * address of the neighbor is not available, it is shown as `unknwn` in + * table format or `0xfffe` in list format. + * * Radio: Radio link on which the message was sent/received (useful when + `OPENTHREAD_CONFIG_MULTI_RADIO` is enabled). Can be `15.4`, `trel`, + or `all` (if sent on all radio links). + * @sa otHistoryTrackerIterateRxHistory + * @sa otHistoryTrackerIterateTxHistory + */ template <> otError History::Process(Arg aArgs[]) { return ProcessRxTxHistory(kRxTx, aArgs); } +/** + * @cli history tx + * @code + * history tx + * | Age | Type | Len | Chksum | Sec | Prio | RSS |Dir | Neighb | Radio | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | ICMP6(EchoReply) | 16 | 0x932c | yes | norm | NA | TX | 0x4800 | 15.4 | + * | 00:00:18.798 | src: [fdde:ad00:beef:0:dc0e:d6b3:f180:b75b]:0 | + * | | dst: [fdde:ad00:beef:0:ac09:a16b:3204:dc09]:0 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | UDP | 50 | 0xce87 | yes | net | NA | TX | 0x4800 | 15.4 | + * | 00:00:18.800 | src: [fdde:ad00:beef:0:0:ff:fe00:4801]:61631 | + * | | dst: [fdde:ad00:beef:0:0:ff:fe00:4800]:61631 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | UDP | 64 | 0xf7ba | no | net | NA | TX | 0x4800 | 15.4 | + * | 00:00:39.499 | src: [fe80:0:0:0:a4a5:bbac:a8e:bd07]:19788 | + * | | dst: [fe80:0:0:0:d03d:d3e7:cc5e:7cd7]:19788 | + * +----------------------+------------------+-------+--------+-----+------+------+----+--------+-------+ + * | | UDP | 44 | 0x26d4 | no | net | NA | TX | bcast | 15.4 | + * | 00:00:40.256 | src: [fe80:0:0:0:a4a5:bbac:a8e:bd07]:19788 | + * | | dst: [ff02:0:0:0:0:0:0:2]:19788 | + * Done + * @endcode + * @code + * history tx list + * 00:00:23.957 + type:ICMP6(EchoReply) len:16 checksum:0x932c sec:yes prio:norm tx-success:yes to:0x4800 radio:15.4 + src:[fdde:ad00:beef:0:dc0e:d6b3:f180:b75b]:0 + dst:[fdde:ad00:beef:0:ac09:a16b:3204:dc09]:0 + * 00:00:23.959 + type:UDP len:50 checksum:0xce87 sec:yes prio:net tx-success:yes to:0x4800 radio:15.4 + src:[fdde:ad00:beef:0:0:ff:fe00:4801]:61631 + dst:[fdde:ad00:beef:0:0:ff:fe00:4800]:61631 + * 00:00:44.658 + type:UDP len:64 checksum:0xf7ba sec:no prio:net tx-success:yes to:0x4800 radio:15.4 + src:[fe80:0:0:0:a4a5:bbac:a8e:bd07]:19788 + dst:[fe80:0:0:0:d03d:d3e7:cc5e:7cd7]:19788 + * 00:00:45.415 + type:UDP len:44 checksum:0x26d4 sec:no prio:net tx-success:yes to:0xffff radio:15.4 + src:[fe80:0:0:0:a4a5:bbac:a8e:bd07]:19788 + dst:[ff02:0:0:0:0:0:0:2]:19788 + * Done + * @endcode + * @cparam history tx [@ca{list}] [@ca{num-entries}] + * * Use the `list` option to display the output in list format. Otherwise, + * the output is shown in table format. + * * Use the `num-entries` option to limit the output to the number of + * most-recent entries specified. If this option is not used, all stored + * entries are shown in the output. + * @par + * Displays the IPv6 message TX history in table or list format. + * @par + * Each table or list entry provides: + * * Age: Time elapsed since the command was issued, and given in the format: + * `hours`:`minutes`:`seconds`:`milliseconds` + * * Type: + * * IPv6 message type, such as `UDP`, `TCP`, `HopOpts`, and `ICMP6` (and its subtype). + * * `src`: Source IPv6 address and port number. + * * `dst`: Destination IPv6 address and port number (port number is valid + for UDP/TCP, otherwise it is 0). + * * Len: IPv6 payload length (excluding the IPv6 header). + * * Chksum: Message checksum (valid for UDP, TCP, or ICMP6 messages). + * * Sec: Indicates if link-layer security was used. + * * Prio: Message priority. Possible values are `low`, `norm`, `high`, or + * `net` (for Thread control messages). + * * RSS: Received Signal Strength (in dBm), averaged over all received fragment + * frames that formed the message. For TX history, `NA` (not applicable) + is displayed. + * * Dir: Shows whether the message was sent (`TX`) or received (`RX`). A failed + * transmission is indicated with `TX-F` in table format or + * `tx-success:no` in list format. Examples of a failed transmission + * include a `tx`getting aborted and no `ack` getting sent from the peer for + * any of the message fragments. + * * Neighb: Short address (RLOC16) of the neighbor with whom the message was + * sent/received. If the frame was broadcast, it is shown as + * `bcast` in table format or `0xffff` in list format. If the short + * address of the neighbor is not available, it is shown as `unknwn` in + * table format or `0xfffe` in list format. + * * Radio: Radio link on which the message was sent/received (useful when + `OPENTHREAD_CONFIG_MULTI_RADIO` is enabled). Can be `15.4`, `trel`, + or `all` (if sent on all radio links). + * @sa otHistoryTrackerIterateTxHistory + */ template <> otError History::Process(Arg aArgs[]) { return ProcessRxTxHistory(kTx, aArgs); } const char *History::MessagePriorityToString(uint8_t aPriority) @@ -636,6 +1246,58 @@ void History::OutputRxTxEntryTableFormat(const otHistoryTrackerMessageInfo &aInf OutputLine("| %20s | dst: %-70s |", "", addrString); } +/** + * @cli history prefix + * @code + * history prefix + * | Age | Event | Prefix | Flags | Pref | RLOC16 | + * +----------------------+---------+---------------------------------------------+-----------+------+--------+ + * | 00:00:10.663 | Added | fd00:1111:2222:3333::/64 | paro | med | 0x5400 | + * | 00:01:02.054 | Removed | fd00:dead:beef:1::/64 | paros | high | 0x5400 | + * | 00:01:21.136 | Added | fd00:abba:cddd:0::/64 | paos | med | 0x5400 | + * | 00:01:45.144 | Added | fd00:dead:beef:1::/64 | paros | high | 0x3c00 | + * | 00:01:50.944 | Added | fd00:dead:beef:1::/64 | paros | high | 0x5400 | + * | 00:01:59.887 | Added | fd00:dead:beef:1::/64 | paros | med | 0x8800 | + * Done + * @endcode + * @code + * history prefix list + * 00:04:12.487 -> event:Added prefix:fd00:1111:2222:3333::/64 flags:paro pref:med rloc16:0x5400 + * 00:05:03.878 -> event:Removed prefix:fd00:dead:beef:1::/64 flags:paros pref:high rloc16:0x5400 + * 00:05:22.960 -> event:Added prefix:fd00:abba:cddd:0::/64 flags:paos pref:med rloc16:0x5400 + * 00:05:46.968 -> event:Added prefix:fd00:dead:beef:1::/64 flags:paros pref:high rloc16:0x3c00 + * 00:05:52.768 -> event:Added prefix:fd00:dead:beef:1::/64 flags:paros pref:high rloc16:0x5400 + * 00:06:01.711 -> event:Added prefix:fd00:dead:beef:1::/64 flags:paros pref:med rloc16:0x8800 + * Done + * @endcode + * @cparam history prefix [@ca{list}] [@ca{num-entries}] + * * Use the `list` option to display the output in list format. Otherwise, + * the output is shown in table format. + * * Use the `num-entries` option to limit the output to the number of + * most-recent entries specified. If this option is not used, all stored + * entries are shown in the output. + * @par + * Displays the network data for the mesh prefix history in table or list format. + * @par + * Each table or list entry provides: + * * Age: Time elapsed since the command was issued, and given in the format: + * `hours`:`minutes`:`seconds`:`milliseconds` + * * Event: Possible values are `Added` or `Removed`. + * * Prefix + * * Flags/meaning: + * * `p`: Preferred flag + * * `a`: Stateless IPv6 address auto-configuration flag. + * * `d`: DHCPv6 IPv6 address configuration flag. + * * `c`: DHCPv6 other-configuration flag. + * * `r`: Default route flag. + * * `o`: On mesh flag. + * * `s`: Stable flag. + * * `n`: Nd Dns flag. + * * `D`: Domain prefix flag. + * * Pref: Preference. Values can be either `high`, `med`, or `low`. + * * RLOC16 + * @sa otHistoryTrackerIterateOnMeshPrefixHistory + */ template <> otError History::Process(Arg aArgs[]) { otError error; @@ -686,6 +1348,45 @@ template <> otError History::Process(Arg aArgs[]) return error; } +/** + * @cli history route + * @code + * history route + * | Age | Event | Route | Flags | Pref | RLOC16 | + * +----------------------+---------+---------------------------------------------+-----------+------+--------+ + * | 00:00:05.456 | Removed | fd00:1111:0::/48 | s | med | 0x3c00 | + * | 00:00:29.310 | Added | fd00:1111:0::/48 | s | med | 0x3c00 | + * | 00:00:42.822 | Added | fd00:1111:0::/48 | s | med | 0x5400 | + * | 00:01:27.688 | Added | fd00:aaaa:bbbb:cccc::/64 | s | med | 0x8800 | + * Done + * @endcode + * @code + * history route list 2 + * 00:00:48.704 -> event:Removed route:fd00:1111:0::/48 flags:s pref:med rloc16:0x3c00 + * 00:01:12.558 -> event:Added route:fd00:1111:0::/48 flags:s pref:med rloc16:0x3c00 + * Done + * @endcode + * @cparam history route [@ca{list}] [@ca{num-entries}] + * * Use the `list` option to display the output in list format. Otherwise, + * the output is shown in table format. + * * Use the `num-entries` option to limit the output to the number of + * most-recent entries specified. If this option is not used, all stored + * entries are shown in the output. + * @par + * Displays the network data external-route history in table or list format. + * @par + * Each table or list entry provides: + * * Age: Time elapsed since the command was issued, and given in the format: + * `hours`:`minutes`:`seconds`:`milliseconds` + * * Event: Possible values are `Added` or `Removed`. + * * Route + * * Flags/meaning: + * * `s`: Stable flag. + * * `n`: NAT64 flag. + * * Pref: Preference. Values can be either `high`, `med`, or `low`. + * * RLOC16 + * @sa otHistoryTrackerIterateExternalRouteHistory + */ template <> otError History::Process(Arg aArgs[]) { otError error; diff --git a/src/cli/cli_ping.cpp b/src/cli/cli_ping.cpp new file mode 100644 index 000000000..80868c789 --- /dev/null +++ b/src/cli/cli_ping.cpp @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2024, 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 the CLI interpreter for Ping Sender function. + */ + +#include "cli_ping.hpp" + +#include + +#include "cli/cli.hpp" +#include "cli/cli_output.hpp" +#include "common/code_utils.hpp" + +#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE + +namespace ot { +namespace Cli { + +PingSender::PingSender(otInstance *aInstance, OutputImplementer &aOutputImplementer) + : Output(aInstance, aOutputImplementer) + , mPingIsAsync(false) +{ +} + +otError PingSender::Process(Arg aArgs[]) +{ + otError error = OT_ERROR_NONE; + otPingSenderConfig config; + bool async = false; + bool nat64SynthesizedAddress; + + /** + * @cli ping stop + * @code + * ping stop + * Done + * @endcode + * @par + * Stop sending ICMPv6 Echo Requests. + * @sa otPingSenderStop + */ + if (aArgs[0] == "stop") + { + otPingSenderStop(GetInstancePtr()); + ExitNow(); + } + else if (aArgs[0] == "async") + { + async = true; + aArgs++; + } + + memset(&config, 0, sizeof(config)); + + if (aArgs[0] == "-I") + { + SuccessOrExit(error = aArgs[1].ParseAsIp6Address(config.mSource)); + +#if !OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + VerifyOrExit(otIp6HasUnicastAddress(GetInstancePtr(), &config.mSource), error = OT_ERROR_INVALID_ARGS); +#endif + aArgs += 2; + } + + if (aArgs[0] == "-m") + { + config.mMulticastLoop = true; + aArgs++; + } + + SuccessOrExit(error = Interpreter::GetInterpreter().ParseToIp6Address( + GetInstancePtr(), aArgs[0], config.mDestination, nat64SynthesizedAddress)); + if (nat64SynthesizedAddress) + { + OutputFormat("Pinging synthesized IPv6 address: "); + OutputIp6AddressLine(config.mDestination); + } + + if (!aArgs[1].IsEmpty()) + { + SuccessOrExit(error = aArgs[1].ParseAsUint16(config.mSize)); + } + + if (!aArgs[2].IsEmpty()) + { + SuccessOrExit(error = aArgs[2].ParseAsUint16(config.mCount)); + } + + if (!aArgs[3].IsEmpty()) + { + SuccessOrExit(error = ParsePingInterval(aArgs[3], config.mInterval)); + } + + if (!aArgs[4].IsEmpty()) + { + SuccessOrExit(error = aArgs[4].ParseAsUint8(config.mHopLimit)); + config.mAllowZeroHopLimit = (config.mHopLimit == 0); + } + + if (!aArgs[5].IsEmpty()) + { + uint32_t timeout; + + SuccessOrExit(error = ParsePingInterval(aArgs[5], timeout)); + VerifyOrExit(timeout <= NumericLimits::kMax, error = OT_ERROR_INVALID_ARGS); + config.mTimeout = static_cast(timeout); + } + + VerifyOrExit(aArgs[6].IsEmpty(), error = OT_ERROR_INVALID_ARGS); + + config.mReplyCallback = PingSender::HandlePingReply; + config.mStatisticsCallback = PingSender::HandlePingStatistics; + config.mCallbackContext = this; + + SuccessOrExit(error = otPingSenderPing(GetInstancePtr(), &config)); + + mPingIsAsync = async; + + if (!async) + { + error = OT_ERROR_PENDING; + } + +exit: + return error; +} + +otError PingSender::ParsePingInterval(const Arg &aArg, uint32_t &aInterval) +{ + otError error = OT_ERROR_NONE; + const char *string = aArg.GetCString(); + const uint32_t msFactor = 1000; + uint32_t factor = msFactor; + + aInterval = 0; + + while (*string) + { + if ('0' <= *string && *string <= '9') + { + // In the case of seconds, change the base of already calculated value. + if (factor == msFactor) + { + aInterval *= 10; + } + + aInterval += static_cast(*string - '0') * factor; + + // In the case of milliseconds, change the multiplier factor. + if (factor != msFactor) + { + factor /= 10; + } + } + else if (*string == '.') + { + // Accept only one dot character. + VerifyOrExit(factor == msFactor, error = OT_ERROR_INVALID_ARGS); + + // Start analyzing hundreds of milliseconds. + factor /= 10; + } + else + { + ExitNow(error = OT_ERROR_INVALID_ARGS); + } + + string++; + } + +exit: + return error; +} + +void PingSender::HandlePingReply(const otPingSenderReply *aReply, void *aContext) +{ + static_cast(aContext)->HandlePingReply(aReply); +} + +void PingSender::HandlePingReply(const otPingSenderReply *aReply) +{ + OutputFormat("%u bytes from ", static_cast(aReply->mSize + sizeof(otIcmp6Header))); + OutputIp6Address(aReply->mSenderAddress); + OutputLine(": icmp_seq=%u hlim=%u time=%ums", aReply->mSequenceNumber, aReply->mHopLimit, aReply->mRoundTripTime); +} + +void PingSender::HandlePingStatistics(const otPingSenderStatistics *aStatistics, void *aContext) +{ + static_cast(aContext)->HandlePingStatistics(aStatistics); +} + +void PingSender::HandlePingStatistics(const otPingSenderStatistics *aStatistics) +{ + OutputFormat("%u packets transmitted, %u packets received.", aStatistics->mSentCount, aStatistics->mReceivedCount); + + if ((aStatistics->mSentCount != 0) && !aStatistics->mIsMulticast && + aStatistics->mReceivedCount <= aStatistics->mSentCount) + { + uint32_t packetLossRate = + 1000 * (aStatistics->mSentCount - aStatistics->mReceivedCount) / aStatistics->mSentCount; + + OutputFormat(" Packet loss = %lu.%u%%.", ToUlong(packetLossRate / 10), + static_cast(packetLossRate % 10)); + } + + if (aStatistics->mReceivedCount != 0) + { + uint32_t avgRoundTripTime = 1000 * aStatistics->mTotalRoundTripTime / aStatistics->mReceivedCount; + + OutputFormat(" Round-trip min/avg/max = %u/%u.%u/%u ms.", aStatistics->mMinRoundTripTime, + static_cast(avgRoundTripTime / 1000), static_cast(avgRoundTripTime % 1000), + aStatistics->mMaxRoundTripTime); + } + + OutputNewLine(); + + if (!mPingIsAsync) + { + OutputResult(OT_ERROR_NONE); + } +} + +void PingSender::OutputResult(otError aError) { Interpreter::GetInterpreter().OutputResult(aError); } + +} // namespace Cli +} // namespace ot + +#endif // OPENTHREAD_CONFIG_PING_SENDER_ENABLE diff --git a/src/cli/cli_ping.hpp b/src/cli/cli_ping.hpp new file mode 100644 index 000000000..e517506bd --- /dev/null +++ b/src/cli/cli_ping.hpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2024, 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 contains definitions for the CLI interpreter for Ping Sneder function. + */ + +#ifndef CLI_PING_SENDER_HPP_ +#define CLI_PING_SENDER_HPP_ + +#include "openthread-core-config.h" + +#include + +#include "cli/cli_output.hpp" + +#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE + +namespace ot { +namespace Cli { + +/** + * Implements the Ping Sender CLI interpreter. + * + */ + +class PingSender : private Output +{ +public: + typedef Utils::CmdLineParser::Arg Arg; + + /** + * Constructor + * + * @param[in] aInstance The OpenThread Instance. + * @param[in] aOutputImplementer An `OutputImplementer`. + * + */ + PingSender(otInstance *aInstance, OutputImplementer &aOutputImplementer); + + /** + * Processes a CLI sub-command. + * + * @param[in] aArgs An array of command line arguments. + * + * @retval OT_ERROR_NONE Successfully executed the CLI command. + * @retval OT_ERROR_PENDING The CLI command was successfully started but final result is pending. + * @retval OT_ERROR_INVALID_COMMAND Invalid or unknown CLI command. + * @retval OT_ERROR_INVALID_ARGS Invalid arguments. + * @retval ... Error during execution of the CLI command. + * + */ + otError Process(Arg aArgs[]); + +private: + otError ParsePingInterval(const Arg &aArg, uint32_t &aInterval); + + static void HandlePingReply(const otPingSenderReply *aReply, void *aContext); + void HandlePingReply(const otPingSenderReply *aReply); + static void HandlePingStatistics(const otPingSenderStatistics *aStatistics, void *aContext); + void HandlePingStatistics(const otPingSenderStatistics *aStatistics); + + void OutputResult(otError aError); + + bool mPingIsAsync : 1; +}; + +} // namespace Cli +} // namespace ot + +#endif // OPENTHREAD_CONFIG_PING_SENDER_ENABLE + +#endif // CLI_PING_SENDER_HPP_ diff --git a/src/cli/cli_srp_client.cpp b/src/cli/cli_srp_client.cpp index 58c9ef457..30ed8d914 100644 --- a/src/cli/cli_srp_client.cpp +++ b/src/cli/cli_srp_client.cpp @@ -81,6 +81,7 @@ template <> otError SrpClient::Process(Arg aArgs[]) * @par * Indicates the current state of auto-start mode (enabled or disabled). * @sa otSrpClientIsAutoStartModeEnabled + * @sa @srp */ if (aArgs[0].IsEmpty()) { @@ -160,6 +161,7 @@ template <> otError SrpClient::Process(Arg aArgs[]) * @par * Gets or enables/disables printing callback events from the SRP client. * @sa otSrpClientSetCallback + * @sa @srp */ template <> otError SrpClient::Process(Arg aArgs[]) { @@ -212,6 +214,7 @@ template <> otError SrpClient::Process(Arg aArgs[]) * @par * Gets or sets the host name of the SRP client. * @sa otSrpClientSetHostName + * @sa @srp */ else if (aArgs[0] == "name") { @@ -286,6 +289,7 @@ template <> otError SrpClient::Process(Arg aArgs[]) * Indicates whether auto address mode is enabled. If auto address mode is not * enabled, then the list of SRP client host addresses is returned. * @sa otSrpClientGetHostInfo + * @sa @srp */ if (aArgs[1].IsEmpty()) { @@ -329,6 +333,7 @@ template <> otError SrpClient::Process(Arg aArgs[]) * addresses. * @sa otSrpClientEnableAutoHostAddress * @sa otSrpClientSetHostAddresses + * @sa @srp */ else if (aArgs[1] == "auto") { @@ -385,6 +390,7 @@ template <> otError SrpClient::Process(Arg aArgs[]) * Removes SRP client host information and all services from the SRP server. * @sa otSrpClientRemoveHostAndServices * @sa otSrpClientSetHostName + * @sa @srp */ else if (aArgs[0] == "remove") { @@ -492,6 +498,7 @@ template <> otError SrpClient::Process(Arg aArgs[]) * that is being used by the SRP client. If the client is not running, the address * is unspecified (all zeros) with a port number of 0. * @sa otSrpClientGetServerAddress + * @sa @srp */ if (aArgs[0].IsEmpty()) { @@ -579,6 +586,7 @@ template <> otError SrpClient::Process(Arg aArgs[]) * @par * Adds a service with a given instance name, service name, and port number. * @sa otSrpClientAddService + * @sa @srp */ else if (aArgs[0] == "add") { @@ -654,6 +662,7 @@ template <> otError SrpClient::Process(Arg aArgs[]) * This command is intended for testing only, and requires that * `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` be enabled. * @sa otSrpClientIsServiceKeyRecordEnabled + * @sa @srp */ else if (aArgs[0] == "key") { @@ -846,6 +855,7 @@ void SrpClient::OutputService(uint8_t aIndentSize, const otSrpClientService &aSe * @par * Starts the SRP client operation. * @sa otSrpClientStart + * @sa @srp */ template <> otError SrpClient::Process(Arg aArgs[]) { @@ -871,6 +881,7 @@ template <> otError SrpClient::Process(Arg aArgs[]) * @endcode * @par api_copy * #otSrpClientIsRunning + * @sa @srp */ template <> otError SrpClient::Process(Arg aArgs[]) { diff --git a/src/cli/cli_srp_server.cpp b/src/cli/cli_srp_server.cpp index 98213d524..1dc6d43c7 100644 --- a/src/cli/cli_srp_server.cpp +++ b/src/cli/cli_srp_server.cpp @@ -117,6 +117,7 @@ template <> otError SrpServer::Process(Arg aArgs[]) * This command requires that `OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE` be enabled. * @sa otSrpServerIsAutoEnableMode * @sa otSrpServerSetAutoEnableMode + * @sa @srp */ template <> otError SrpServer::Process(Arg aArgs[]) { @@ -174,6 +175,7 @@ template <> otError SrpServer::Process(Arg aArgs[]) * SRP servers are no longer active within the Thread network. * * `running`: The SRP server is active and can handle service registrations. * @sa otSrpServerGetState + * @sa @srp */ template <> otError SrpServer::Process(Arg aArgs[]) { @@ -213,6 +215,7 @@ template <> otError SrpServer::Process(Arg aArgs[]) * @par * Enables or disables the SRP server. * @sa otSrpServerSetEnabled + * @sa @srp */ template <> otError SrpServer::Process(Arg aArgs[]) { @@ -312,6 +315,7 @@ template <> otError SrpServer::Process(Arg aArgs[]) * @sa otSrpServerGetNextHost * @sa otSrpServerHostGetAddresses * @sa otSrpServerHostGetFullName + * @sa @srp */ template <> otError SrpServer::Process(Arg aArgs[]) { @@ -414,6 +418,7 @@ void SrpServer::OutputHostAddresses(const otSrpServerHost *aHost) * @sa otSrpServerServiceGetInstanceName * @sa otSrpServerServiceGetServiceName * @sa otSrpServerServiceGetSubTypeServiceNameAt + * @sa @srp */ template <> otError SrpServer::Process(Arg aArgs[]) { diff --git a/src/cli/cli_tcp.cpp b/src/cli/cli_tcp.cpp index ddfc098db..4f3a8d5c7 100644 --- a/src/cli/cli_tcp.cpp +++ b/src/cli/cli_tcp.cpp @@ -324,6 +324,7 @@ template <> otError TcpExample::Process(Arg aArgs[]) * address and port is referred to as "naming the TCP endpoint." This binds the * endpoint for communication. * @sa otTcpBind + * @sa @tcp */ template <> otError TcpExample::Process(Arg aArgs[]) { @@ -369,6 +370,7 @@ template <> otError TcpExample::Process(Arg aArgs[]) * If the connection establishment is successful, the resulting TCP connection * is associated with the example TCP endpoint. * @sa otTcpConnect + * @sa @tcp */ template <> otError TcpExample::Process(Arg aArgs[]) { @@ -449,6 +451,7 @@ template <> otError TcpExample::Process(Arg aArgs[]) * @par * Sends data over the TCP connection associated with the example TCP endpoint * that is provided with the `tcp` CLI. + * @sa @tcp */ template <> otError TcpExample::Process(Arg aArgs[]) { @@ -683,6 +686,7 @@ template <> otError TcpExample::Process(Arg aArgs[]) * Uses the example TCP listener to listen for incoming connections on the * specified IPv6 address and port. * @sa otTcpListen + * @sa @tcp */ template <> otError TcpExample::Process(Arg aArgs[]) { diff --git a/src/cli/ftd.cmake b/src/cli/ftd.cmake index df9b37a3b..7b6f08a00 100644 --- a/src/cli/ftd.cmake +++ b/src/cli/ftd.cmake @@ -31,6 +31,8 @@ add_library(openthread-cli-ftd) target_compile_definitions(openthread-cli-ftd PRIVATE OPENTHREAD_FTD=1 + OPENTHREAD_MTD=0 + OPENTHREAD_RADIO=0 ) target_compile_options(openthread-cli-ftd PRIVATE diff --git a/src/cli/mtd.cmake b/src/cli/mtd.cmake index b5eb1db0f..733bfaaa9 100644 --- a/src/cli/mtd.cmake +++ b/src/cli/mtd.cmake @@ -30,7 +30,9 @@ add_library(openthread-cli-mtd) target_compile_definitions(openthread-cli-mtd PRIVATE + OPENTHREAD_FTD=0 OPENTHREAD_MTD=1 + OPENTHREAD_RADIO=0 ) target_compile_options(openthread-cli-mtd PRIVATE diff --git a/src/cli/radio.cmake b/src/cli/radio.cmake index 28320d6a3..449f99612 100644 --- a/src/cli/radio.cmake +++ b/src/cli/radio.cmake @@ -30,6 +30,8 @@ add_library(openthread-cli-radio) target_compile_definitions(openthread-cli-radio PRIVATE + OPENTHREAD_FTD=0 + OPENTHREAD_MTD=0 OPENTHREAD_RADIO=1 OPENTHREAD_RADIO_CLI=1 ) diff --git a/src/core/BUILD.gn b/src/core/BUILD.gn index 5263637bd..f4fa5db94 100644 --- a/src/core/BUILD.gn +++ b/src/core/BUILD.gn @@ -825,6 +825,7 @@ source_set("libopenthread_core_config") { "config/srp_server.h", "config/time_sync.h", "config/tmf.h", + "config/trel.h", "openthread-core-config.h", ] public_configs = [ diff --git a/src/core/api/coap_secure_api.cpp b/src/core/api/coap_secure_api.cpp index 86f76b4c9..2ba31a262 100644 --- a/src/core/api/coap_secure_api.cpp +++ b/src/core/api/coap_secure_api.cpp @@ -171,7 +171,7 @@ void otCoapSecureSetClientConnectedCallback(otInstance *aIns otHandleCoapSecureClientConnect aHandler, void *aContext) { - AsCoreType(aInstance).GetApplicationCoapSecure().SetClientConnectedCallback(aHandler, aContext); + AsCoreType(aInstance).GetApplicationCoapSecure().SetConnectedCallback(aHandler, aContext); } void otCoapSecureSetDefaultHandler(otInstance *aInstance, otCoapRequestHandler aHandler, void *aContext) diff --git a/src/core/api/trel_api.cpp b/src/core/api/trel_api.cpp index 687c1169c..09344d3d1 100644 --- a/src/core/api/trel_api.cpp +++ b/src/core/api/trel_api.cpp @@ -60,6 +60,11 @@ const otTrelPeer *otTrelGetNextPeer(otInstance *aInstance, otTrelPeerIterator *a return AsCoreType(aInstance).Get().GetNextPeer(*aIterator); } +uint16_t otTrelGetNumberOfPeers(otInstance *aInstance) +{ + return AsCoreType(aInstance).Get().GetNumberOfPeers(); +} + void otTrelSetFilterEnabled(otInstance *aInstance, bool aEnable) { AsCoreType(aInstance).Get().SetFilterEnabled(aEnable); @@ -70,4 +75,11 @@ bool otTrelIsFilterEnabled(otInstance *aInstance) return AsCoreType(aInstance).Get().IsFilterEnabled(); } +const otTrelCounters *otTrelGetCounters(otInstance *aInstance) +{ + return AsCoreType(aInstance).Get().GetCounters(); +} + +void otTrelResetCounters(otInstance *aInstance) { AsCoreType(aInstance).Get().ResetCounters(); } + #endif // OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp index e981af508..4173626e4 100644 --- a/src/core/border_router/routing_manager.cpp +++ b/src/core/border_router/routing_manager.cpp @@ -72,8 +72,7 @@ RoutingManager::RoutingManager(Instance &aInstance) , mIsEnabled(false) , mInfraIf(aInstance) , mOmrPrefixManager(aInstance) - , mRioPreference(NetworkData::kRoutePreferenceLow) - , mUserSetRioPreference(false) + , mRioAdvertiser(aInstance) , mOnLinkPrefixManager(aInstance) , mDiscoveredPrefixTable(aInstance) , mRoutePublisher(aInstance) @@ -153,45 +152,6 @@ RoutingManager::State RoutingManager::GetState(void) const return state; } -void RoutingManager::SetRouteInfoOptionPreference(RoutePreference aPreference) -{ - LogInfo("User explicitly set RIO Preference to %s", RoutePreferenceToString(aPreference)); - mUserSetRioPreference = true; - UpdateRioPreference(aPreference); -} - -void RoutingManager::ClearRouteInfoOptionPreference(void) -{ - VerifyOrExit(mUserSetRioPreference); - - LogInfo("User cleared explicitly set RIO Preference"); - mUserSetRioPreference = false; - SetRioPreferenceBasedOnRole(); - -exit: - return; -} - -void RoutingManager::SetRioPreferenceBasedOnRole(void) -{ - UpdateRioPreference(Get().IsRouterOrLeader() ? NetworkData::kRoutePreferenceMedium - : NetworkData::kRoutePreferenceLow); -} - -void RoutingManager::UpdateRioPreference(RoutePreference aPreference) -{ - VerifyOrExit(mRioPreference != aPreference); - - LogInfo("RIO Preference changed: %s -> %s", RoutePreferenceToString(mRioPreference), - RoutePreferenceToString(aPreference)); - mRioPreference = aPreference; - - ScheduleRoutingPolicyEvaluation(kAfterRandomDelay); - -exit: - return; -} - Error RoutingManager::GetOmrPrefix(Ip6::Prefix &aPrefix) const { Error error = kErrorNone; @@ -377,12 +337,6 @@ void RoutingManager::Stop(void) SendRouterAdvertisement(kInvalidateAllPrevPrefixes); -#if OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE - mAdvertisedPrefixes.Free(); -#else - mAdvertisedPrefixes.Clear(); -#endif - mDiscoveredPrefixTable.RemoveAllEntries(); mDiscoveredPrefixStaleTimer.Stop(); @@ -457,9 +411,9 @@ void RoutingManager::HandleReceived(const InfraIf::Icmp6Packet &aPacket, const I void RoutingManager::HandleNotifierEvents(Events aEvents) { - if (aEvents.Contains(kEventThreadRoleChanged) && !mUserSetRioPreference) + if (aEvents.Contains(kEventThreadRoleChanged)) { - SetRioPreferenceBasedOnRole(); + mRioAdvertiser.HandleRoleChanged(); } mRoutePublisher.HandleNotifierEvents(aEvents); @@ -620,19 +574,18 @@ void RoutingManager::SendRouterAdvertisement(RouterAdvTxMode aRaTxMode) // - One RA Flags Extensions Option (with stub router flag). // - One PIO for current local on-link prefix. // - At most `kMaxOldPrefixes` for old deprecating on-link prefixes. - // - At most twice `kMaxOnMeshPrefixes` RIO for on-mesh prefixes. - // Factor two is used for RIO to account for entries invalidating - // previous prefixes while adding new ones. + // - At most 3 times `kMaxOnMeshPrefixes` RIO for on-mesh prefixes. + // Factor three is used for RIOs to account for any new prefix + // with older prefixes entries being deprecated and prefixes + // being invalidated. static constexpr uint16_t kMaxRaLength = sizeof(Ip6::Nd::RouterAdvertMessage::Header) + sizeof(Ip6::Nd::RaFlagsExtOption) + sizeof(Ip6::Nd::PrefixInfoOption) + sizeof(Ip6::Nd::PrefixInfoOption) * OnLinkPrefixManager::kMaxOldPrefixes + - 2 * kMaxOnMeshPrefixes * (sizeof(Ip6::Nd::RouteInfoOption) + sizeof(Ip6::Prefix)); + 3 * kMaxOnMeshPrefixes * (sizeof(Ip6::Nd::RouteInfoOption) + sizeof(Ip6::Prefix)); - uint8_t buffer[kMaxRaLength]; - Ip6::Nd::RouterAdvertMessage raMsg(mRaInfo.mHeader, buffer); - NetworkData::Iterator iterator; - NetworkData::OnMeshPrefixConfig prefixConfig; + uint8_t buffer[kMaxRaLength]; + Ip6::Nd::RouterAdvertMessage raMsg(mRaInfo.mHeader, buffer); LogInfo("Preparing RA"); @@ -653,119 +606,13 @@ void RoutingManager::SendRouterAdvertisement(RouterAdvTxMode aRaTxMode) mOnLinkPrefixManager.AppendAsPiosTo(raMsg); - // Determine which previously advertised prefixes need to be - // invalidated. Under `kInvalidateAllPrevPrefixes` mode we need - // to invalidate all. Under `kAdvPrefixesFromNetData` mode, we - // check Network Data entries and invalidate any previously - // advertised prefix that is no longer present in the Network - // Data. We go through all Network Data prefixes and mark the - // ones we find in `mAdvertisedPrefixes` as deleted by setting - // the prefix length to zero). By the end, the remaining entries - // in the array with a non-zero prefix length are invalidated. - - if (aRaTxMode != kInvalidateAllPrevPrefixes) + if (aRaTxMode == kInvalidateAllPrevPrefixes) { - iterator = NetworkData::kIteratorInit; - - while (Get().GetNextOnMeshPrefix(iterator, prefixConfig) == kErrorNone) - { - if (!prefixConfig.mOnMesh || prefixConfig.mDp || - (prefixConfig.GetPrefix() == mOmrPrefixManager.GetLocalPrefix().GetPrefix())) - { - continue; - } - - mAdvertisedPrefixes.MarkAsDeleted(prefixConfig.GetPrefix()); - } - - if (mOmrPrefixManager.IsLocalAddedInNetData()) - { - mAdvertisedPrefixes.MarkAsDeleted(mOmrPrefixManager.GetLocalPrefix().GetPrefix()); - } + mRioAdvertiser.InvalidatPrevRios(raMsg); } - - for (const OnMeshPrefix &prefix : mAdvertisedPrefixes) - { - if (prefix.GetLength() != 0) - { - SuccessOrAssert(raMsg.AppendRouteInfoOption(prefix, /* aRouteLifetime */ 0, mRioPreference)); - LogRouteInfoOption(prefix, 0, mRioPreference); - } - } - - // Discover and add prefixes from Network Data to advertise as - // RIO in the Router Advertisement message. - - mAdvertisedPrefixes.Clear(); - - if (aRaTxMode == kAdvPrefixesFromNetData) + else { - // `mAdvertisedPrefixes` array has a limited size. We add more - // important prefixes first in the array to ensure they are - // advertised in the RA message. Note that `Add()` method - // will ensure to add a prefix only once (will check if - // prefix is already present in the array). - - // (1) Local OMR prefix. - - if (mOmrPrefixManager.IsLocalAddedInNetData()) - { - mAdvertisedPrefixes.Add(mOmrPrefixManager.GetLocalPrefix().GetPrefix()); - } - - // (2) Favored OMR prefix. - - if (!mOmrPrefixManager.GetFavoredPrefix().IsEmpty() && !mOmrPrefixManager.GetFavoredPrefix().IsDomainPrefix()) - { - mAdvertisedPrefixes.Add(mOmrPrefixManager.GetFavoredPrefix().GetPrefix()); - } - - // (3) All other OMR prefixes. - - iterator = NetworkData::kIteratorInit; - - while (Get().GetNextOnMeshPrefix(iterator, prefixConfig) == kErrorNone) - { - // Local OMR prefix is added to the array depending on - // `mOmrPrefixManager.IsLocalAddedInNetData()` at step (1). - // As we iterate through the Network Data prefixes, we skip - // over entries matching the local OMR prefix. This - // ensures that we stop including it in emitted RA - // message as soon as we decide to remove it from Network - // Data. Note that upon requesting it to be removed from - // Network Data the change needs to be registered with - // leader and can take some time to be updated in Network - // Data. - - if (prefixConfig.mDp) - { - continue; - } - - if (IsValidOmrPrefix(prefixConfig) && - (prefixConfig.GetPrefix() != mOmrPrefixManager.GetLocalPrefix().GetPrefix())) - { - mAdvertisedPrefixes.Add(prefixConfig.GetPrefix()); - } - } - - // (4) All other on-mesh prefixes (excluding Domain Prefix). - - iterator = NetworkData::kIteratorInit; - - while (Get().GetNextOnMeshPrefix(iterator, prefixConfig) == kErrorNone) - { - if (prefixConfig.mOnMesh && !prefixConfig.mDp && !IsValidOmrPrefix(prefixConfig)) - { - mAdvertisedPrefixes.Add(prefixConfig.GetPrefix()); - } - } - - for (const OnMeshPrefix &prefix : mAdvertisedPrefixes) - { - SuccessOrAssert(raMsg.AppendRouteInfoOption(prefix, kDefaultOmrPrefixLifetime, mRioPreference)); - LogRouteInfoOption(prefix, kDefaultOmrPrefixLifetime, mRioPreference); - } + mRioAdvertiser.AppendRios(raMsg); } if (raMsg.ContainsAnyOptions()) @@ -831,9 +678,9 @@ bool RoutingManager::IsReceivedRouterAdvertFromManager(const Ip6::Nd::RouterAdve case Ip6::Nd::Option::kTypeRouteInfo: { // RIO (with non-zero lifetime) should match entries from - // `mAdvertisedPrefixes`. We keep track of the number - // of matched RIOs and check after the loop ends that all - // entries were seen. + // `mRioAdvertiser`. We keep track of the number of matched + // RIOs and check after the loop ends that all entries were + // seen. const Ip6::Nd::RouteInfoOption &rio = static_cast(option); @@ -842,7 +689,7 @@ bool RoutingManager::IsReceivedRouterAdvertFromManager(const Ip6::Nd::RouterAdve if (rio.GetRouteLifetime() != 0) { - VerifyOrExit(mAdvertisedPrefixes.Contains(prefix)); + VerifyOrExit(mRioAdvertiser.HasAdvertised(prefix)); rioCount++; } @@ -854,7 +701,7 @@ bool RoutingManager::IsReceivedRouterAdvertFromManager(const Ip6::Nd::RouterAdve } } - VerifyOrExit(rioCount == mAdvertisedPrefixes.GetLength()); + VerifyOrExit(rioCount == mRioAdvertiser.GetAdvertisedRioCount()); isFromManager = true; @@ -1023,16 +870,16 @@ bool RoutingManager::ShouldProcessRouteInfoOption(const Ip6::Nd::RouteInfoOption VerifyOrExit(mOmrPrefixManager.GetLocalPrefix().GetPrefix() != aPrefix); // Ignore OMR prefixes advertised by ourselves or in current Thread Network Data. - // The `mAdvertisedPrefixes` and the OMR prefix set in Network Data should eventually + // The `RioAdvertiser` prefixes and the OMR prefix set in Network Data should eventually // be equal, but there is time that they are not synchronized immediately: - // 1. Network Data could contain more OMR prefixes than `mAdvertisedPrefixes` because + // 1. Network Data could contain more OMR prefixes than `RioAdvertiser` because // we added random delay before Evaluating routing policy when Network Data is changed. - // 2. `mAdvertisedPrefixes` could contain more OMR prefixes than Network Data because + // 2. `RioAdvertiser` prefixes could contain more OMR prefixes than Network Data because // it takes time to sync a new OMR prefix into Network Data (multicast loopback RA // messages are usually faster than Thread Network Data propagation). // They are the reasons why we need both the checks. - VerifyOrExit(!mAdvertisedPrefixes.Contains(aPrefix)); + VerifyOrExit(!mRioAdvertiser.HasAdvertised(aPrefix)); VerifyOrExit(!Get().NetworkDataContainsOmrPrefix(aPrefix)); shouldProcess = true; @@ -2238,6 +2085,45 @@ void RoutingManager::OmrPrefixManager::Evaluate(void) return; } +bool RoutingManager::OmrPrefixManager::ShouldAdvertiseLocalAsRio(void) const +{ + // Determines whether the local OMR prefix should be advertised as + // RIO in emitted RAs. To advertise, we must have decided to + // publish it, and it must already be added and present in the + // Network Data. This ensures that we only advertise the local + // OMR prefix in emitted RAs when, as a Border Router, we can + // accept and route messages using an OMR-based address + // destination, which requires the prefix to be present in + // Network Data. Similarly, we stop advertising (and start + // deprecating) the OMR prefix in RAs as soon as we decide to + // remove it. After requesting its removal from Network Data, it + // may still be present in Network Data for a short interval due + // to delays in registering changes with the leader. + + bool shouldAdvertise = false; + NetworkData::Iterator iterator = NetworkData::kIteratorInit; + NetworkData::OnMeshPrefixConfig prefixConfig; + + VerifyOrExit(mIsLocalAddedInNetData); + + while (Get().GetNextOnMeshPrefix(iterator, prefixConfig) == kErrorNone) + { + if (!IsValidOmrPrefix(prefixConfig)) + { + continue; + } + + if (prefixConfig.GetPrefix() == mLocalPrefix.GetPrefix()) + { + shouldAdvertise = true; + break; + } + } + +exit: + return shouldAdvertise; +} + Error RoutingManager::OmrPrefixManager::AddLocalToNetData(void) { Error error = kErrorNone; @@ -2878,39 +2764,241 @@ const char *RoutingManager::OnLinkPrefixManager::StateToString(State aState) } //--------------------------------------------------------------------------------------------------------------------- -// OnMeshPrefixArray +// RioAdvertiser -void RoutingManager::OnMeshPrefixArray::Add(const OnMeshPrefix &aPrefix) +RoutingManager::RioAdvertiser::RioAdvertiser(Instance &aInstance) + : InstanceLocator(aInstance) + , mTimer(aInstance) + , mPreference(NetworkData::kRoutePreferenceLow) + , mUserSetPreference(false) { - // Checks if `aPrefix` is already present in the array and if not - // adds it as new entry. +} - Error error; +void RoutingManager::RioAdvertiser::SetPreference(RoutePreference aPreference) +{ + LogInfo("User explicitly set RIO Preference to %s", RoutePreferenceToString(aPreference)); + mUserSetPreference = true; + UpdatePreference(aPreference); +} - VerifyOrExit(!Contains(aPrefix)); +void RoutingManager::RioAdvertiser::ClearPreference(void) +{ + VerifyOrExit(mUserSetPreference); - error = PushBack(aPrefix); + LogInfo("User cleared explicitly set RIO Preference"); + mUserSetPreference = false; + SetPreferenceBasedOnRole(); - if (error != kErrorNone) +exit: + return; +} + +void RoutingManager::RioAdvertiser::HandleRoleChanged(void) +{ + if (!mUserSetPreference) { - LogWarn("Too many on-mesh prefixes in net data, ignoring prefix %s", aPrefix.ToString().AsCString()); + SetPreferenceBasedOnRole(); } +} + +void RoutingManager::RioAdvertiser::SetPreferenceBasedOnRole(void) +{ + UpdatePreference(Get().IsRouterOrLeader() ? NetworkData::kRoutePreferenceMedium + : NetworkData::kRoutePreferenceLow); +} + +void RoutingManager::RioAdvertiser::UpdatePreference(RoutePreference aPreference) +{ + VerifyOrExit(mPreference != aPreference); + + LogInfo("RIO Preference changed: %s -> %s", RoutePreferenceToString(mPreference), + RoutePreferenceToString(aPreference)); + mPreference = aPreference; + + Get().ScheduleRoutingPolicyEvaluation(kAfterRandomDelay); exit: return; } -void RoutingManager::OnMeshPrefixArray::MarkAsDeleted(const OnMeshPrefix &aPrefix) +void RoutingManager::RioAdvertiser::InvalidatPrevRios(Ip6::Nd::RouterAdvertMessage &aRaMessage) { - // Searches for a matching entry to `aPrefix` and if found marks - // it as deleted by setting prefix length to zero. + for (const RioPrefix &prefix : mPrefixes) + { + AppendRio(prefix.mPrefix, /* aRouteLifetime */ 0, aRaMessage); + } - OnMeshPrefix *entry = Find(aPrefix); +#if OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE + mPrefixes.Free(); +#endif - if (entry != nullptr) + mPrefixes.Clear(); + mTimer.Stop(); +} + +void RoutingManager::RioAdvertiser::AppendRios(Ip6::Nd::RouterAdvertMessage &aRaMessage) +{ + TimeMilli now = TimerMilli::GetNow(); + TimeMilli nextTime = now.GetDistantFuture(); + RioPrefixArray oldPrefixes; + NetworkData::Iterator iterator = NetworkData::kIteratorInit; + NetworkData::OnMeshPrefixConfig prefixConfig; + const OmrPrefixManager &omrPrefixManager = Get().mOmrPrefixManager; + +#if OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE + oldPrefixes.TakeFrom(static_cast(mPrefixes)); +#else + oldPrefixes = mPrefixes; +#endif + + mPrefixes.Clear(); + + // `mPrefixes` array can have a limited size. We add more + // important prefixes first in the array to ensure they are + // advertised in the RA message. Note that `Add()` method + // will ensure to add a prefix only once (will check if + // prefix is already present in the array). + + // (1) Local OMR prefix. + + if (omrPrefixManager.ShouldAdvertiseLocalAsRio()) + { + mPrefixes.Add(omrPrefixManager.GetLocalPrefix().GetPrefix()); + } + + // (2) Favored OMR prefix. + + if (!omrPrefixManager.GetFavoredPrefix().IsEmpty() && !omrPrefixManager.GetFavoredPrefix().IsDomainPrefix()) + { + mPrefixes.Add(omrPrefixManager.GetFavoredPrefix().GetPrefix()); + } + + // (3) All other OMR prefixes. + + iterator = NetworkData::kIteratorInit; + + while (Get().GetNextOnMeshPrefix(iterator, prefixConfig) == kErrorNone) + { + // Decision on whether or not to include the local OMR prefix is + // delegated to `OmrPrefixManager.ShouldAdvertiseLocalAsRio()` + // at step (1). Here as we iterate over the Network Data + // prefixes, we skip entries matching the local OMR prefix. + // In particular, `OmrPrefixManager` may have decided to remove the + // local prefix and not advertise it anymore, but it may still be + // present in the Network Data (due to delay of registering changes + // with leader). + + if (prefixConfig.mDp) + { + continue; + } + + if (IsValidOmrPrefix(prefixConfig) && + (prefixConfig.GetPrefix() != omrPrefixManager.GetLocalPrefix().GetPrefix())) + { + mPrefixes.Add(prefixConfig.GetPrefix()); + } + } + + // (4) All other on-mesh prefixes (excluding Domain Prefix). + + iterator = NetworkData::kIteratorInit; + + while (Get().GetNextOnMeshPrefix(iterator, prefixConfig) == kErrorNone) + { + if (prefixConfig.mOnMesh && !prefixConfig.mDp && !IsValidOmrPrefix(prefixConfig)) + { + mPrefixes.Add(prefixConfig.GetPrefix()); + } + } + + // Determine deprecating prefixes + + for (RioPrefix &prefix : oldPrefixes) { - entry->SetLength(0); + if (mPrefixes.ContainsMatching(prefix.mPrefix)) + { + continue; + } + + if (prefix.mIsDeprecating) + { + if (now >= prefix.mExpirationTime) + { + AppendRio(prefix.mPrefix, /* aRouteLifetime */ 0, aRaMessage); + continue; + } + } + else + { + prefix.mIsDeprecating = true; + prefix.mExpirationTime = now + kDeprecationTime; + } + + if (mPrefixes.PushBack(prefix) != kErrorNone) + { + LogWarn("Too many deprecating on-mesh prefixes, removing %s", prefix.mPrefix.ToString().AsCString()); + AppendRio(prefix.mPrefix, /* aRouteLifetime */ 0, aRaMessage); + } + + nextTime = Min(nextTime, prefix.mExpirationTime); } + + // Advertise all prefixes in `mPrefixes` + + for (const RioPrefix &prefix : mPrefixes) + { + uint32_t lifetime = kDefaultOmrPrefixLifetime; + + if (prefix.mIsDeprecating) + { + lifetime = TimeMilli::MsecToSec(prefix.mExpirationTime - now); + } + + AppendRio(prefix.mPrefix, lifetime, aRaMessage); + } + + if (nextTime != now.GetDistantFuture()) + { + mTimer.FireAtIfEarlier(nextTime); + } +} + +void RoutingManager::RioAdvertiser::AppendRio(const Ip6::Prefix &aPrefix, + uint32_t aRouteLifetime, + Ip6::Nd::RouterAdvertMessage &aRaMessage) +{ + SuccessOrAssert(aRaMessage.AppendRouteInfoOption(aPrefix, aRouteLifetime, mPreference)); + LogRouteInfoOption(aPrefix, aRouteLifetime, mPreference); +} + +void RoutingManager::RioAdvertiser::HandleTimer(void) +{ + Get().ScheduleRoutingPolicyEvaluation(kImmediately); +} + +void RoutingManager::RioAdvertiser::RioPrefixArray::Add(const Ip6::Prefix &aPrefix) +{ + // Checks if `aPrefix` is already present in the array and if not + // adds it as a new entry. + + Error error; + RioPrefix newEntry; + + VerifyOrExit(!ContainsMatching(aPrefix)); + + newEntry.Clear(); + newEntry.mPrefix = aPrefix; + + error = PushBack(newEntry); + + if (error != kErrorNone) + { + LogWarn("Too many on-mesh prefixes in net data, ignoring prefix %s", aPrefix.ToString().AsCString()); + } + +exit: + return; } //--------------------------------------------------------------------------------------------------------------------- @@ -3672,7 +3760,7 @@ void RoutingManager::PdPrefixManager::SetEnabled(bool aEnabled) extern "C" void otPlatBorderRoutingProcessIcmp6Ra(otInstance *aInstance, const uint8_t *aMessage, uint16_t aLength) { - AsCoreType(aInstance).Get().ProcessPlatfromGeneratedRa(aMessage, aLength); + AsCoreType(aInstance).Get().ProcessPlatformGeneratedRa(aMessage, aLength); } #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp index 95a86f0e0..4aef01d91 100644 --- a/src/core/border_router/routing_manager.hpp +++ b/src/core/border_router/routing_manager.hpp @@ -209,7 +209,7 @@ class RoutingManager : public InstanceLocator * @returns The current Route Info Option preference. * */ - RoutePreference GetRouteInfoOptionPreference(void) const { return mRioPreference; } + RoutePreference GetRouteInfoOptionPreference(void) const { return mRioAdvertiser.GetPreference(); } /** * Explicitly sets the preference to use when advertising Route Info Options (RIO) in Router @@ -221,7 +221,7 @@ class RoutingManager : public InstanceLocator * @param[in] aPreference The route preference to use. * */ - void SetRouteInfoOptionPreference(RoutePreference aPreference); + void SetRouteInfoOptionPreference(RoutePreference aPreference) { mRioAdvertiser.SetPreference(aPreference); } /** * Clears a previously set preference value for advertised Route Info Options. @@ -230,7 +230,7 @@ class RoutingManager : public InstanceLocator * in router/leader role and low preference when in child role. * */ - void ClearRouteInfoOptionPreference(void); + void ClearRouteInfoOptionPreference(void) { mRioAdvertiser.ClearPreference(); } /** * Gets the current preference used for published routes in Network Data. @@ -283,7 +283,7 @@ class RoutingManager : public InstanceLocator /** * Returns the platform provided off-mesh-routable (OMR) prefix. * - * The prefix is extracted from the platform generated RA messages handled by `ProcessPlatfromGeneratedNd()`. + * The prefix is extracted from the platform generated RA messages handled by `ProcessPlatformGeneratedNd()`. * * @param[out] aPrefixInfo A reference to where the prefix info will be output to. * @@ -517,7 +517,7 @@ class RoutingManager : public InstanceLocator * @param[in] aLength The length of the router advertisement message. * */ - void ProcessPlatfromGeneratedRa(const uint8_t *aRouterAdvert, uint16_t aLength) + void ProcessPlatformGeneratedRa(const uint8_t *aRouterAdvert, uint16_t aLength) { mPdPrefixManager.ProcessPlatformGeneratedRa(aRouterAdvert, aLength); } @@ -909,7 +909,7 @@ class RoutingManager : public InstanceLocator void Stop(void); void Evaluate(void); void UpdateDefaultRouteFlag(bool aDefaultRoute); - bool IsLocalAddedInNetData(void) const { return mIsLocalAddedInNetData; } + bool ShouldAdvertiseLocalAsRio(void) const; const Ip6::Prefix &GetGeneratedPrefix(void) const { return mGeneratedPrefix; } const OmrPrefix &GetLocalPrefix(void) const { return mLocalPrefix; } const FavoredOmrPrefix &GetFavoredPrefix(void) const { return mFavoredPrefix; } @@ -997,18 +997,60 @@ class RoutingManager : public InstanceLocator ExpireTimer mTimer; }; - typedef Ip6::Prefix OnMeshPrefix; + void HandleRioAdvertiserimer(void) { mRioAdvertiser.HandleTimer(); } - class OnMeshPrefixArray : + class RioAdvertiser : public InstanceLocator + { + // Manages the list of prefixes advertised as RIO in emitted + // RA. The RIO prefixes are discovered from on-mesh prefixes in + // network data including OMR prefix from `OmrPrefixManager`. + // It also handles deprecating removed prefixes. + + public: + explicit RioAdvertiser(Instance &aInstance); + + RoutePreference GetPreference(void) const { return mPreference; } + void SetPreference(RoutePreference aPreference); + void ClearPreference(void); + void HandleRoleChanged(void); + void AppendRios(Ip6::Nd::RouterAdvertMessage &aRaMessage); + void InvalidatPrevRios(Ip6::Nd::RouterAdvertMessage &aRaMessage); + bool HasAdvertised(const Ip6::Prefix &aPrefix) const { return mPrefixes.ContainsMatching(aPrefix); } + uint16_t GetAdvertisedRioCount(void) const { return mPrefixes.GetLength(); } + void HandleTimer(void); + + private: + static constexpr uint32_t kDeprecationTime = TimeMilli::SecToMsec(300); + + struct RioPrefix : public Clearable + { + bool Matches(const Ip6::Prefix &aPrefix) const { return (mPrefix == aPrefix); } + + Ip6::Prefix mPrefix; + bool mIsDeprecating; + TimeMilli mExpirationTime; + }; + + struct RioPrefixArray : #if OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE - public Heap::Array + public Heap::Array #else - public Array + public Array #endif - { - public: - void Add(const OnMeshPrefix &aPrefix); - void MarkAsDeleted(const OnMeshPrefix &aPrefix); + { + void Add(const Ip6::Prefix &aPrefix); + }; + + void SetPreferenceBasedOnRole(void); + void UpdatePreference(RoutePreference aPreference); + void AppendRio(const Ip6::Prefix &aPrefix, uint32_t aRouteLifetime, Ip6::Nd::RouterAdvertMessage &aRaMessage); + + using RioTimer = TimerMilliIn; + + RioPrefixArray mPrefixes; + RioTimer mTimer; + RoutePreference mPreference; + bool mUserSetPreference; }; #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE @@ -1227,8 +1269,6 @@ class RoutingManager : public InstanceLocator void HandleNotifierEvents(Events aEvents); bool IsInitialized(void) const { return mInfraIf.IsInitialized(); } bool IsEnabled(void) const { return mIsEnabled; } - void SetRioPreferenceBasedOnRole(void); - void UpdateRioPreference(RoutePreference aPreference); Error LoadOrGenerateRandomBrUlaPrefix(void); void EvaluateRoutingPolicy(void); @@ -1276,10 +1316,7 @@ class RoutingManager : public InstanceLocator OmrPrefixManager mOmrPrefixManager; - // List of on-mesh prefixes (discovered from Network Data) which - // were advertised as RIO in the last sent RA message. - OnMeshPrefixArray mAdvertisedPrefixes; - + RioAdvertiser mRioAdvertiser; RoutePreference mRioPreference; bool mUserSetRioPreference; diff --git a/src/core/coap/coap_secure.hpp b/src/core/coap/coap_secure.hpp index 50a1d4521..e34ce89ea 100644 --- a/src/core/coap/coap_secure.hpp +++ b/src/core/coap/coap_secure.hpp @@ -258,18 +258,6 @@ class CoapSecure : public CoapBase } #endif // defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) - /** - * Sets the connected callback to indicate, when a Client connect to the CoAP Secure server. - * - * @param[in] aCallback A pointer to a function that will be called once DTLS connection is established. - * @param[in] aContext A pointer to arbitrary context information. - * - */ - void SetClientConnectedCallback(ConnectedCallback aCallback, void *aContext) - { - mConnectedCallback.Set(aCallback, aContext); - } - /** * Sets the authentication mode for the CoAP secure connection. It disables or enables the verification * of peer certificate. @@ -382,7 +370,7 @@ class CoapSecure : public CoapBase */ void HandleUdpReceive(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { - return mDtls.HandleUdpReceive(aMessage, aMessageInfo); + return mDtls.HandleReceive(aMessage, aMessageInfo); } /** diff --git a/src/core/common/heap_data.cpp b/src/core/common/heap_data.cpp index d12686e2c..9c09e5903 100644 --- a/src/core/common/heap_data.cpp +++ b/src/core/common/heap_data.cpp @@ -78,6 +78,25 @@ void Data::SetFrom(Data &&aData) TakeFrom(aData); } +bool Data::Matches(const uint8_t *aBuffer, uint16_t aLength) const +{ + bool matches = false; + + VerifyOrExit(aLength == mData.GetLength()); + + if (IsNull()) + { + matches = (aLength == 0); + } + else + { + matches = mData.MatchesBytesIn(aBuffer); + } + +exit: + return matches; +} + void Data::Free(void) { Heap::Free(mData.GetBytes()); diff --git a/src/core/common/heap_data.hpp b/src/core/common/heap_data.hpp index 9fbbe3d42..f0b0823ed 100644 --- a/src/core/common/heap_data.hpp +++ b/src/core/common/heap_data.hpp @@ -169,6 +169,18 @@ class Data */ void CopyBytesTo(uint8_t *aBuffer) const { return mData.CopyBytesTo(aBuffer); } + /** + * Compares the `Data` content with the bytes from a given buffer. + * + * @param[in] aBuffer A pointer to a buffer to compare with the data. + * @param[in] aLength The length of @p aBuffer. + * + * @retval TRUE The `Data` content matches the bytes in @p aBuffer. + * @retval FALSE The `Data` content does not match the byes in @p aBuffer. + * + */ + bool Matches(const uint8_t *aBuffer, uint16_t aLength) const; + /** * Frees any buffer allocated by the `Heap::Data`. * diff --git a/src/core/config/announce_sender.h b/src/core/config/announce_sender.h index b71d88e7a..7d6b8ae28 100644 --- a/src/core/config/announce_sender.h +++ b/src/core/config/announce_sender.h @@ -28,13 +28,23 @@ /** * @file - * This file includes compile-time configurations for the DNS Client. + * This file includes compile-time configurations for the Announce Sender. * */ #ifndef CONFIG_ANNOUNCE_SENDER_H_ #define CONFIG_ANNOUNCE_SENDER_H_ +/** + * @addtogroup config-announce-sender + * + * @brief + * This module includes configuration variables for the Announce Sender. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_ANNOUNCE_SENDER_ENABLE * @@ -90,4 +100,9 @@ #define OPENTHREAD_CONFIG_ANNOUNCE_SENDER_JITTER_INTERVAL 500 #endif +/** + * @} + * + */ + #endif // CONFIG_ANNOUNCE_SENDER_H_ diff --git a/src/core/config/backbone_router.h b/src/core/config/backbone_router.h index e2bdbd338..398e0059c 100644 --- a/src/core/config/backbone_router.h +++ b/src/core/config/backbone_router.h @@ -35,6 +35,16 @@ #ifndef CONFIG_BACKBONE_ROUTER_H_ #define CONFIG_BACKBONE_ROUTER_H_ +/** + * @addtogroup config-backbone-router + * + * @brief + * This module includes configuration variables for Backbone Router services. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE * @@ -113,4 +123,9 @@ #define OPENTHREAD_CONFIG_NDPROXY_TABLE_ENTRY_NUM 250 #endif +/** + * @} + * + */ + #endif // CONFIG_BACKBONE_ROUTER_H_ diff --git a/src/core/config/border_agent.h b/src/core/config/border_agent.h index c7bb8df3a..5769fe177 100644 --- a/src/core/config/border_agent.h +++ b/src/core/config/border_agent.h @@ -35,6 +35,16 @@ #ifndef CONFIG_BORDER_AGENT_H_ #define CONFIG_BORDER_AGENT_H_ +/** + * @addtogroup config-border-agent + * + * @brief + * This module includes configuration variables for Border Agent. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE * @@ -65,4 +75,9 @@ #define OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE 0 #endif +/** + * @} + * + */ + #endif // CONFIG_BORDER_AGENT_H_ diff --git a/src/core/config/border_router.h b/src/core/config/border_router.h index 543ea8fed..d1586742d 100644 --- a/src/core/config/border_router.h +++ b/src/core/config/border_router.h @@ -35,6 +35,16 @@ #ifndef CONFIG_BORDER_ROUTER_H_ #define CONFIG_BORDER_ROUTER_H_ +/** + * @addtogroup config-border-router + * + * @brief + * This module includes configuration variables for Border Router services. + * + * @{ + * + */ + #include /** @@ -83,4 +93,9 @@ #define OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE #endif +/** + * @} + * + */ + #endif // CONFIG_BORDER_ROUTER_H_ diff --git a/src/core/config/border_routing.h b/src/core/config/border_routing.h index 4640a081a..344cde4a5 100644 --- a/src/core/config/border_routing.h +++ b/src/core/config/border_routing.h @@ -35,6 +35,16 @@ #ifndef CONFIG_BORDER_ROUTING_H_ #define CONFIG_BORDER_ROUTING_H_ +/** + * @addtogroup config-border-routing + * + * @brief + * This module includes configuration variables for Border Routing Manager. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE * @@ -162,4 +172,9 @@ #define OPENTHREAD_CONFIG_BORDER_ROUTING_MOCK_PLAT_APIS_ENABLE 0 #endif +/** + * @} + * + */ + #endif // CONFIG_BORDER_ROUTING_H_ diff --git a/src/core/config/channel_manager.h b/src/core/config/channel_manager.h index 0057b664b..7c481c25d 100644 --- a/src/core/config/channel_manager.h +++ b/src/core/config/channel_manager.h @@ -35,6 +35,16 @@ #ifndef CONFIG_CHANNEL_MANAGER_H_ #define CONFIG_CHANNEL_MANAGER_H_ +/** + * @addtogroup config-channel-manager + * + * @brief + * This module includes configuration variables for Channel Manager. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE * @@ -136,4 +146,9 @@ #define OPENTHREAD_CONFIG_CHANNEL_MANAGER_CCA_FAILURE_THRESHOLD (0xffff * 14 / 100) #endif +/** + * @} + * + */ + #endif // CONFIG_CHANNEL_MANAGER_H_ diff --git a/src/core/config/channel_monitor.h b/src/core/config/channel_monitor.h index 92b263e61..312b168e7 100644 --- a/src/core/config/channel_monitor.h +++ b/src/core/config/channel_monitor.h @@ -35,6 +35,16 @@ #ifndef CONFIG_CHANNEL_MONITOR_H_ #define CONFIG_CHANNEL_MONITOR_H_ +/** + * @addtogroup config-channel-monitor + * + * @brief + * This module includes configuration variables for Channel Monitor. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE * @@ -92,4 +102,9 @@ #define OPENTHREAD_CONFIG_CHANNEL_MONITOR_SAMPLE_WINDOW 960 #endif +/** + * @} + * + */ + #endif // CONFIG_CHANNEL_MONITOR_H_ diff --git a/src/core/config/child_supervision.h b/src/core/config/child_supervision.h index 94e8ec63a..a0729498c 100644 --- a/src/core/config/child_supervision.h +++ b/src/core/config/child_supervision.h @@ -35,6 +35,16 @@ #ifndef CONFIG_CHILD_SUPERVISION_H_ #define CONFIG_CHILD_SUPERVISION_H_ +/** + * @addtogroup config-child-supervision + * + * @brief + * This module includes configuration variables for Child Supervision. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_CHILD_SUPERVISION_INTERVAL * @@ -86,4 +96,9 @@ #define OPENTHREAD_CONFIG_CHILD_SUPERVISION_OLDER_VERSION_CHILD_DEFAULT_INTERVAL 129 #endif +/** + * @} + * + */ + #endif // CONFIG_CHILD_SUPERVISION_H_ diff --git a/src/core/config/coap.h b/src/core/config/coap.h index c3ee709e4..518da3976 100644 --- a/src/core/config/coap.h +++ b/src/core/config/coap.h @@ -35,6 +35,16 @@ #ifndef CONFIG_COAP_H_ #define CONFIG_COAP_H_ +/** + * @addtogroup config-coap + * + * @brief + * This module includes configuration variables for CoAP. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_COAP_SERVER_MAX_CACHED_RESPONSES * @@ -97,4 +107,9 @@ #define OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE 0 #endif +/** + * @} + * + */ + #endif // CONFIG_COAP_H_ diff --git a/src/core/config/commissioner.h b/src/core/config/commissioner.h index ff43adb36..9a8d9617d 100644 --- a/src/core/config/commissioner.h +++ b/src/core/config/commissioner.h @@ -35,6 +35,16 @@ #ifndef CONFIG_COMMISSIONER_H_ #define CONFIG_COMMISSIONER_H_ +/** + * @addtogroup config-commissioner + * + * @brief + * This module includes configuration variables for the Commissioner. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_COMMISSIONER_ENABLE * @@ -66,4 +76,9 @@ #define OPENTHREAD_CONFIG_COMMISSIONER_JOINER_SESSION_TIMEOUT 30 #endif +/** + * @} + * + */ + #endif // CONFIG_COMMISSIONER_H_ diff --git a/src/core/config/crypto.h b/src/core/config/crypto.h index b7fb5c354..b60520cc9 100644 --- a/src/core/config/crypto.h +++ b/src/core/config/crypto.h @@ -29,6 +29,16 @@ #ifndef CONFIG_CRYPTO_H_ #define CONFIG_CRYPTO_H_ +/** + * @addtogroup config-crypto + * + * @brief + * This module includes configuration variables for the Crypto Backend Library. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_CRYPTO_LIB * @@ -95,4 +105,9 @@ #endif // OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PLATFORM +/** + * @} + * + */ + #endif // CONFIG_CRYPTO_H_ diff --git a/src/core/config/dataset_updater.h b/src/core/config/dataset_updater.h index 40557485a..2543afe95 100644 --- a/src/core/config/dataset_updater.h +++ b/src/core/config/dataset_updater.h @@ -35,6 +35,16 @@ #ifndef CONFIG_DATASET_UPDATER_H_ #define CONFIG_DATASET_UPDATER_H_ +/** + * @addtogroup config-dataset-updater + * + * @brief + * This module includes configuration variables for Dataset Updater. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE * @@ -67,4 +77,9 @@ #define OPENTHREAD_CONFIG_DATASET_UPDATER_DEFAULT_RETRY_WAIT_INTERVAL 1500 #endif +/** + * @} + * + */ + #endif // CONFIG_DATASET_UPDATER_H_ diff --git a/src/core/config/dhcp6_client.h b/src/core/config/dhcp6_client.h index 9b50636e1..2bf1b6ab1 100644 --- a/src/core/config/dhcp6_client.h +++ b/src/core/config/dhcp6_client.h @@ -35,6 +35,16 @@ #ifndef CONFIG_DHCP6_CLIENT_H_ #define CONFIG_DHCP6_CLIENT_H_ +/** + * @addtogroup config-dhcpv6-client + * + * @brief + * This module includes configuration variables for the DHCPv6 client. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_DHCP6_CLIENT_ENABLE * @@ -65,4 +75,9 @@ #define OPENTHREAD_CONFIG_DHCP6_CLIENT_NUM_PREFIXES 4 #endif +/** + * @} + * + */ + #endif // CONFIG_DHCP6_CLIENT_H_ diff --git a/src/core/config/dhcp6_server.h b/src/core/config/dhcp6_server.h index d833c6d5d..8e01fb411 100644 --- a/src/core/config/dhcp6_server.h +++ b/src/core/config/dhcp6_server.h @@ -35,6 +35,16 @@ #ifndef CONFIG_DHCP6_SERVER_H_ #define CONFIG_DHCP6_SERVER_H_ +/** + * @addtogroup config-dhcpv6-server + * + * @brief + * This module includes configuration variables for the DHCPv6 server. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_DHCP6_SERVER_ENABLE * @@ -55,4 +65,9 @@ #define OPENTHREAD_CONFIG_DHCP6_SERVER_NUM_PREFIXES 4 #endif +/** + * @} + * + */ + #endif // CONFIG_DHCP6_SERVER_H_ diff --git a/src/core/config/diag.h b/src/core/config/diag.h index a38d547d2..03261c705 100644 --- a/src/core/config/diag.h +++ b/src/core/config/diag.h @@ -35,6 +35,16 @@ #ifndef CONFIG_DIAG_H_ #define CONFIG_DIAG_H_ +/** + * @addtogroup config-diag + * + * @brief + * This module includes configuration variables for the DIAG service. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_DIAG_ENABLE * @@ -75,4 +85,9 @@ #define OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE 256 #endif +/** + * @} + * + */ + #endif // CONFIG_DIAG_H_ diff --git a/src/core/config/dns_client.h b/src/core/config/dns_client.h index d727261d8..6db961d4b 100644 --- a/src/core/config/dns_client.h +++ b/src/core/config/dns_client.h @@ -35,6 +35,16 @@ #ifndef CONFIG_DNS_CLIENT_H_ #define CONFIG_DNS_CLIENT_H_ +/** + * @addtogroup config-dns-client + * + * @brief + * This module includes configuration variables for the DNS client. + * + * @{ + * + */ + #include "config/ip6.h" #include "config/srp_client.h" @@ -181,4 +191,9 @@ #define OPENTHREAD_CONFIG_DNS_CLIENT_OVER_TCP_QUERY_MAX_SIZE 1024 #endif +/** + * @} + * + */ + #endif // CONFIG_DNS_CLIENT_H_ diff --git a/src/core/config/dns_dso.h b/src/core/config/dns_dso.h index 8b7d5a529..9b5ed5761 100644 --- a/src/core/config/dns_dso.h +++ b/src/core/config/dns_dso.h @@ -35,6 +35,16 @@ #ifndef CONFIG_DNS_DSO_H_ #define CONFIG_DNS_DSO_H_ +/** + * @addtogroup config-dns-dso + * + * @brief + * This module includes configuration variables for DNS Stateful Operations. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_DNS_DSO_ENABLE * @@ -87,4 +97,9 @@ #define OPENTHREAD_CONFIG_DNS_DSO_MOCK_PLAT_APIS_ENABLE 0 #endif +/** + * @} + * + */ + #endif // CONFIG_DNS_DSO_H_ diff --git a/src/core/config/dnssd_server.h b/src/core/config/dnssd_server.h index 8d6bb46d4..36b5620f3 100644 --- a/src/core/config/dnssd_server.h +++ b/src/core/config/dnssd_server.h @@ -35,6 +35,16 @@ #ifndef CONFIG_DNSSD_SERVER_H_ #define CONFIG_DNSSD_SERVER_H_ +/** + * @addtogroup config-dnssd-server + * + * @brief + * This module includes configuration variables for the DNS-SD server. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE * @@ -48,7 +58,7 @@ /** * @def OPENTHREAD_CONFIG_DNSSD_SERVER_PORT * - * Define the the DNS-SD Server port. + * Define the DNS-SD Server port. * */ #ifndef OPENTHREAD_CONFIG_DNSSD_SERVER_PORT @@ -98,4 +108,9 @@ #define OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_MOCK_PLAT_APIS_ENABLE 0 #endif +/** + * @} + * + */ + #endif // CONFIG_DNSSD_SERVER_H_ diff --git a/src/core/config/history_tracker.h b/src/core/config/history_tracker.h index 591474a3f..3da4ae881 100644 --- a/src/core/config/history_tracker.h +++ b/src/core/config/history_tracker.h @@ -35,6 +35,16 @@ #ifndef CONFIG_HISTORY_TRACKER_H_ #define CONFIG_HISTORY_TRACKER_H_ +/** + * @addtogroup config-history-tracker + * + * @brief + * This module includes configuration variables for History Tracker. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE * @@ -163,4 +173,9 @@ #define OPENTHREAD_CONFIG_HISTORY_TRACKER_EXTERNAL_ROUTE_LIST_SIZE 32 #endif +/** + * @} + * + */ + #endif // CONFIG_HISTORY_TRACKER_H_ diff --git a/src/core/config/ip6.h b/src/core/config/ip6.h index 82dc45c95..263190033 100644 --- a/src/core/config/ip6.h +++ b/src/core/config/ip6.h @@ -35,7 +35,18 @@ #ifndef CONFIG_IP6_H_ #define CONFIG_IP6_H_ +/** + * @addtogroup config-ip6 + * + * @brief + * This module includes configuration variables for the IP6 service. + * + * @{ + * + */ + #include "config/border_routing.h" +#include "config/misc.h" /** * @def OPENTHREAD_CONFIG_IP6_MAX_EXT_UCAST_ADDRS @@ -178,8 +189,8 @@ * Define as 1 to enable support for TLS over TCP. * */ -#if (OPENTHREAD_CONFIG_TCP_ENABLE || OPENTHREAD_CONFIG_BLE_TCAT_ENABLE) && !defined(OPENTHREAD_CONFIG_TLS_ENABLE) -#define OPENTHREAD_CONFIG_TLS_ENABLE 1 +#ifndef OPENTHREAD_CONFIG_TLS_ENABLE +#define OPENTHREAD_CONFIG_TLS_ENABLE (OPENTHREAD_CONFIG_TCP_ENABLE || OPENTHREAD_CONFIG_BLE_TCAT_ENABLE) #endif /** @@ -202,4 +213,9 @@ #define OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE #endif +/** + * @} + * + */ + #endif // CONFIG_IP6_H_ diff --git a/src/core/config/joiner.h b/src/core/config/joiner.h index c01dc3056..fdf2bef7f 100644 --- a/src/core/config/joiner.h +++ b/src/core/config/joiner.h @@ -35,6 +35,16 @@ #ifndef CONFIG_JOINER_H_ #define CONFIG_JOINER_H_ +/** + * @addtogroup config-joiner + * + * @brief + * This module includes configuration variables for the Joiner. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_JOINER_ENABLE * @@ -55,4 +65,9 @@ #define OPENTHREAD_CONFIG_JOINER_MAX_CANDIDATES 2 #endif +/** + * @} + * + */ + #endif // CONFIG_JOINER_H_ diff --git a/src/core/config/link_metrics_manager.h b/src/core/config/link_metrics_manager.h index 96fed1101..8ce73119a 100644 --- a/src/core/config/link_metrics_manager.h +++ b/src/core/config/link_metrics_manager.h @@ -35,6 +35,16 @@ #ifndef CONFIG_LINK_METRICS_MANAGER_H_ #define CONFIG_LINK_METRICS_MANAGER_H_ +/** + * @addtogroup config-link-metrics-manager + * + * @brief + * This module includes configuration variables for Link Metrics Manager. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_LINK_METRICS_MANAGER_ENABLE * @@ -55,4 +65,9 @@ #define OPENTHREAD_CONFIG_LINK_METRICS_MANAGER_ON_BY_DEFAULT 0 #endif +/** + * @} + * + */ + #endif // CONFIG_LINK_METRICS_MANAGER_H_ diff --git a/src/core/config/link_quality.h b/src/core/config/link_quality.h index f85c1a149..2ed1d514f 100644 --- a/src/core/config/link_quality.h +++ b/src/core/config/link_quality.h @@ -35,6 +35,16 @@ #ifndef CONFIG_LINK_QUALITY_H_ #define CONFIG_LINK_QUALITY_H_ +/** + * @addtogroup config-link-quality + * + * @brief + * This module includes configuration variables for the Link Quality service. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_CCA_FAILURE_RATE_AVERAGING_WINDOW * @@ -74,4 +84,9 @@ #define OPENTHREAD_CONFIG_IPV6_TX_ERR_RATE_AVERAGING_WINDOW 128 #endif +/** + * @} + * + */ + #endif // CONFIG_LINK_QUALITY_H_ diff --git a/src/core/config/link_raw.h b/src/core/config/link_raw.h index 6c2ceebeb..dd7dae2fd 100644 --- a/src/core/config/link_raw.h +++ b/src/core/config/link_raw.h @@ -35,6 +35,16 @@ #ifndef CONFIG_LINK_RAW_H_ #define CONFIG_LINK_RAW_H_ +/** + * @addtogroup config-link-raw + * + * @brief + * This module includes configuration variables for the Link Raw service. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_LINK_RAW_ENABLE * @@ -45,4 +55,9 @@ #define OPENTHREAD_CONFIG_LINK_RAW_ENABLE 0 #endif +/** + * @} + * + */ + #endif // CONFIG_LINK_RAW_H_ diff --git a/src/core/config/logging.h b/src/core/config/logging.h index aacec6984..c3d6602ea 100644 --- a/src/core/config/logging.h +++ b/src/core/config/logging.h @@ -35,6 +35,16 @@ #ifndef CONFIG_LOGGING_H_ #define CONFIG_LOGGING_H_ +/** + * @addtogroup config-logging + * + * @brief + * This module includes configuration variables for the Logging service. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_LOG_OUTPUT * @@ -184,4 +194,9 @@ #define OPENTHREAD_CONFIG_LOG_MAX_SIZE 150 #endif +/** + * @} + * + */ + #endif // CONFIG_LOGGING_H_ diff --git a/src/core/config/mac.h b/src/core/config/mac.h index d0cefa624..ec7e2f9d2 100644 --- a/src/core/config/mac.h +++ b/src/core/config/mac.h @@ -35,6 +35,16 @@ #ifndef CONFIG_MAC_H_ #define CONFIG_MAC_H_ +/** + * @addtogroup config-mac + * + * @brief + * This module includes configuration variables for MAC. + * + * @{ + * + */ + #include "config/time_sync.h" /** @@ -587,4 +597,9 @@ #define OPENTHREAD_CONFIG_MAC_DATA_POLL_TIMEOUT 100 #endif +/** + * @} + * + */ + #endif // CONFIG_MAC_H_ diff --git a/src/core/config/mesh_diag.h b/src/core/config/mesh_diag.h index 4049255fe..962cca878 100644 --- a/src/core/config/mesh_diag.h +++ b/src/core/config/mesh_diag.h @@ -35,6 +35,16 @@ #ifndef CONFIG_MESH_DIAG_H_ #define CONFIG_MESH_DIAG_H_ +/** + * @addtogroup config-mesh-diag + * + * @brief + * This module includes configuration variables for Mesh Diagnostic. + * + * @{ + * + */ + #include "config/border_routing.h" /** @@ -59,4 +69,9 @@ #define OPENTHREAD_CONFIG_MESH_DIAG_RESPONSE_TIMEOUT 5000 #endif +/** + * @} + * + */ + #endif // CONFIG_MESH_DIAG_H_ diff --git a/src/core/config/mesh_forwarder.h b/src/core/config/mesh_forwarder.h index c5e12d48b..f4a83a690 100644 --- a/src/core/config/mesh_forwarder.h +++ b/src/core/config/mesh_forwarder.h @@ -34,6 +34,16 @@ #ifndef CONFIG_MESH_FORWARDER_H_ #define CONFIG_MESH_FORWARDER_H_ +/** + * @addtogroup config-mesh-forwarder + * + * @brief + * This module includes configuration variables for the Mesh Forwarder. + * + * @{ + * + */ + #include "config/border_router.h" /** @@ -200,4 +210,9 @@ #define OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_HISTOGRAM_BIN_INTERVAL 10 #endif +/** + * @} + * + */ + #endif // CONFIG_MESH_FORWARDER_H_ diff --git a/src/core/config/misc.h b/src/core/config/misc.h index c9be7ec5e..b04e32ea6 100644 --- a/src/core/config/misc.h +++ b/src/core/config/misc.h @@ -34,6 +34,16 @@ #ifndef CONFIG_MISC_H_ #define CONFIG_MISC_H_ +/** + * @addtogroup config-misc + * + * @brief + * This module includes configuration variables for Miscellaneous constants. + * + * @{ + * + */ + #include "config/coap.h" #include "config/srp_server.h" @@ -572,4 +582,19 @@ #define OPENTHREAD_CONFIG_OPERATIONAL_DATASET_AUTO_INIT 0 #endif +/** + * @def OPENTHREAD_CONFIG_BLE_TCAT_ENABLE + * + * Define to 1 to enable TCAT over BLE support. + * + */ +#ifndef OPENTHREAD_CONFIG_BLE_TCAT_ENABLE +#define OPENTHREAD_CONFIG_BLE_TCAT_ENABLE 0 +#endif + +/** + * @} + * + */ + #endif // CONFIG_MISC_H_ diff --git a/src/core/config/mle.h b/src/core/config/mle.h index 7a7915a14..0810c010e 100644 --- a/src/core/config/mle.h +++ b/src/core/config/mle.h @@ -35,6 +35,16 @@ #ifndef CONFIG_MLE_H_ #define CONFIG_MLE_H_ +/** + * @addtogroup config-mle + * + * @brief + * This module includes configuration variables for the MLE service. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_MLE_MAX_ROUTERS * @@ -338,4 +348,9 @@ #define OPENTHREAD_CONFIG_MLE_LINK_METRICS_SERIES_MTD 2 #endif +/** + * @} + * + */ + #endif // CONFIG_MLE_H_ diff --git a/src/core/config/nat64.h b/src/core/config/nat64.h index fff5883b0..f2a7a2b0a 100644 --- a/src/core/config/nat64.h +++ b/src/core/config/nat64.h @@ -35,6 +35,16 @@ #ifndef CONFIG_NAT64_H_ #define CONFIG_NAT64_H_ +/** + * @addtogroup config-nat64 + * + * @brief + * This module includes configuration variables for NAT64. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE * @@ -75,4 +85,9 @@ #define OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE 0 #endif +/** + * @} + * + */ + #endif diff --git a/src/core/config/netdata_publisher.h b/src/core/config/netdata_publisher.h index ee8fe583a..1286852a1 100644 --- a/src/core/config/netdata_publisher.h +++ b/src/core/config/netdata_publisher.h @@ -35,6 +35,16 @@ #ifndef CONFIG_NETDATA_PUBLISHER_H_ #define CONFIG_NETDATA_PUBLISHER_H_ +/** + * @addtogroup config-netdata-publisher + * + * @brief + * This module includes configuration variables for Network Data Publisher. + * + * @{ + * + */ + #include "config/border_router.h" #include "config/border_routing.h" #include "config/srp_server.h" @@ -156,4 +166,9 @@ #define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES 3 #endif +/** + * @} + * + */ + #endif // CONFIG_NETDATA_PUBLISHER_H_ diff --git a/src/core/config/network_diagnostic.h b/src/core/config/network_diagnostic.h index 2aaf26018..ccf128d38 100644 --- a/src/core/config/network_diagnostic.h +++ b/src/core/config/network_diagnostic.h @@ -35,6 +35,16 @@ #ifndef CONFIG_NETWORK_DIAGNOSTIC_H_ #define CONFIG_NETWORK_DIAGNOSTIC_H_ +/** + * @addtogroup config-network-diagnostic + * + * @brief + * This module includes configuration variables for Network Diagnostics. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_NET_DIAG_VENDOR_NAME * @@ -82,4 +92,9 @@ #define OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE 0 #endif +/** + * @} + * + */ + #endif // CONFIG_NETWORK_DIAGNOSTIC_H_ diff --git a/src/core/config/parent_search.h b/src/core/config/parent_search.h index 9c78bc026..c5a978bba 100644 --- a/src/core/config/parent_search.h +++ b/src/core/config/parent_search.h @@ -35,6 +35,16 @@ #ifndef CONFIG_PARENT_SEARCH_H_ #define CONFIG_PARENT_SEARCH_H_ +/** + * @addtogroup config-parent-search + * + * @brief + * This module includes configuration variables for Parent Search. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE * @@ -93,4 +103,9 @@ #define OPENTHREAD_CONFIG_PARENT_SEARCH_RSS_THRESHOLD -65 #endif +/** + * @} + * + */ + #endif // CONFIG_PARENT_SEARCH_H_ diff --git a/src/core/config/ping_sender.h b/src/core/config/ping_sender.h index d655b1dc8..7c5d25df6 100644 --- a/src/core/config/ping_sender.h +++ b/src/core/config/ping_sender.h @@ -35,6 +35,16 @@ #ifndef CONFIG_PING_SENDER_H_ #define CONFIG_PING_SENDER_H_ +/** + * @addtogroup config-ping-sender + * + * @brief + * This module includes configuration variables for Ping Sender. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_PING_SENDER_ENABLE * @@ -89,4 +99,9 @@ #define OPENTHREAD_CONFIG_PING_SENDER_DEFAULT_COUNT 1 #endif +/** + * @} + * + */ + #endif // CONFIG_PING_SENDER_H_ diff --git a/src/core/config/platform.h b/src/core/config/platform.h index 9fa475bdf..927abb086 100644 --- a/src/core/config/platform.h +++ b/src/core/config/platform.h @@ -35,6 +35,16 @@ #ifndef CONFIG_PLATFORM_H_ #define CONFIG_PLATFORM_H_ +/** + * @addtogroup config-platform + * + * @brief + * This module includes configuration variables for platform-specific services. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_PLATFORM_INFO * @@ -186,4 +196,9 @@ #endif #endif +/** + * @} + * + */ + #endif // CONFIG_PLATFORM_H_ diff --git a/src/core/config/power_calibration.h b/src/core/config/power_calibration.h index 56e9467e2..2b79684e2 100644 --- a/src/core/config/power_calibration.h +++ b/src/core/config/power_calibration.h @@ -35,6 +35,16 @@ #ifndef CONFIG_POWER_CALIBRATION_H_ #define CONFIG_POWER_CALIBRATION_H_ +/** + * @addtogroup config-power-calibration + * + * @brief + * This module includes configuration variables for Power Calibration. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE * @@ -65,4 +75,9 @@ #define OPENTHREAD_CONFIG_POWER_CALIBRATION_NUM_CALIBRATED_POWER_ENTRIES 6 #endif +/** + * @} + * + */ + #endif // CONFIG_POWER_CALIBRATION_H_ diff --git a/src/core/config/radio_link.h b/src/core/config/radio_link.h index 14e9a1292..d56f9dbeb 100644 --- a/src/core/config/radio_link.h +++ b/src/core/config/radio_link.h @@ -35,6 +35,16 @@ #ifndef CONFIG_RADIO_LINK_H_ #define CONFIG_RADIO_LINK_H_ +/** + * @addtogroup config-radio-link + * + * @brief + * This module includes configuration variables for radio links. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE * @@ -93,4 +103,9 @@ #define OPENTHREAD_CONFIG_MULTI_RADIO_FRAG_TAG_TIMEOUT (20 * 1000) #endif +/** + * @} + * + */ + #endif // CONFIG_RADIO_LINK_H_ diff --git a/src/core/config/secure_transport.h b/src/core/config/secure_transport.h index ea6799ff9..eb636baa7 100644 --- a/src/core/config/secure_transport.h +++ b/src/core/config/secure_transport.h @@ -35,6 +35,16 @@ #ifndef CONFIG_SECURE_TRANSPORT_H_ #define CONFIG_SECURE_TRANSPORT_H_ +/** + * @addtogroup config-secure-transport + * + * @brief + * This module includes configuration variables for Secure Transport. + * + * @{ + * + */ + #include "config/border_agent.h" #include "config/coap.h" #include "config/commissioner.h" @@ -62,8 +72,13 @@ OPENTHREAD_CONFIG_COMMISSIONER_ENABLE || OPENTHREAD_CONFIG_JOINER_ENABLE || OPENTHREAD_CONFIG_BLE_TCAT_ENABLE) #endif -#if OPENTHREAD_CONFIG_DTLS_ENABLE +#ifdef OPENTHREAD_CONFIG_DTLS_ENABLE #error "OPENTHREAD_CONFIG_DTLS_ENABLE is deprecated please use OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE instead" #endif +/** + * @} + * + */ + #endif // CONFIG_SECURE_TRANSPORT_H_ diff --git a/src/core/config/sntp_client.h b/src/core/config/sntp_client.h index bd8d5fa5a..48079a82b 100644 --- a/src/core/config/sntp_client.h +++ b/src/core/config/sntp_client.h @@ -35,6 +35,16 @@ #ifndef CONFIG_SNTP_CLIENT_H_ #define CONFIG_SNTP_CLIENT_H_ +/** + * @addtogroup config-sntp-client + * + * @brief + * This module includes configuration variables for the SNTP Client. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE * @@ -65,4 +75,9 @@ #define OPENTHREAD_CONFIG_SNTP_CLIENT_MAX_RETRANSMIT 2 #endif +/** + * @} + * + */ + #endif // CONFIG_SNTP_CLIENT_H_ diff --git a/src/core/config/srp_client.h b/src/core/config/srp_client.h index ca609abeb..34c9abfb6 100644 --- a/src/core/config/srp_client.h +++ b/src/core/config/srp_client.h @@ -35,6 +35,16 @@ #ifndef CONFIG_SRP_CLIENT_H_ #define CONFIG_SRP_CLIENT_H_ +/** + * @addtogroup config-srp-client + * + * @brief + * This module includes configuration variables for the SRP Client. + * + * @{ + * + */ + #include "config/misc.h" /** @@ -69,7 +79,7 @@ * */ #ifndef OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_DEFAULT_MODE -#define OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_DEFAULT_MODE 0 +#define OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_DEFAULT_MODE 1 #endif /** @@ -274,7 +284,7 @@ * @def OPENTHREAD_CONFIG_SRP_CLIENT_RETRY_WAIT_INTERVAL_JITTER * * Specifies jitter (in msec) for retry wait interval. If the current retry wait interval is smaller than the jitter - * then the the wait interval itself is used as jitter (e.g., with jitter 500 msec and if retry interval is 300ms + * then the wait interval itself is used as jitter (e.g., with jitter 500 msec and if retry interval is 300ms * the retry interval is then randomly selected from [0, 2*300] ms). * */ @@ -402,4 +412,9 @@ #define OPENTHREAD_CONFIG_SRP_CLIENT_BUFFERS_TXT_BUFFER_SIZE 64 #endif +/** + * @} + * + */ + #endif // CONFIG_SRP_CLIENT_H_ diff --git a/src/core/config/srp_server.h b/src/core/config/srp_server.h index 5b76ec3ee..0ae6ef9a9 100644 --- a/src/core/config/srp_server.h +++ b/src/core/config/srp_server.h @@ -35,6 +35,16 @@ #ifndef CONFIG_SRP_SERVER_H_ #define CONFIG_SRP_SERVER_H_ +/** + * @addtogroup config-srp-server + * + * @brief + * This module includes configuration variables for the SRP Server. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_SRP_SERVER_ENABLE * @@ -109,4 +119,9 @@ #define OPENTHREAD_CONFIG_SRP_SERVER_SERVICE_UPDATE_TIMEOUT ((4 * 250u) + 250u) #endif +/** + * @} + * + */ + #endif // CONFIG_SRP_SERVER_H_ diff --git a/src/core/config/time_sync.h b/src/core/config/time_sync.h index c56d32d28..43d232c37 100644 --- a/src/core/config/time_sync.h +++ b/src/core/config/time_sync.h @@ -35,6 +35,16 @@ #ifndef CONFIG_TIME_SYNC_H_ #define CONFIG_TIME_SYNC_H_ +/** + * @addtogroup config-time-sync + * + * @brief + * This module includes configuration variables for the Time Sync service. + * + * @{ + * + */ + /** * @def OPENTHREAD_CONFIG_TIME_SYNC_ENABLE * @@ -94,4 +104,9 @@ #define OPENTHREAD_CONFIG_TIME_SYNC_JUMP_NOTIF_MIN_US 10000 #endif +/** + * @} + * + */ + #endif // CONFIG_TIME_SYNC_H_ diff --git a/src/core/config/tmf.h b/src/core/config/tmf.h index 42d3a70dc..18a397dd5 100644 --- a/src/core/config/tmf.h +++ b/src/core/config/tmf.h @@ -35,6 +35,17 @@ #ifndef CONFIG_TMF_H_ #define CONFIG_TMF_H_ +/** + * @addtogroup config-tmf + * + * @brief + * This module includes configuration variables for the Thread Management + * Framework service. + * + * @{ + * + */ + #include "config/border_router.h" /** @@ -247,4 +258,9 @@ #error "Thread 1.2 or higher version is required for OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE" #endif +/** + * @} + * + */ + #endif // CONFIG_TMF_H_ diff --git a/src/core/config/trel.h b/src/core/config/trel.h new file mode 100644 index 000000000..8d378ee03 --- /dev/null +++ b/src/core/config/trel.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024, 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 compile-time configurations for TREL. + * + */ + +#ifndef CONFIG_TREL_H_ +#define CONFIG_TREL_H_ + +/** + * @addtogroup config-trel + * + * @brief + * This module includes configuration variables for TREL. + * + * @{ + * + */ + +/** + * @def OPENTHREAD_CONFIG_TREL_PEER_TABLE_SIZE + * + * Specifies the capacity of TREL peer table. Only non-zero value + * will be directly used for setting the TREL peer table capacity. + * Zero value lets the size to be determined by the OT stack itself + * which is derived based on other configurations such as a child + * table size, neighbor table size, etc. + */ +#ifndef OPENTHREAD_CONFIG_TREL_PEER_TABLE_SIZE +#define OPENTHREAD_CONFIG_TREL_PEER_TABLE_SIZE (0) +#endif + +/** + * @} + * + */ + +#endif // CONFIG_TREL_H_ diff --git a/src/core/diags/factory_diags.cpp b/src/core/diags/factory_diags.cpp index 249594f77..78845f1aa 100644 --- a/src/core/diags/factory_diags.cpp +++ b/src/core/diags/factory_diags.cpp @@ -846,7 +846,7 @@ Error Diags::ProcessCmd(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_ // This `rcp` command is for debugging and testing only, building only when NDEBUG is not defined // so that it will be excluded from release build. -#if !defined(NDEBUG) && defined(OPENTHREAD_RADIO) +#if OPENTHREAD_RADIO && !defined(NDEBUG) if (aArgsLength > 0 && !strcmp(aArgs[0], "rcp")) { aArgs++; diff --git a/src/core/ftd.cmake b/src/core/ftd.cmake index dd6dae2f4..074c4362c 100644 --- a/src/core/ftd.cmake +++ b/src/core/ftd.cmake @@ -30,6 +30,8 @@ add_library(openthread-ftd) target_compile_definitions(openthread-ftd PRIVATE OPENTHREAD_FTD=1 + OPENTHREAD_MTD=0 + OPENTHREAD_RADIO=0 ) target_compile_options(openthread-ftd PRIVATE diff --git a/src/core/meshcop/announce_begin_client.cpp b/src/core/meshcop/announce_begin_client.cpp index 5d3b9d9c5..07ee2723f 100644 --- a/src/core/meshcop/announce_begin_client.cpp +++ b/src/core/meshcop/announce_begin_client.cpp @@ -60,10 +60,9 @@ Error AnnounceBeginClient::SendRequest(uint32_t aChannelMask, uint16_t aPeriod, const Ip6::Address &aAddress) { - Error error = kErrorNone; - MeshCoP::ChannelMaskTlv channelMask; - Tmf::MessageInfo messageInfo(GetInstance()); - Coap::Message *message = nullptr; + Error error = kErrorNone; + Tmf::MessageInfo messageInfo(GetInstance()); + Coap::Message *message = nullptr; VerifyOrExit(Get().IsActive(), error = kErrorInvalidState); VerifyOrExit((message = Get().NewPriorityMessage()) != nullptr, error = kErrorNoBufs); @@ -74,9 +73,7 @@ Error AnnounceBeginClient::SendRequest(uint32_t aChannelMask, SuccessOrExit( error = Tlv::Append(*message, Get().GetSessionId())); - channelMask.Init(); - channelMask.SetChannelMask(aChannelMask); - SuccessOrExit(error = channelMask.AppendTo(*message)); + SuccessOrExit(error = MeshCoP::ChannelMaskTlv::AppendTo(*message, aChannelMask)); SuccessOrExit(error = Tlv::Append(*message, aCount)); SuccessOrExit(error = Tlv::Append(*message, aPeriod)); diff --git a/src/core/meshcop/dataset.cpp b/src/core/meshcop/dataset.cpp index 1692696fc..b15a40720 100644 --- a/src/core/meshcop/dataset.cpp +++ b/src/core/meshcop/dataset.cpp @@ -199,9 +199,9 @@ void Dataset::ConvertTo(Info &aDatasetInfo) const case Tlv::kChannelMask: { - uint32_t mask = As(cur)->GetChannelMask(); + uint32_t mask; - if (mask != 0) + if (As(cur)->ReadChannelMask(mask) == kErrorNone) { aDatasetInfo.SetChannelMask(mask); } @@ -312,10 +312,10 @@ Error Dataset::SetFrom(const Info &aDatasetInfo) if (aDatasetInfo.IsChannelMaskPresent()) { - ChannelMaskTlv tlv; - tlv.Init(); - tlv.SetChannelMask(aDatasetInfo.GetChannelMask()); - IgnoreError(WriteTlv(tlv)); + ChannelMaskTlv::Value value; + + ChannelMaskTlv::PrepareValue(value, aDatasetInfo.GetChannelMask()); + IgnoreError(WriteTlv(Tlv::kChannelMask, value.mData, value.mLength)); } if (aDatasetInfo.IsExtendedPanIdPresent()) diff --git a/src/core/meshcop/dataset_manager.cpp b/src/core/meshcop/dataset_manager.cpp index bc316980e..8bf1cb38a 100644 --- a/src/core/meshcop/dataset_manager.cpp +++ b/src/core/meshcop/dataset_manager.cpp @@ -228,7 +228,7 @@ Error DatasetManager::GetChannelMask(Mac::ChannelMask &aChannelMask) const channelMaskTlv = As(dataset.FindTlv(Tlv::kChannelMask)); VerifyOrExit(channelMaskTlv != nullptr, error = kErrorNotFound); - VerifyOrExit((mask = channelMaskTlv->GetChannelMask()) != 0); + SuccessOrExit(channelMaskTlv->ReadChannelMask(mask)); aChannelMask.SetMask(mask & Get().GetSupportedChannelMask().GetMask()); diff --git a/src/core/meshcop/dataset_manager_ftd.cpp b/src/core/meshcop/dataset_manager_ftd.cpp index e5423dc3c..5f74842ef 100644 --- a/src/core/meshcop/dataset_manager_ftd.cpp +++ b/src/core/meshcop/dataset_manager_ftd.cpp @@ -319,10 +319,10 @@ Error ActiveDatasetManager::GenerateLocal(void) if (!dataset.Contains()) { - ChannelMaskTlv tlv; - tlv.Init(); - tlv.SetChannelMask(Get().GetSupportedChannelMask().GetMask()); - IgnoreError(dataset.WriteTlv(tlv)); + ChannelMaskTlv::Value value; + + ChannelMaskTlv::PrepareValue(value, Get().GetSupportedChannelMask().GetMask()); + IgnoreError(dataset.WriteTlv(Tlv::kChannelMask, value.mData, value.mLength)); } if (!dataset.Contains()) diff --git a/src/core/meshcop/energy_scan_client.cpp b/src/core/meshcop/energy_scan_client.cpp index beea65caa..41f083883 100644 --- a/src/core/meshcop/energy_scan_client.cpp +++ b/src/core/meshcop/energy_scan_client.cpp @@ -66,10 +66,9 @@ Error EnergyScanClient::SendQuery(uint32_t aChannelMas otCommissionerEnergyReportCallback aCallback, void *aContext) { - Error error = kErrorNone; - MeshCoP::ChannelMaskTlv channelMask; - Tmf::MessageInfo messageInfo(GetInstance()); - Coap::Message *message = nullptr; + Error error = kErrorNone; + Tmf::MessageInfo messageInfo(GetInstance()); + Coap::Message *message = nullptr; VerifyOrExit(Get().IsActive(), error = kErrorInvalidState); VerifyOrExit((message = Get().NewPriorityMessage()) != nullptr, error = kErrorNoBufs); @@ -80,9 +79,7 @@ Error EnergyScanClient::SendQuery(uint32_t aChannelMas SuccessOrExit( error = Tlv::Append(*message, Get().GetSessionId())); - channelMask.Init(); - channelMask.SetChannelMask(aChannelMask); - SuccessOrExit(error = channelMask.AppendTo(*message)); + SuccessOrExit(error = MeshCoP::ChannelMaskTlv::AppendTo(*message, aChannelMask)); SuccessOrExit(error = Tlv::Append(*message, aCount)); SuccessOrExit(error = Tlv::Append(*message, aPeriod)); @@ -110,7 +107,7 @@ void EnergyScanClient::HandleTmf(Coap::Message &aMessage, cons LogInfo("Received %s", UriToString()); - VerifyOrExit((mask = MeshCoP::ChannelMaskTlv::GetChannelMask(aMessage)) != 0); + SuccessOrExit(MeshCoP::ChannelMaskTlv::FindIn(aMessage, mask)); SuccessOrExit(MeshCoP::Tlv::FindTlv(aMessage, MeshCoP::Tlv::kEnergyList, sizeof(energyListTlv), energyListTlv)); diff --git a/src/core/meshcop/meshcop_tlvs.cpp b/src/core/meshcop/meshcop_tlvs.cpp index 573e6b095..151abcd42 100644 --- a/src/core/meshcop/meshcop_tlvs.cpp +++ b/src/core/meshcop/meshcop_tlvs.cpp @@ -158,191 +158,140 @@ const char *StateTlv::StateToString(State aState) return aState == kReject ? kStateStrings[2] : kStateStrings[aState]; } -bool ChannelMaskBaseTlv::IsValid(void) const +bool ChannelMaskTlv::IsValid(void) const { - const ChannelMaskEntryBase *cur = GetFirstEntry(); - const ChannelMaskEntryBase *end = reinterpret_cast(GetNext()); - bool ret = false; + uint32_t channelMask; - VerifyOrExit(cur != nullptr); - - while (cur < end) - { - uint8_t channelPage; - - VerifyOrExit((cur + 1) <= end && cur->GetNext() <= end); - - channelPage = cur->GetChannelPage(); - -#if OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT - if (channelPage == OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE) -#else - if ((channelPage == OT_RADIO_CHANNEL_PAGE_0) || (channelPage == OT_RADIO_CHANNEL_PAGE_2)) -#endif - { - VerifyOrExit(static_cast(cur)->IsValid()); - } + return (ReadChannelMask(channelMask) == kErrorNone); +} - cur = cur->GetNext(); - } +Error ChannelMaskTlv::ReadChannelMask(uint32_t &aChannelMask) const +{ + EntriesData entriesData; - ret = true; + entriesData.Clear(); + entriesData.mData = &mEntriesStart; + entriesData.mLength = GetLength(); -exit: - return ret; + return entriesData.Parse(aChannelMask); } -const ChannelMaskEntryBase *ChannelMaskBaseTlv::GetFirstEntry(void) const +Error ChannelMaskTlv::FindIn(const Message &aMessage, uint32_t &aChannelMask) { - const ChannelMaskEntryBase *entry = nullptr; + Error error; + EntriesData entriesData; - VerifyOrExit(GetLength() >= sizeof(ChannelMaskEntryBase)); + entriesData.Clear(); + entriesData.mMessage = &aMessage; - entry = reinterpret_cast(GetValue()); - VerifyOrExit(GetLength() >= entry->GetEntrySize(), entry = nullptr); + SuccessOrExit(error = FindTlvValueOffset(aMessage, Tlv::kChannelMask, entriesData.mOffset, entriesData.mLength)); + error = entriesData.Parse(aChannelMask); exit: - return entry; + return error; } -ChannelMaskEntryBase *ChannelMaskBaseTlv::GetFirstEntry(void) { return AsNonConst(AsConst(this)->GetFirstEntry()); } - -void ChannelMaskTlv::SetChannelMask(uint32_t aChannelMask) +Error ChannelMaskTlv::EntriesData::Parse(uint32_t &aChannelMask) { - uint8_t length = 0; - ChannelMaskEntry *entry; - - entry = static_cast(GetFirstEntry()); - -#if OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT - if (aChannelMask & OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK) - { - OT_ASSERT(entry != nullptr); - entry->Init(); - entry->SetChannelPage(OT_RADIO_CHANNEL_PAGE_2); - entry->SetMask(aChannelMask & OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK); + // Validates and parses the Channel Mask TLV entries for each + // channel page and if successful updates `aChannelMask` to + // return the combined mask for all channel pages supported by + // radio. The entries can be either contained in `mMessage` from + // `mOffset` (when `mMessage` is non-null) or be in a buffer + // `mData`. `mLength` gives the number of bytes for all entries. - length += sizeof(ChannelMaskEntry); + Error error = kErrorParse; + Entry readEntry; + const Entry *entry; + uint16_t size; - entry = static_cast(entry->GetNext()); - } -#endif + aChannelMask = 0; -#if OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT - if (aChannelMask & OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK) - { - OT_ASSERT(entry != nullptr); - entry->Init(); - entry->SetChannelPage(OT_RADIO_CHANNEL_PAGE_0); - entry->SetMask(aChannelMask & OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK); + VerifyOrExit(mLength > 0); // At least one entry. - length += sizeof(ChannelMaskEntry); - } -#endif - -#if OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT - if (aChannelMask & OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MASK) + while (mLength > 0) { - OT_ASSERT(entry != nullptr); - entry->Init(); - entry->SetChannelPage(OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE); - entry->SetMask(aChannelMask & OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MASK); + VerifyOrExit(mLength > kEntryHeaderSize); - length += sizeof(ChannelMaskEntry); - } -#endif + if (mMessage != nullptr) + { + // We first read the entry's header only and after + // validating the entry and that the entry's channel page + // is supported by radio, we read the full `Entry`. - SetLength(length); -} + mMessage->ReadBytes(mOffset, &readEntry, kEntryHeaderSize); + entry = &readEntry; + } + else + { + entry = reinterpret_cast(mData); + } -uint32_t ChannelMaskTlv::GetChannelMask(void) const -{ - const ChannelMaskEntryBase *cur = GetFirstEntry(); - const ChannelMaskEntryBase *end = reinterpret_cast(GetNext()); - uint32_t mask = 0; + size = kEntryHeaderSize + entry->GetMaskLength(); - VerifyOrExit(cur != nullptr); + VerifyOrExit(size <= mLength); - while (cur < end) - { - uint8_t channelPage; + if (Radio::SupportsChannelPage(entry->GetChannelPage())) + { + // Currently supported channel pages all use `uint32_t` + // channel mask. - VerifyOrExit((cur + 1) <= end && cur->GetNext() <= end); + VerifyOrExit(entry->GetMaskLength() == kMaskLength); - channelPage = cur->GetChannelPage(); + if (mMessage != nullptr) + { + IgnoreError(mMessage->Read(mOffset, readEntry)); + } -#if OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT - if (channelPage == OT_RADIO_CHANNEL_PAGE_2) - { - mask |= static_cast(cur)->GetMask() & OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK; + aChannelMask |= (entry->GetMask() & Radio::ChannelMaskForPage(entry->GetChannelPage())); } -#endif -#if OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT - if (channelPage == OT_RADIO_CHANNEL_PAGE_0) + mLength -= size; + + if (mMessage != nullptr) { - mask |= static_cast(cur)->GetMask() & OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK; + mOffset += size; } -#endif - -#if OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT - if (channelPage == OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE) + else { - mask |= static_cast(cur)->GetMask() & - OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MASK; + mData += size; } -#endif - - cur = cur->GetNext(); } + error = kErrorNone; + exit: - return mask; + return error; } -uint32_t ChannelMaskTlv::GetChannelMask(const Message &aMessage) +void ChannelMaskTlv::PrepareValue(Value &aValue, uint32_t aChannelMask) { - uint32_t mask = 0; - uint16_t offset; - uint16_t end; + Entry *entry = reinterpret_cast(aValue.mData); - SuccessOrExit(FindTlvValueStartEndOffsets(aMessage, kChannelMask, offset, end)); + aValue.mLength = 0; - while (offset + sizeof(ChannelMaskEntryBase) <= end) + for (uint8_t page : Radio::kSupportedChannelPages) { - ChannelMaskEntry entry; + uint32_t mask = (Radio::ChannelMaskForPage(page) & aChannelMask); - IgnoreError(aMessage.Read(offset, entry)); - VerifyOrExit(offset + entry.GetEntrySize() <= end); - - switch (entry.GetChannelPage()) + if (mask != 0) { -#if OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT - case OT_RADIO_CHANNEL_PAGE_0: - IgnoreError(aMessage.Read(offset, entry)); - mask |= entry.GetMask() & OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK; - break; -#endif - -#if OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT - case OT_RADIO_CHANNEL_PAGE_2: - IgnoreError(aMessage.Read(offset, entry)); - mask |= entry.GetMask() & OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK; - break; -#endif - -#if OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT - case OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE: - IgnoreError(aMessage.Read(offset, entry)); - mask |= entry.GetMask() & OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MASK; - break; -#endif + entry->SetChannelPage(page); + entry->SetMaskLength(kMaskLength); + entry->SetMask(mask); + + aValue.mLength += sizeof(Entry); + entry++; } - offset += entry.GetEntrySize(); } +} -exit: - return mask; +Error ChannelMaskTlv::AppendTo(Message &aMessage, uint32_t aChannelMask) +{ + Value value; + + PrepareValue(value, aChannelMask); + return Tlv::Append(aMessage, value.mData, value.mLength); } } // namespace MeshCoP diff --git a/src/core/meshcop/meshcop_tlvs.hpp b/src/core/meshcop/meshcop_tlvs.hpp index b7b2af3fb..2f2b11186 100644 --- a/src/core/meshcop/meshcop_tlvs.hpp +++ b/src/core/meshcop/meshcop_tlvs.hpp @@ -613,258 +613,121 @@ typedef SimpleTlvInfo PendingTimestampTlv; */ typedef UintTlvInfo DelayTimerTlv; -// forward declare ChannelMaskTlv -class ChannelMaskTlv; - /** - * Implements Channel Mask Entry generation and parsing. + * Implements Channel Mask TLV generation and parsing. * */ OT_TOOL_PACKED_BEGIN -class ChannelMaskEntryBase +class ChannelMaskTlv : public Tlv, public TlvInfo { -public: - /** - * Gets the ChannelPage value. - * - * @returns The ChannelPage value. - * - */ - uint8_t GetChannelPage(void) const { return mChannelPage; } - - /** - * Sets the ChannelPage value. - * - * @param[in] aChannelPage The ChannelPage value. - * - */ - void SetChannelPage(uint8_t aChannelPage) { mChannelPage = aChannelPage; } - - /** - * Gets the MaskLength value. - * - * @returns The MaskLength value. - * - */ - uint8_t GetMaskLength(void) const { return mMaskLength; } + static constexpr uint8_t kEntryHeaderSize = 2; // Two bytes: mChannelPage and mMaskLength + static constexpr uint8_t kEntrySize = kEntryHeaderSize + sizeof(uint32_t); +public: /** - * Sets the MaskLength value. - * - * @param[in] aMaskLength The MaskLength value. + * Represents Channel Mask TLV value to append. * */ - void SetMaskLength(uint8_t aMaskLength) { mMaskLength = aMaskLength; } + struct Value + { + static constexpr uint16_t kMaxLength = (kEntrySize * Radio::kNumChannelPages); ///< Max value length. - /** - * Returns the total size of this Channel Mask Entry including the mask. - * - * @returns The total size of this entry (number of bytes). - * - */ - uint16_t GetEntrySize(void) const { return sizeof(ChannelMaskEntryBase) + mMaskLength; } + uint8_t mData[kMaxLength]; ///< Array to store TLV value (encoded as one or more Channel Mask TLV Entry) + uint8_t mLength; ///< Value length in bytes. + }; - /** - * Clears the bit corresponding to @p aChannel in ChannelMask. - * - * @param[in] aChannel The channel in ChannelMask to clear. - * - */ - void ClearChannel(uint8_t aChannel) - { - uint8_t *mask = reinterpret_cast(this) + sizeof(*this); - mask[aChannel / 8] &= ~(0x80 >> (aChannel % 8)); - } + ChannelMaskTlv(void) = delete; /** - * Sets the bit corresponding to @p aChannel in ChannelMask. + * Parses the Channel Mask TLV value and validates that all the included entries are well-formed. * - * @param[in] aChannel The channel in ChannelMask to set. + * @returns TRUE if the TLV is well-formed, FALSE otherwise. * */ - void SetChannel(uint8_t aChannel) - { - uint8_t *mask = reinterpret_cast(this) + sizeof(*this); - mask[aChannel / 8] |= 0x80 >> (aChannel % 8); - } + bool IsValid(void) const; /** - * Indicates whether or not the bit corresponding to @p aChannel in ChannelMask is set. - * - * @param[in] aChannel The channel in ChannelMask to get. + * Parses and retrieves the combined channel mask for all supported channel pages from entries in the TLV. * - */ - bool IsChannelSet(uint8_t aChannel) const - { - const uint8_t *mask = reinterpret_cast(this) + sizeof(*this); - return (aChannel < (mMaskLength * 8)) ? ((mask[aChannel / 8] & (0x80 >> (aChannel % 8))) != 0) : false; - } - - /** - * Gets the next Channel Mask Entry in a Channel Mask TLV. + * @param[out] aChannelMask A reference to return the channel mask. * - * @returns A pointer to next Channel Mask Entry. + * @retval kErrorNone Successfully parsed the TLV value, @p aChannelMask is updated. + * @retval kErrorParse TLV value is not well-formed. * */ - const ChannelMaskEntryBase *GetNext(void) const - { - return reinterpret_cast(reinterpret_cast(this) + GetEntrySize()); - } + Error ReadChannelMask(uint32_t &aChannelMask) const; /** - * Gets the next Channel Mask Entry in a Channel Mask TLV. + * Searches within a given message for Channel Mask TLV, parses and validates the TLV value and returns the + * combined channel mask for all supported channel pages included in the TLV. * - * @returns A pointer to next Channel Mask Entry. + * @param[in] aMessage The message to search in. + * @param[out] aChannelMask A reference to return the channel mask. * - */ - ChannelMaskEntryBase *GetNext(void) { return AsNonConst(AsConst(this)->GetNext()); } - -private: - uint8_t mChannelPage; - uint8_t mMaskLength; -} OT_TOOL_PACKED_END; - -/** - * Implements Channel Mask Entry Page 0 generation and parsing. - * - */ -OT_TOOL_PACKED_BEGIN -class ChannelMaskEntry : public ChannelMaskEntryBase -{ -public: - /** - * Initializes the entry. + * @retval kErrorNone Found the TLV, successfully parsed its value, @p aChannelMask is updated. + * @retval kErrorNotFound No Channel Mask TLV found in the @p aMessage. + * @retval kErrorParse Found the TLV, but failed to parse it. * */ - void Init(void) - { - SetChannelPage(0); - SetMaskLength(sizeof(mMask)); - } + static Error FindIn(const Message &aMessage, uint32_t &aChannelMask); /** - * Indicates whether or not the entry appears to be well-formed. + * Prepares Channel Mask TLV value for appending/writing. * - * @retval TRUE If the entry appears to be well-formed. - * @retval FALSE If the entry does not appear to be well-formed. + * @param[out] aValue A reference to `Value` structure to populate. + * @param[in] aChannelMask The combined channel mask for all supported channel pages. * */ - bool IsValid(void) const { return GetMaskLength() == sizeof(mMask); } + static void PrepareValue(Value &aValue, uint32_t aChannelMask); /** - * Returns the Channel Mask value as a `uint32_t` bit mask. + * Prepares a Channel Mask TLV value and appends the TLV to a given message. * - * @returns The Channel Mask value. + * @param[in] aMessage The message to append to. + * @param[in] aChannelMask The combined channel mask for all supported channel pages. * - */ - uint32_t GetMask(void) const { return Reverse32(BigEndian::HostSwap32(mMask)); } - - /** - * Sets the Channel Mask value. - * - * @param[in] aMask The Channel Mask value. + * @retval kErrorNone Successfully prepared the Channel Mask TLV and appended it to @p aMessage. + * @retval kErrorNoBufs Insufficient available buffers to grow the message. * */ - void SetMask(uint32_t aMask) { mMask = BigEndian::HostSwap32(Reverse32(aMask)); } + static Error AppendTo(Message &aMessage, uint32_t aChannelMask); private: - uint32_t mMask; -} OT_TOOL_PACKED_END; + static constexpr uint8_t kMaskLength = sizeof(uint32_t); -/** - * Implements Channel Mask TLV generation and parsing. - * - */ -OT_TOOL_PACKED_BEGIN -class ChannelMaskBaseTlv : public Tlv, public TlvInfo -{ -public: - /** - * Initializes the TLV. - * - */ - void Init(void) + OT_TOOL_PACKED_BEGIN + class Entry { - SetType(kChannelMask); - SetLength(sizeof(*this) - sizeof(Tlv)); - } - - /** - * Indicates whether or not the TLV appears to be well-formed. - * - * @retval TRUE If the TLV appears to be well-formed. - * @retval FALSE If the TLV does not appear to be well-formed. - * - */ - bool IsValid(void) const; - - /** - * Gets the first Channel Mask Entry in the Channel Mask TLV. - * - * @returns A pointer to first Channel Mask Entry or `nullptr` if not found. - * - */ - const ChannelMaskEntryBase *GetFirstEntry(void) const; - - /** - * Gets the first Channel Mask Entry in the Channel Mask TLV. - * - * @returns A pointer to first Channel Mask Entry or `nullptr` if not found. - * - */ - ChannelMaskEntryBase *GetFirstEntry(void); -} OT_TOOL_PACKED_END; - -/** - * Implements Channel Mask TLV generation and parsing. - * - */ -OT_TOOL_PACKED_BEGIN -class ChannelMaskTlv : public ChannelMaskBaseTlv -{ -public: - /** - * Initializes the TLV. - * - */ - void Init(void) + public: + uint8_t GetChannelPage(void) const { return mChannelPage; } + void SetChannelPage(uint8_t aChannelPage) { mChannelPage = aChannelPage; } + uint8_t GetMaskLength(void) const { return mMaskLength; } + void SetMaskLength(uint8_t aMaskLength) { mMaskLength = aMaskLength; } + uint32_t GetMask(void) const { return Reverse32(BigEndian::HostSwap32(mMask)); } + void SetMask(uint32_t aMask) { mMask = BigEndian::HostSwap32(Reverse32(aMask)); } + + private: + uint8_t mChannelPage; + uint8_t mMaskLength; + uint32_t mMask; + } OT_TOOL_PACKED_END; + + struct EntriesData : public Clearable { - SetType(kChannelMask); - SetLength(sizeof(*this) - sizeof(Tlv)); - memset(mEntries, 0, sizeof(mEntries)); - } - - /** - * Sets the Channel Mask Entries. - * - * @param[in] aChannelMask The Channel Mask value. - * - */ - void SetChannelMask(uint32_t aChannelMask); - - /** - * Returns the Channel Mask value as a `uint32_t` bit mask. - * - * @returns The Channel Mask or 0 if not found. - * - */ - uint32_t GetChannelMask(void) const; + // Represents received Channel Mask TLV Entries data which + // is either contained in `mData` buffer, or in `mMessage` + // at `mOffset`. - /** - * Reads message and returns the Channel Mask value as a `uint32_t` bit mask. - * - * @param[in] aMessage A reference to the message. - * - * @returns The Channel Mask or 0 if not found. - * - */ - static uint32_t GetChannelMask(const Message &aMessage); + Error Parse(uint32_t &aChannelMask); -private: - static constexpr uint8_t kNumMaskEntries = Radio::kNumChannelPages; + const uint8_t *mData; + const Message *mMessage; + uint16_t mOffset; + uint16_t mLength; + }; - ChannelMaskEntry mEntries[kNumMaskEntries]; -} OT_TOOL_PACKED_END; + uint8_t mEntriesStart; +} OT_TOOL_PACKED_BEGIN; /** * Implements Energy List TLV generation and parsing. diff --git a/src/core/meshcop/panid_query_client.cpp b/src/core/meshcop/panid_query_client.cpp index 431e8c2fa..01a3e9a39 100644 --- a/src/core/meshcop/panid_query_client.cpp +++ b/src/core/meshcop/panid_query_client.cpp @@ -62,10 +62,9 @@ Error PanIdQueryClient::SendQuery(uint16_t aPanId, otCommissionerPanIdConflictCallback aCallback, void *aContext) { - Error error = kErrorNone; - MeshCoP::ChannelMaskTlv channelMask; - Tmf::MessageInfo messageInfo(GetInstance()); - Coap::Message *message = nullptr; + Error error = kErrorNone; + Tmf::MessageInfo messageInfo(GetInstance()); + Coap::Message *message = nullptr; VerifyOrExit(Get().IsActive(), error = kErrorInvalidState); VerifyOrExit((message = Get().NewPriorityMessage()) != nullptr, error = kErrorNoBufs); @@ -76,9 +75,7 @@ Error PanIdQueryClient::SendQuery(uint16_t aPanId, SuccessOrExit( error = Tlv::Append(*message, Get().GetSessionId())); - channelMask.Init(); - channelMask.SetChannelMask(aChannelMask); - SuccessOrExit(error = channelMask.AppendTo(*message)); + SuccessOrExit(error = MeshCoP::ChannelMaskTlv::AppendTo(*message, aChannelMask)); SuccessOrExit(error = Tlv::Append(*message, aPanId)); @@ -106,7 +103,7 @@ void PanIdQueryClient::HandleTmf(Coap::Message &aMessage, con SuccessOrExit(Tlv::Find(aMessage, panId)); - VerifyOrExit((mask = MeshCoP::ChannelMaskTlv::GetChannelMask(aMessage)) != 0); + SuccessOrExit(MeshCoP::ChannelMaskTlv::FindIn(aMessage, mask)); mCallback.InvokeIfSet(panId, mask); diff --git a/src/core/meshcop/secure_transport.cpp b/src/core/meshcop/secure_transport.cpp index 945f701c6..480456e69 100644 --- a/src/core/meshcop/secure_transport.cpp +++ b/src/core/meshcop/secure_transport.cpp @@ -138,17 +138,28 @@ void SecureTransport::FreeMbedtls(void) mbedtls_ssl_free(&mSsl); } +void SecureTransport::SetState(State aState) +{ + VerifyOrExit(mState != aState); + + LogInfo("State: %s -> %s", StateToString(mState), StateToString(aState)); + mState = aState; + +exit: + return; +} + Error SecureTransport::Open(ReceiveHandler aReceiveHandler, ConnectedHandler aConnectedHandler, void *aContext) { Error error; - VerifyOrExit(mState == kStateClosed, error = kErrorAlready); + VerifyOrExit(IsStateClosed(), error = kErrorAlready); - SuccessOrExit(error = mSocket.Open(&SecureTransport::HandleUdpReceive, this)); + SuccessOrExit(error = mSocket.Open(&SecureTransport::HandleReceive, this)); mConnectedCallback.Set(aConnectedHandler, aContext); mReceiveCallback.Set(aReceiveHandler, aContext); - mState = kStateOpen; + SetState(kStateOpen); exit: return error; @@ -158,7 +169,7 @@ Error SecureTransport::Connect(const Ip6::SockAddr &aSockAddr) { Error error; - VerifyOrExit(mState == kStateOpen, error = kErrorInvalidState); + VerifyOrExit(IsStateOpen(), error = kErrorInvalidState); mMessageInfo.SetPeerAddr(aSockAddr.GetAddress()); mMessageInfo.SetPeerPort(aSockAddr.mPort); @@ -169,19 +180,17 @@ Error SecureTransport::Connect(const Ip6::SockAddr &aSockAddr) return error; } -void SecureTransport::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo) +void SecureTransport::HandleReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo) { - static_cast(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo)); + static_cast(aContext)->HandleReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo)); } -void SecureTransport::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +void SecureTransport::HandleReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { - switch (mState) - { - case SecureTransport::kStateClosed: - ExitNow(); + VerifyOrExit(!IsStateClosed()); - case SecureTransport::kStateOpen: + if (IsStateOpen()) + { IgnoreError(mSocket.Connect(Ip6::SockAddr(aMessageInfo.GetPeerAddr(), aMessageInfo.GetPeerPort()))); mMessageInfo.SetPeerAddr(aMessageInfo.GetPeerAddr()); @@ -196,17 +205,16 @@ void SecureTransport::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo mMessageInfo.SetSockPort(aMessageInfo.GetSockPort()); SuccessOrExit(Setup(false)); - break; - - default: + } + else + { // Once DTLS session is started, communicate only with a peer. VerifyOrExit((mMessageInfo.GetPeerAddr() == aMessageInfo.GetPeerAddr()) && (mMessageInfo.GetPeerPort() == aMessageInfo.GetPeerPort())); - break; } #ifdef MBEDTLS_SSL_SRV_C - if (mState == SecureTransport::kStateConnecting) + if (IsStateConnecting()) { IgnoreError(SetClientId(mMessageInfo.GetPeerAddr().mFields.m8, sizeof(mMessageInfo.GetPeerAddr().mFields))); } @@ -224,7 +232,7 @@ Error SecureTransport::Bind(uint16_t aPort) { Error error; - VerifyOrExit(mState == kStateOpen, error = kErrorInvalidState); + VerifyOrExit(IsStateOpen(), error = kErrorInvalidState); VerifyOrExit(!mTransportCallback.IsSet(), error = kErrorAlready); SuccessOrExit(error = mSocket.Bind(aPort, Ip6::kNetifUnspecified)); @@ -237,7 +245,7 @@ Error SecureTransport::Bind(TransportCallback aCallback, void *aContext) { Error error = kErrorNone; - VerifyOrExit(mState == kStateOpen, error = kErrorInvalidState); + VerifyOrExit(IsStateOpen(), error = kErrorInvalidState); VerifyOrExit(!mSocket.IsBound(), error = kErrorAlready); VerifyOrExit(!mTransportCallback.IsSet(), error = kErrorAlready); @@ -252,9 +260,9 @@ Error SecureTransport::Setup(bool aClient) int rval; // do not handle new connection before guard time expired - VerifyOrExit(mState == kStateOpen, rval = MBEDTLS_ERR_SSL_TIMEOUT); + VerifyOrExit(IsStateOpen(), rval = MBEDTLS_ERR_SSL_TIMEOUT); - mState = kStateInitializing; + SetState(kStateInitializing); mbedtls_ssl_init(&mSsl); mbedtls_ssl_config_init(&mConf); @@ -361,7 +369,6 @@ Error SecureTransport::Setup(bool aClient) mReceiveMessage = nullptr; mMessageSubType = Message::kSubTypeNone; - mState = kStateConnecting; if (mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8) { @@ -374,14 +381,14 @@ Error SecureTransport::Setup(bool aClient) } #endif - mState = kStateConnecting; + SetState(kStateConnecting); Process(); exit: - if ((mState == kStateInitializing) && (rval != 0)) + if (IsStateInitializing() && (rval != 0)) { - mState = kStateOpen; + SetState(kStateOpen); FreeMbedtls(); } @@ -453,7 +460,7 @@ void SecureTransport::Close(void) { Disconnect(); - mState = kStateClosed; + SetState(kStateClosed); mTimerSet = false; mTransportCallback.Clear(); @@ -463,10 +470,10 @@ void SecureTransport::Close(void) void SecureTransport::Disconnect(void) { - VerifyOrExit(mState == kStateConnecting || mState == kStateConnected); + VerifyOrExit(IsStateConnectingOrConnected()); mbedtls_ssl_close_notify(&mSsl); - mState = kStateCloseNotify; + SetState(kStateCloseNotify); mTimer.Start(kGuardTimeNewConnectionMilli); mMessageInfo.Clear(); @@ -561,7 +568,7 @@ Error SecureTransport::GetPeerCertificateBase64(unsigned char *aPeerCert, size_t { Error error = kErrorNone; - VerifyOrExit(mState == kStateConnected, error = kErrorInvalidState); + VerifyOrExit(IsStateConnected(), error = kErrorInvalidState); #if (MBEDTLS_VERSION_NUMBER >= 0x03010000) VerifyOrExit(mbedtls_base64_encode(aPeerCert, aCertBufferSize, aCertLength, @@ -1004,22 +1011,15 @@ void SecureTransport::HandleTimer(Timer &aTimer) void SecureTransport::HandleTimer(void) { - switch (mState) + if (IsStateConnectingOrConnected()) { - case kStateConnecting: - case kStateConnected: Process(); - break; - - case kStateCloseNotify: - mState = kStateOpen; + } + else if (IsStateCloseNotify()) + { + SetState(kStateOpen); mTimer.Stop(); mConnectedCallback.InvokeIfSet(false); - break; - - default: - OT_ASSERT(false); - OT_UNREACHABLE_CODE(break); } } @@ -1029,15 +1029,15 @@ void SecureTransport::Process(void) bool shouldDisconnect = false; int rval; - while ((mState == kStateConnecting) || (mState == kStateConnected)) + while (IsStateConnectingOrConnected()) { - if (mState == kStateConnecting) + if (IsStateConnecting()) { rval = mbedtls_ssl_handshake(&mSsl); if (mSsl.MBEDTLS_PRIVATE(state) == MBEDTLS_SSL_HANDSHAKE_OVER) { - mState = kStateConnected; + SetState(kStateConnected); mConnectedCallback.InvokeIfSet(true); } } @@ -1174,6 +1174,31 @@ Error SecureTransport::HandleSecureTransportSend(const uint8_t *aBuf, return error; } +#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) + +const char *SecureTransport::StateToString(State aState) +{ + static const char *const kStateStrings[] = { + "Closed", // (0) kStateClosed + "Open", // (1) kStateOpen + "Initializing", // (2) kStateInitializing + "Connecting", // (3) kStateConnecting + "Connected", // (4) kStateConnected + "CloseNotify", // (5) kStateCloseNotify + }; + + static_assert(0 == kStateClosed, "kStateClosed valid is incorrect"); + static_assert(1 == kStateOpen, "kStateOpen valid is incorrect"); + static_assert(2 == kStateInitializing, "kStateInitializing valid is incorrect"); + static_assert(3 == kStateConnecting, "kStateConnecting valid is incorrect"); + static_assert(4 == kStateConnected, "kStateConnected valid is incorrect"); + static_assert(5 == kStateCloseNotify, "kStateCloseNotify valid is incorrect"); + + return kStateStrings[aState]; +} + +#endif + } // namespace MeshCoP } // namespace ot diff --git a/src/core/meshcop/secure_transport.hpp b/src/core/meshcop/secure_transport.hpp index ef51f5e28..ddeb13a8c 100644 --- a/src/core/meshcop/secure_transport.hpp +++ b/src/core/meshcop/secure_transport.hpp @@ -71,6 +71,7 @@ #include "common/callback.hpp" #include "common/locator.hpp" +#include "common/log.hpp" #include "common/message.hpp" #include "common/random.hpp" #include "common/timer.hpp" @@ -435,7 +436,15 @@ class SecureTransport : public InstanceLocator */ const Ip6::MessageInfo &GetMessageInfo(void) const { return mMessageInfo; } - void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + /** + * Checks and handles a received message provided to the SecureTransport object. If checks based on + * the message info and current connection state pass, the message is processed. + * + * @param[in] aMessage A reference to the message to receive. + * @param[in] aMessageInfo A reference to the message info associated with @p aMessage. + * + */ + void HandleReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); private: enum State : uint8_t @@ -459,6 +468,15 @@ class SecureTransport : public InstanceLocator static constexpr size_t kSecureTransportKeyBlockSize = 40; static constexpr size_t kSecureTransportRandomBufferSize = 32; + bool IsStateClosed(void) const { return mState == kStateClosed; } + bool IsStateOpen(void) const { return mState == kStateOpen; } + bool IsStateInitializing(void) const { return mState == kStateInitializing; } + bool IsStateConnecting(void) const { return mState == kStateConnecting; } + bool IsStateConnected(void) const { return mState == kStateConnected; } + bool IsStateCloseNotify(void) const { return mState == kStateCloseNotify; } + bool IsStateConnectingOrConnected(void) const { return mState == kStateConnecting || mState == kStateConnected; } + void SetState(State aState); + void FreeMbedtls(void); Error Setup(bool aClient); @@ -530,13 +548,17 @@ class SecureTransport : public InstanceLocator static void HandleTimer(Timer &aTimer); void HandleTimer(void); - static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); + static void HandleReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); - void HandleSecureTransportReceive(const uint8_t *aBuf, uint16_t aLength); + void HandleReceive(const uint8_t *aBuf, uint16_t aLength); Error HandleSecureTransportSend(const uint8_t *aBuf, uint16_t aLength, Message::SubType aMessageSubType); void Process(void); +#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) + static const char *StateToString(State aState); +#endif + State mState; int mCipherSuites[2]; diff --git a/src/core/mtd.cmake b/src/core/mtd.cmake index e9b831c24..ae8d9e3ef 100644 --- a/src/core/mtd.cmake +++ b/src/core/mtd.cmake @@ -29,7 +29,9 @@ add_library(openthread-mtd) target_compile_definitions(openthread-mtd PRIVATE + OPENTHREAD_FTD=0 OPENTHREAD_MTD=1 + OPENTHREAD_RADIO=0 ) target_compile_options(openthread-mtd PRIVATE diff --git a/src/core/net/dns_types.cpp b/src/core/net/dns_types.cpp index aa19c73bf..eecc9ff29 100644 --- a/src/core/net/dns_types.cpp +++ b/src/core/net/dns_types.cpp @@ -100,6 +100,69 @@ Error Header::ResponseCodeToError(Response aResponse) return error; } +bool Name::Matches(const char *aFirstLabel, const char *aLabels, const char *aDomain) const +{ + bool matches = false; + + VerifyOrExit(!IsEmpty()); + + if (IsFromCString()) + { + const char *namePtr = mString; + + if (aFirstLabel != nullptr) + { + matches = CompareAndSkipLabels(namePtr, aFirstLabel, kLabelSeparatorChar); + VerifyOrExit(matches); + } + + matches = CompareAndSkipLabels(namePtr, aLabels, kLabelSeparatorChar); + VerifyOrExit(matches); + + matches = CompareAndSkipLabels(namePtr, aDomain, kNullChar); + } + else + { + uint16_t offset = mOffset; + + if (aFirstLabel != nullptr) + { + SuccessOrExit(CompareLabel(*mMessage, offset, aFirstLabel)); + } + + SuccessOrExit(CompareMultipleLabels(*mMessage, offset, aLabels)); + SuccessOrExit(CompareName(*mMessage, offset, aDomain)); + matches = true; + } + +exit: + return matches; +} + +bool Name::CompareAndSkipLabels(const char *&aNamePtr, const char *aLabels, char aExpectedNextChar) +{ + // Compares `aNamePtr` to the label string `aLabels` followed by + // the `aExpectedNextChar`(using case-insensitive match). Upon + // successful comparison, `aNamePtr` is advanced to point after + // the matched portion. + + bool matches = false; + uint16_t len = StringLength(aLabels, kMaxNameSize); + + VerifyOrExit(len < kMaxNameSize); + + VerifyOrExit(StringStartsWith(aNamePtr, aLabels, kStringCaseInsensitiveMatch)); + aNamePtr += len; + + VerifyOrExit(*aNamePtr == aExpectedNextChar); + aNamePtr++; + + matches = true; + +exit: + return matches; +} + Error Name::AppendTo(Message &aMessage) const { Error error; @@ -369,6 +432,27 @@ Error Name::CompareLabel(const Message &aMessage, uint16_t &aOffset, const char return error; } +Error Name::CompareMultipleLabels(const Message &aMessage, uint16_t &aOffset, const char *aLabels) +{ + Error error; + LabelIterator iterator(aMessage, aOffset); + + while (true) + { + SuccessOrExit(error = iterator.GetNextLabel()); + VerifyOrExit(iterator.CompareLabel(aLabels, !kIsSingleLabel), error = kErrorNotFound); + + if (*aLabels == kNullChar) + { + aOffset = iterator.mNextLabelOffset; + ExitNow(); + } + } + +exit: + return error; +} + Error Name::CompareName(const Message &aMessage, uint16_t &aOffset, const char *aName) { Error error; diff --git a/src/core/net/dns_types.hpp b/src/core/net/dns_types.hpp index 9f8a93093..5428713aa 100644 --- a/src/core/net/dns_types.hpp +++ b/src/core/net/dns_types.hpp @@ -511,8 +511,24 @@ class Name : public Clearable */ static constexpr uint8_t kMaxLabelLength = kMaxLabelSize - 1; + /** + * Dot character separating labels in a name. + * + */ static constexpr char kLabelSeparatorChar = '.'; + /** + * Represents a string buffer (with `kMaxNameSize`) intended to hold a DNS name. + * + */ + typedef char Buffer[kMaxNameSize]; + + /** + * Represents a string buffer (with `kMaxLabelSize`) intended to hold a DNS label. + * + */ + typedef char LabelBuffer[kMaxLabelSize]; + /** * Represents the name type. * @@ -646,6 +662,32 @@ class Name : public Clearable return *mMessage; } + /** + * Matches the `Name` with a given set of labels and domain name. + * + * This method allows the caller to specify name components separately, enabling scenarios like comparing "service + * instance name" with separate instance label (which can include dot character), service type, and domain strings. + * + * @p aFirstLabel can be `nullptr` if not needed. But if non-null, it is treated as a single label and can itself + * include dot `.` character. + * + * The @p aLabels MUST NOT be `nullptr` and MUST follow "..", i.e., a sequence of one or + * more labels separated by dot '.' char, and it MUST NOT end with dot `.`. + * + * @p aDomain MUST NOT be `nullptr` and MUST have at least one label and MUST always end with a dot `.` character. + * + * If the above conditions are not satisfied, the behavior of this method is undefined. + * + * @param[in] aFirstLabel A first label to check. Can be `nullptr`. + * @param[in] aLabels A string of dot separated labels, MUST NOT end with dot. + * @param[in] aDomain Domain name. MUST end with dot. + * + * @retval TRUE The name matches the given components. + * @retval FALSE The name does not match the given components. + * + */ + bool Matches(const char *aFirstLabel, const char *aLabels, const char *aDomain) const; + /** * Encodes and appends the name to a message. * @@ -821,6 +863,35 @@ class Name : public Clearable */ static Error ReadName(const Message &aMessage, uint16_t &aOffset, char *aNameBuffer, uint16_t aNameBufferSize); + /** + * Reads a full name from a message. + * + * On successful read, the read name follows "...", i.e., a sequence of labels separated by + * dot '.' character. The read name will ALWAYS end with a dot. + * + * Verifies that the labels after the first label in message do not contain any dot character. If they do, + * returns `kErrorParse`. + * + * @tparam kNameBufferSize Size of the string buffer array. + * + * @param[in] aMessage The message to read the name from. `aMessage.GetOffset()` MUST point to + * the start of DNS header (this is used to handle compressed names). + * @param[in,out] aOffset On input, the offset in @p aMessage pointing to the start of the name field. + * On exit (when parsed successfully), @p aOffset is updated to point to the byte + * after the end of name field. + * @param[out] aNameBuffer Reference to a name string buffer to output the read name. + * + * @retval kErrorNone Successfully read the name, @p aNameBuffer and @p Offset are updated. + * @retval kErrorParse Name could not be parsed (invalid format). + * @retval kErrorNoBufs Name could not fit in @p aNameBuffer. + * + */ + template + static Error ReadName(const Message &aMessage, uint16_t &aOffset, char (&aNameBuffer)[kNameBufferSize]) + { + return ReadName(aMessage, aOffset, aNameBuffer, kNameBufferSize); + } + /** * Compares a single name label from a message with a given label string. * @@ -845,6 +916,29 @@ class Name : public Clearable */ static Error CompareLabel(const Message &aMessage, uint16_t &aOffset, const char *aLabel); + /** + * Parses and compares multiple name labels from a message. + * + * Can be used to read and compare a group of labels from an encoded DNS name in a message with possibly more + * labels remaining to read. + * + * The @p aLabels must follow "..", i.e., a sequence of labels separated by dot '.' char. + * + * @param[in] aMessage The message to read the labels from to compare. `aMessage.GetOffset()` MUST point + * to the start of DNS header (this is used to handle compressed names). + * @param[in,out] aOffset On input, the offset in @p aMessage pointing to the start of the labels to read. + * On exit and only when all labels are successfully read and match @p aLabels, + * @p aOffset is updated to point to the start of the next label. + * @param[in] aLabels A pointer to a null terminated string containing the labels to compare with. + * + * @retval kErrorNone The labels from @p aMessage matches @p aLabels. @p aOffset is updated. + * @retval kErrorNotFound The labels from @p aMessage does not match @p aLabel (note that @p aOffset is not + * updated in this case). + * @retval kErrorParse Name could not be parsed (invalid format). + * + */ + static Error CompareMultipleLabels(const Message &aMessage, uint16_t &aOffset, const char *aLabels); + /** * Parses and compares a full name from a message with a given name. * @@ -928,14 +1022,14 @@ class Name : public Clearable static Error CompareName(const Message &aMessage, uint16_t &aOffset, const Name &aName); /** - * Extracts label(s) from a full name by checking that it contains a given suffix name (e.g., suffix name can be + * Extracts label(s) from a name by checking that it contains a given suffix name (e.g., suffix name can be * a domain name) and removing it. * - * Both @p aName and @p aSuffixName must be full DNS name and end with ('.'), otherwise the behavior of this method - * is undefined. + * Both @p aName and @p aSuffixName MUST follow the same style regarding inclusion of trailing dot ('.'). Otherwise + * `kErrorParse` is returned. * - * @param[in] aName The full name to extract labels from. - * @param[in] aSuffixName The suffix name (e.g. can be domain name). + * @param[in] aName The name to extract labels from. + * @param[in] aSuffixName The suffix name (e.g., can be domain name). * @param[out] aLabels Pointer to buffer to copy the extracted labels. * @param[in] aLabelsSize Size of @p aLabels buffer. * @@ -946,6 +1040,30 @@ class Name : public Clearable */ static Error ExtractLabels(const char *aName, const char *aSuffixName, char *aLabels, uint16_t aLabelsSize); + /** + * Extracts label(s) from a name by checking that it contains a given suffix name (e.g., suffix name can be + * a domain name) and removing it. + * + * Both @p aName and @p aSuffixName MUST follow the same style regarding inclusion of trailing dot ('.'). Otherwise + * `kErrorParse` is returned. + * + * @tparam kLabelsBufferSize Size of the buffer string. + * + * @param[in] aName The name to extract labels from. + * @param[in] aSuffixName The suffix name (e.g., can be domain name). + * @param[out] aLabelsBuffer A buffer to copy the extracted labels. + * + * @retval kErrorNone Successfully extracted the labels, @p aLabels is updated. + * @retval kErrorParse @p aName does not contain @p aSuffixName. + * @retval kErrorNoBufs Could not fit the labels in @p aLabels. + * + */ + template + static Error ExtractLabels(const char *aName, const char *aSuffixName, char (&aLabels)[kLabelsBufferSize]) + { + return ExtractLabels(aName, aSuffixName, aLabels, kLabelsBufferSize); + } + /** * Tests if a DNS name is a sub-domain of a given domain. * @@ -1025,6 +1143,7 @@ class Name : public Clearable { } + static bool CompareAndSkipLabels(const char *&aNamePtr, const char *aLabels, char aExpectedNextChar); static Error AppendLabel(const char *aLabel, uint8_t aLength, Message &aMessage); const char *mString; // String containing the name or `nullptr` if name is not from string. @@ -1660,6 +1779,36 @@ class PtrRecord : public ResourceRecord char *aNameBuffer, uint16_t aNameBufferSize) const; + /** + * Parses and reads the PTR name from a message. + * + * This is a template variation of the previous method with name and label buffer sizes as template parameters. + * + * @tparam kLabelBufferSize The size of label buffer. + * @tparam kNameBufferSize The size of name buffer. + * + * @param[in] aMessage The message to read from. `aMessage.GetOffset()` MUST point to the start of + * DNS header. + * @param[in,out] aOffset On input, the offset in @p aMessage to the start of PTR name field. + * On exit, when successfully read, @p aOffset is updated to point to the byte + * after the entire PTR record (skipping over the record). + * @param[out] aLabelBuffer A char array buffer to output the first label as a null-terminated C string. + * @param[out] aNameBuffer A char array to output the rest of name (after first label). + * + * @retval kErrorNone The PTR name was read successfully. @p aOffset, @aLabelBuffer and @aNameBuffer are updated. + * @retval kErrorParse The PTR record in @p aMessage could not be parsed (invalid format). + * @retval kErrorNoBufs Either label or name could not fit in the related given buffers. + * + */ + template + Error ReadPtrName(const Message &aMessage, + uint16_t &aOffset, + char (&aLabelBuffer)[kLabelBufferSize], + char (&aNameBuffer)[kNameBufferSize]) const + { + return ReadPtrName(aMessage, aOffset, aLabelBuffer, kLabelBufferSize, aNameBuffer, kNameBufferSize); + } + } OT_TOOL_PACKED_END; /** @@ -1868,6 +2017,32 @@ class SrvRecord : public ResourceRecord /* aSkipRecord */ true); } + /** + * Parses and reads the SRV target host name from a message. + * + * Also verifies that the SRV record is well-formed (e.g., the record data length `GetLength()` matches + * the SRV encoded name). + * + * @tparam kNameBufferSize Size of the name buffer. + * + * @param[in] aMessage The message to read from. `aMessage.GetOffset()` MUST point to the start of + * DNS header. + * @param[in,out] aOffset On input, the offset in @p aMessage to start of target host name field. + * On exit when successfully read, @p aOffset is updated to point to the byte + * after the entire SRV record (skipping over the record). + * @param[out] aNameBuffer A char array to output the read name as a null-terminated C string + * + * @retval kErrorNone The host name was read successfully. @p aOffset and @p aNameBuffer are updated. + * @retval kErrorParse The SRV record in @p aMessage could not be parsed (invalid format). + * @retval kErrorNoBufs Name could not fit in @p aNameBuffer. + * + */ + template + Error ReadTargetHostName(const Message &aMessage, uint16_t &aOffset, char (&aNameBuffer)[kNameBufferSize]) const + { + return ReadTargetHostName(aMessage, aOffset, aNameBuffer, kNameBufferSize); + } + private: uint16_t mPriority; uint16_t mWeight; diff --git a/src/core/net/dnssd_server.cpp b/src/core/net/dnssd_server.cpp index ea59c08d5..385eb88f3 100644 --- a/src/core/net/dnssd_server.cpp +++ b/src/core/net/dnssd_server.cpp @@ -412,12 +412,12 @@ Error Server::Response::ParseQueryName(void) // Parses and validates the query name and updates // the name compression offsets. - Error error = kErrorNone; - DnsName name; - uint16_t offset; + Error error = kErrorNone; + Name::Buffer name; + uint16_t offset; offset = sizeof(Header); - SuccessOrExit(error = Name::ReadName(*mMessage, offset, name, sizeof(name))); + SuccessOrExit(error = Name::ReadName(*mMessage, offset, name)); switch (mType) { @@ -446,9 +446,9 @@ Error Server::Response::ParseQueryName(void) while (true) { - DnsLabel label; - uint8_t labelLength = sizeof(label); - uint16_t comapreOffset; + Name::LabelBuffer label; + uint8_t labelLength = sizeof(label); + uint16_t comapreOffset; SuccessOrExit(error = Name::ReadLabel(*mMessage, offset, label, labelLength)); @@ -472,7 +472,7 @@ Error Server::Response::ParseQueryName(void) return error; } -void Server::Response::ReadQueryName(DnsName &aName) const { Server::ReadQueryName(*mMessage, aName); } +void Server::Response::ReadQueryName(Name::Buffer &aName) const { Server::ReadQueryName(*mMessage, aName); } bool Server::Response::QueryNameMatches(const char *aName) const { return Server::QueryNameMatches(*mMessage, aName); } @@ -526,12 +526,12 @@ Error Server::Response::AppendSrvRecord(const char *aHostName, uint16_t aWeight, uint16_t aPort) { - Error error = kErrorNone; - SrvRecord srvRecord; - uint16_t recordOffset; - DnsName hostLabels; + Error error = kErrorNone; + SrvRecord srvRecord; + uint16_t recordOffset; + Name::Buffer hostLabels; - SuccessOrExit(error = Name::ExtractLabels(aHostName, kDefaultDomainName, hostLabels, sizeof(hostLabels))); + SuccessOrExit(error = Name::ExtractLabels(aHostName, kDefaultDomainName, hostLabels)); srvRecord.Init(); srvRecord.SetTtl(aTtl); @@ -674,7 +674,7 @@ uint8_t Server::GetNameLength(const char *aName) #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) void Server::Response::Log(void) const { - DnsName name; + Name::Buffer name; ReadQueryName(name); LogInfo("%s query for '%s'", QueryTypeToString(mType), name); @@ -830,16 +830,16 @@ bool Server::Response::QueryNameMatchesService(const Srp::Server::Service &aServ #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE bool Server::ShouldForwardToUpstream(const Request &aRequest) { - bool shouldForward = false; - uint16_t readOffset; - DnsName name; + bool shouldForward = false; + uint16_t readOffset; + Name::Buffer name; VerifyOrExit(aRequest.mHeader.IsRecursionDesiredFlagSet()); readOffset = sizeof(Header); for (uint16_t i = 0; i < aRequest.mHeader.GetQuestionCount(); i++) { - SuccessOrExit(Name::ReadName(*aRequest.mMessage, readOffset, name, sizeof(name))); + SuccessOrExit(Name::ReadName(*aRequest.mMessage, readOffset, name)); readOffset += sizeof(Question); VerifyOrExit(!Name::IsSubDomainOf(name, kDefaultDomainName)); @@ -866,6 +866,10 @@ void Server::OnUpstreamQueryDone(UpstreamQueryTransaction &aQueryTransaction, Me { error = mSocket.SendTo(*aResponseMessage, aQueryTransaction.GetMessageInfo()); } + else + { + error = kErrorResponseTimeout; + } ResetUpstreamQueryTransaction(aQueryTransaction, error); @@ -886,7 +890,7 @@ Server::UpstreamQueryTransaction *Server::AllocateUpstreamQueryTransaction(const } } - VerifyOrExit(newTxn != nullptr); + VerifyOrExit(newTxn != nullptr, mCounters.mUpstreamDnsCounters.mFailures++); newTxn->Init(aMessageInfo); LogInfo("Upstream query transaction %d initialized.", static_cast(newTxn - mUpstreamQueryTransactions)); @@ -905,6 +909,7 @@ Error Server::ResolveByUpstream(const Request &aRequest) VerifyOrExit(txn != nullptr, error = kErrorNoBufs); otPlatDnsStartUpstreamQuery(&GetInstance(), txn, aRequest.mMessage); + mCounters.mUpstreamDnsCounters.mQueries++; exit: return error; @@ -915,7 +920,7 @@ void Server::ResolveByProxy(Response &aResponse, const Ip6::MessageInfo &aMessag { ProxyQuery *query; ProxyQueryInfo info; - DnsName name; + Name::Buffer name; VerifyOrExit(mQuerySubscribe.IsSet()); @@ -950,11 +955,11 @@ void Server::ResolveByProxy(Response &aResponse, const Ip6::MessageInfo &aMessag return; } -void Server::ReadQueryName(const Message &aQuery, DnsName &aName) +void Server::ReadQueryName(const Message &aQuery, Name::Buffer &aName) { uint16_t offset = sizeof(Header); - IgnoreError(Name::ReadName(aQuery, offset, aName, sizeof(aName))); + IgnoreError(Name::ReadName(aQuery, offset, aName)); } bool Server::QueryNameMatches(const Message &aQuery, const char *aName) @@ -979,20 +984,20 @@ void Server::ProxyQueryInfo::UpdateIn(ProxyQuery &aQuery) const aQuery.Write(aQuery.GetLength() - sizeof(ProxyQueryInfo), *this); } -Error Server::Response::ExtractServiceInstanceLabel(const char *aInstanceName, DnsLabel &aLabel) +Error Server::Response::ExtractServiceInstanceLabel(const char *aInstanceName, Name::LabelBuffer &aLabel) { - uint16_t offset; - DnsName serviceName; + uint16_t offset; + Name::Buffer serviceName; offset = mOffsets.mServiceName; - IgnoreError(Name::ReadName(*mMessage, offset, serviceName, sizeof(serviceName))); + IgnoreError(Name::ReadName(*mMessage, offset, serviceName)); - return Name::ExtractLabels(aInstanceName, serviceName, aLabel, sizeof(aLabel)); + return Name::ExtractLabels(aInstanceName, serviceName, aLabel); } void Server::RemoveQueryAndPrepareResponse(ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, Response &aResponse) { - DnsName name; + Name::Buffer name; mProxyQueries.Dequeue(aQuery); aInfo.RemoveFrom(aQuery); @@ -1021,7 +1026,7 @@ void Server::Response::Answer(const ServiceInstanceInfo &aInstanceInfo, const Ip if (mType == kPtrQuery) { - DnsLabel instanceLabel; + Name::LabelBuffer instanceLabel; SuccessOrExit(error = ExtractServiceInstanceLabel(aInstanceInfo.mFullName, instanceLabel)); mSection = kAnswerSection; @@ -1148,7 +1153,7 @@ const otDnssdQuery *Server::GetNextQuery(const otDnssdQuery *aQuery) const return (query == nullptr) ? mProxyQueries.GetHead() : query->GetNext(); } -Server::DnsQueryType Server::GetQueryTypeAndName(const otDnssdQuery *aQuery, char (&aName)[Name::kMaxNameSize]) +Server::DnsQueryType Server::GetQueryTypeAndName(const otDnssdQuery *aQuery, Dns::Name::Buffer &aName) { const ProxyQuery *query = static_cast(aQuery); ProxyQueryInfo info; @@ -1277,10 +1282,12 @@ void Server::ResetUpstreamQueryTransaction(UpstreamQueryTransaction &aTxn, Error OT_UNUSED_VARIABLE(index); if (aError == kErrorNone) { + mCounters.mUpstreamDnsCounters.mResponses++; LogInfo("Upstream query transaction %d completed.", index); } else { + mCounters.mUpstreamDnsCounters.mFailures++; LogWarn("Upstream query transaction %d closed: %s.", index, ErrorToString(aError)); } aTxn.Reset(); diff --git a/src/core/net/dnssd_server.hpp b/src/core/net/dnssd_server.hpp index de01d5534..3b6b67993 100644 --- a/src/core/net/dnssd_server.hpp +++ b/src/core/net/dnssd_server.hpp @@ -258,7 +258,7 @@ class Server : public InstanceLocator, private NonCopyable * @returns The DNS-SD query type. * */ - static DnsQueryType GetQueryTypeAndName(const otDnssdQuery *aQuery, char (&aName)[Name::kMaxNameSize]); + static DnsQueryType GetQueryTypeAndName(const otDnssdQuery *aQuery, Dns::Name::Buffer &aName); /** * Returns the counters of the DNS-SD server. @@ -297,8 +297,6 @@ class Server : public InstanceLocator, private NonCopyable static constexpr uint16_t kMaxConcurrentUpstreamQueries = 32; typedef Header::Response ResponseCode; - typedef char DnsName[Name::kMaxNameSize]; - typedef char DnsLabel[Name::kMaxLabelSize]; typedef Message ProxyQuery; typedef MessageQueue ProxyQueryList; @@ -347,7 +345,7 @@ class Server : public InstanceLocator, private NonCopyable void SetResponseCode(ResponseCode aResponseCode) { mHeader.SetResponseCode(aResponseCode); } ResponseCode AddQuestionsFrom(const Request &aRequest); Error ParseQueryName(void); - void ReadQueryName(DnsName &aName) const; + void ReadQueryName(Name::Buffer &aName) const; bool QueryNameMatches(const char *aName) const; Error AppendQueryName(void); Error AppendPtrRecord(const char *aInstanceLabel, uint32_t aTtl); @@ -367,7 +365,7 @@ class Server : public InstanceLocator, private NonCopyable void Send(const Ip6::MessageInfo &aMessageInfo); void Answer(const HostInfo &aHostInfo, const Ip6::MessageInfo &aMessageInfo); void Answer(const ServiceInstanceInfo &aInstanceInfo, const Ip6::MessageInfo &aMessageInfo); - Error ExtractServiceInstanceLabel(const char *aInstanceName, DnsLabel &aLabel); + Error ExtractServiceInstanceLabel(const char *aInstanceName, Name::LabelBuffer &aLabel); #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE Error ResolveBySrp(void); bool QueryNameMatchesService(const Srp::Server::Service &aService) const; @@ -408,7 +406,7 @@ class Server : public InstanceLocator, private NonCopyable void ResolveByProxy(Response &aResponse, const Ip6::MessageInfo &aMessageInfo); void RemoveQueryAndPrepareResponse(ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, Response &aResponse); void Finalize(ProxyQuery &aQuery, ResponseCode aResponseCode); - static void ReadQueryName(const Message &aQuery, DnsName &aName); + static void ReadQueryName(const Message &aQuery, Name::Buffer &aName); static bool QueryNameMatches(const Message &aQuery, const char *aName); #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE diff --git a/src/core/net/srp_client.cpp b/src/core/net/srp_client.cpp index cbc24c4ff..fc4a417b5 100644 --- a/src/core/net/srp_client.cpp +++ b/src/core/net/srp_client.cpp @@ -961,19 +961,16 @@ Error Client::ReadOrGenerateKey(Crypto::Ecdsa::P256::KeyPairAsRef &aKeyRef) if (error == kErrorNone) { - Crypto::Ecdsa::P256::PublicKey publicKey; - - if (keyPair.GetPublicKey(publicKey) == kErrorNone) + if (aKeyRef.ImportKeyPair(keyPair) != kErrorNone) { - SuccessOrExit(error = aKeyRef.ImportKeyPair(keyPair)); - IgnoreError(Get().Delete()); - ExitNow(); + SuccessOrExit(error = aKeyRef.Generate()); } IgnoreError(Get().Delete()); } - - error = aKeyRef.Generate(); - + else + { + SuccessOrExit(error = aKeyRef.Generate()); + } exit: return error; } diff --git a/src/core/net/srp_server.cpp b/src/core/net/srp_server.cpp index aaaaaa71f..946b84163 100644 --- a/src/core/net/srp_server.cpp +++ b/src/core/net/srp_server.cpp @@ -796,13 +796,13 @@ void Server::ProcessDnsUpdate(Message &aMessage, MessageMetadata &aMetadata) Error Server::ProcessZoneSection(const Message &aMessage, MessageMetadata &aMetadata) const { - Error error = kErrorNone; - char name[Dns::Name::kMaxNameSize]; - uint16_t offset = aMetadata.mOffset; + Error error = kErrorNone; + Dns::Name::Buffer name; + uint16_t offset = aMetadata.mOffset; VerifyOrExit(aMetadata.mDnsHeader.GetZoneRecordCount() == 1, error = kErrorParse); - SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name))); + SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name)); // TODO: return `Dns::kResponseNotAuth` for not authorized zone names. VerifyOrExit(StringMatch(name, GetDomain(), kStringCaseInsensitiveMatch), error = kErrorSecurity); SuccessOrExit(error = aMessage.Read(offset, aMetadata.mDnsZone)); @@ -861,10 +861,10 @@ Error Server::ProcessHostDescriptionInstruction(Host &aHost, for (uint16_t numRecords = aMetadata.mDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--) { - char name[Dns::Name::kMaxNameSize]; + Dns::Name::Buffer name; Dns::ResourceRecord record; - SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name))); + SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name)); SuccessOrExit(error = aMessage.Read(offset, record)); @@ -952,9 +952,9 @@ Error Server::ProcessServiceDiscoveryInstructions(Host &aHost, for (uint16_t numRecords = aMetadata.mDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--) { - char serviceName[Dns::Name::kMaxNameSize]; - char instanceLabel[Dns::Name::kMaxLabelSize]; - char instanceServiceName[Dns::Name::kMaxNameSize]; + Dns::Name::Buffer serviceName; + Dns::Name::LabelBuffer instanceLabel; + Dns::Name::Buffer instanceServiceName; String instanceName; Dns::PtrRecord ptrRecord; const char *subServiceName; @@ -962,7 +962,7 @@ Error Server::ProcessServiceDiscoveryInstructions(Host &aHost, bool isSubType; bool isDelete; - SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, serviceName, sizeof(serviceName))); + SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, serviceName)); VerifyOrExit(Dns::Name::IsSubDomainOf(serviceName, GetDomain()), error = kErrorSecurity); error = Dns::ResourceRecord::ReadRecord(aMessage, offset, ptrRecord); @@ -977,8 +977,7 @@ Error Server::ProcessServiceDiscoveryInstructions(Host &aHost, SuccessOrExit(error); - SuccessOrExit(error = ptrRecord.ReadPtrName(aMessage, offset, instanceLabel, sizeof(instanceLabel), - instanceServiceName, sizeof(instanceServiceName))); + SuccessOrExit(error = ptrRecord.ReadPtrName(aMessage, offset, instanceLabel, instanceServiceName)); instanceName.Append("%s.%s", instanceLabel, instanceServiceName); // Class None indicates "Delete an RR from an RRset". @@ -1076,11 +1075,11 @@ Error Server::ProcessServiceDescriptionInstructions(Host &aHost, for (uint16_t numRecords = aMetadata.mDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--) { - char name[Dns::Name::kMaxNameSize]; + Dns::Name::Buffer name; Dns::ResourceRecord record; Service *service; - SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name))); + SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name)); SuccessOrExit(error = aMessage.Read(offset, record)); if (record.GetClass() == Dns::ResourceRecord::kClassAny) @@ -1102,9 +1101,8 @@ Error Server::ProcessServiceDescriptionInstructions(Host &aHost, if (record.GetType() == Dns::ResourceRecord::kTypeSrv) { - Dns::SrvRecord srvRecord; - char hostName[Dns::Name::kMaxNameSize]; - uint16_t hostNameLength = sizeof(hostName); + Dns::SrvRecord srvRecord; + Dns::Name::Buffer hostName; VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed); @@ -1113,7 +1111,7 @@ Error Server::ProcessServiceDescriptionInstructions(Host &aHost, SuccessOrExit(error = aMessage.Read(offset, srvRecord)); offset += sizeof(srvRecord); - SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, hostName, hostNameLength)); + SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, hostName)); VerifyOrExit(Dns::Name::IsSubDomainOf(name, GetDomain()), error = kErrorSecurity); VerifyOrExit(aHost.Matches(hostName), error = kErrorFailed); @@ -1179,22 +1177,22 @@ bool Server::IsValidDeleteAllRecord(const Dns::ResourceRecord &aRecord) Error Server::ProcessAdditionalSection(Host *aHost, const Message &aMessage, MessageMetadata &aMetadata) const { - Error error = kErrorNone; - Dns::OptRecord optRecord; - Dns::LeaseOption leaseOption; - Dns::SigRecord sigRecord; - char name[2]; // The root domain name (".") is expected. - uint16_t offset = aMetadata.mOffset; - uint16_t sigOffset; - uint16_t sigRdataOffset; - char signerName[Dns::Name::kMaxNameSize]; - uint16_t signatureLength; + Error error = kErrorNone; + Dns::OptRecord optRecord; + Dns::LeaseOption leaseOption; + Dns::SigRecord sigRecord; + char name[2]; // The root domain name (".") is expected. + uint16_t offset = aMetadata.mOffset; + uint16_t sigOffset; + uint16_t sigRdataOffset; + Dns::Name::Buffer signerName; + uint16_t signatureLength; VerifyOrExit(aMetadata.mDnsHeader.GetAdditionalRecordCount() == 2, error = kErrorFailed); // EDNS(0) Update Lease Option. - SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name))); + SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name)); SuccessOrExit(error = aMessage.Read(offset, optRecord)); SuccessOrExit(error = leaseOption.ReadFrom(aMessage, offset + sizeof(optRecord), optRecord.GetLength())); @@ -1221,7 +1219,7 @@ Error Server::ProcessAdditionalSection(Host *aHost, const Message &aMessage, Mes // SIG(0). sigOffset = offset; - SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name))); + SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name)); SuccessOrExit(error = aMessage.Read(offset, sigRecord)); VerifyOrExit(sigRecord.IsValid(), error = kErrorParse); @@ -1232,7 +1230,7 @@ Error Server::ProcessAdditionalSection(Host *aHost, const Message &aMessage, Mes // implemented because the end device may not be able to get // the synchronized date/time. - SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, signerName, sizeof(signerName))); + SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, signerName)); signatureLength = sigRecord.GetLength() - (offset - sigRdataOffset); offset += signatureLength; @@ -1383,9 +1381,9 @@ void Server::InformUpdateHandlerOrCommit(Error aError, Host &aHost, const Messag for (const Heap::String &subType : service.mSubTypes) { - char label[Dns::Name::kMaxLabelSize]; + Dns::Name::LabelBuffer label; - IgnoreError(Service::ParseSubTypeServiceName(subType.AsCString(), label, sizeof(label))); + IgnoreError(Service::ParseSubTypeServiceName(subType.AsCString(), label)); LogInfo(" sub-type: %s", label); } } @@ -1892,9 +1890,9 @@ void Server::Service::Log(Action aAction) const for (const Heap::String &subType : mSubTypes) { - char label[Dns::Name::kMaxLabelSize]; + Dns::Name::LabelBuffer label; - IgnoreError(ParseSubTypeServiceName(subType.AsCString(), label, sizeof(label))); + IgnoreError(ParseSubTypeServiceName(subType.AsCString(), label)); LogInfo(" sub-type: %s", subType.AsCString()); } } diff --git a/src/core/net/srp_server.hpp b/src/core/net/srp_server.hpp index bb73c154a..c506416ec 100644 --- a/src/core/net/srp_server.hpp +++ b/src/core/net/srp_server.hpp @@ -407,6 +407,12 @@ class Server : public InstanceLocator, private NonCopyable bool Matches(const char *aInstanceName) const; void Log(Action aAction) const; + template + static Error ParseSubTypeServiceName(const char *aSubTypeServiceName, char (&aLabel)[kLabelSize]) + { + return ParseSubTypeServiceName(aSubTypeServiceName, aLabel, kLabelSize); + } + Service *mNext; Heap::String mInstanceName; Heap::String mInstanceLabel; diff --git a/src/core/openthread-core-config.h b/src/core/openthread-core-config.h index 79640a84f..498eb627c 100644 --- a/src/core/openthread-core-config.h +++ b/src/core/openthread-core-config.h @@ -114,6 +114,7 @@ #include "config/srp_server.h" #include "config/time_sync.h" #include "config/tmf.h" +#include "config/trel.h" #undef OPENTHREAD_CORE_CONFIG_H_IN diff --git a/src/core/radio.cmake b/src/core/radio.cmake index 95ae91533..a41605202 100644 --- a/src/core/radio.cmake +++ b/src/core/radio.cmake @@ -29,6 +29,8 @@ add_library(openthread-radio) target_compile_definitions(openthread-radio PRIVATE + OPENTHREAD_FTD=0 + OPENTHREAD_MTD=0 OPENTHREAD_RADIO=1 OPENTHREAD_RADIO_CLI=0 ) diff --git a/src/core/radio/ble_secure.cpp b/src/core/radio/ble_secure.cpp index fe0a6f5c3..5e5224468 100644 --- a/src/core/radio/ble_secure.cpp +++ b/src/core/radio/ble_secure.cpp @@ -253,7 +253,7 @@ Error BleSecure::HandleBleReceive(uint8_t *aBuf, uint16_t aLength) SuccessOrExit(error = message->AppendBytes(aBuf, aLength)); // Cannot call Receive(..) directly because Setup(..) and mState are private - mTls.HandleUdpReceive(*message, messageInfo); + mTls.HandleReceive(*message, messageInfo); exit: FreeMessage(message); diff --git a/src/core/radio/radio.cpp b/src/core/radio/radio.cpp index bdc46bed3..bd9c8d83a 100644 --- a/src/core/radio/radio.cpp +++ b/src/core/radio/radio.cpp @@ -36,6 +36,18 @@ namespace ot { +const uint8_t Radio::kSupportedChannelPages[kNumChannelPages] = { +#if OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT + kChannelPage0, +#endif +#if OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT + kChannelPage2, +#endif +#if OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT + OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE, +#endif +}; + #if OPENTHREAD_RADIO void Radio::Init(void) { diff --git a/src/core/radio/radio.hpp b/src/core/radio/radio.hpp index 3321abea4..fb587563e 100644 --- a/src/core/radio/radio.hpp +++ b/src/core/radio/radio.hpp @@ -136,33 +136,33 @@ class Radio : public InstanceLocator, private NonCopyable static constexpr uint32_t kSymbolTime = OT_RADIO_SYMBOL_TIME; static constexpr uint8_t kSymbolsPerOctet = OT_RADIO_SYMBOLS_PER_OCTET; static constexpr uint32_t kPhyUsPerByte = kSymbolsPerOctet * kSymbolTime; + static constexpr uint8_t kChannelPage0 = OT_RADIO_CHANNEL_PAGE_0; + static constexpr uint8_t kChannelPage2 = OT_RADIO_CHANNEL_PAGE_2; #if (OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT && OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT) static constexpr uint16_t kNumChannelPages = 2; static constexpr uint32_t kSupportedChannels = OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK | OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK; - static constexpr uint8_t kChannelMin = OT_RADIO_915MHZ_OQPSK_CHANNEL_MIN; - static constexpr uint8_t kChannelMax = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX; - static constexpr uint32_t kSupportedChannelPages = OT_RADIO_CHANNEL_PAGE_0_MASK | OT_RADIO_CHANNEL_PAGE_2_MASK; + static constexpr uint8_t kChannelMin = OT_RADIO_915MHZ_OQPSK_CHANNEL_MIN; + static constexpr uint8_t kChannelMax = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX; #elif OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT - static constexpr uint16_t kNumChannelPages = 1; - static constexpr uint32_t kSupportedChannels = OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK; - static constexpr uint8_t kChannelMin = OT_RADIO_915MHZ_OQPSK_CHANNEL_MIN; - static constexpr uint8_t kChannelMax = OT_RADIO_915MHZ_OQPSK_CHANNEL_MAX; - static constexpr uint32_t kSupportedChannelPages = OT_RADIO_CHANNEL_PAGE_2_MASK; + static constexpr uint16_t kNumChannelPages = 1; + static constexpr uint32_t kSupportedChannels = OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK; + static constexpr uint8_t kChannelMin = OT_RADIO_915MHZ_OQPSK_CHANNEL_MIN; + static constexpr uint8_t kChannelMax = OT_RADIO_915MHZ_OQPSK_CHANNEL_MAX; #elif OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT - static constexpr uint16_t kNumChannelPages = 1; - static constexpr uint32_t kSupportedChannels = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK; - static constexpr uint8_t kChannelMin = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN; - static constexpr uint8_t kChannelMax = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX; - static constexpr uint32_t kSupportedChannelPages = OT_RADIO_CHANNEL_PAGE_0_MASK; + static constexpr uint16_t kNumChannelPages = 1; + static constexpr uint32_t kSupportedChannels = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK; + static constexpr uint8_t kChannelMin = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN; + static constexpr uint8_t kChannelMax = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX; #elif OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT - static constexpr uint16_t kNumChannelPages = 1; - static constexpr uint32_t kSupportedChannels = OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MASK; - static constexpr uint8_t kChannelMin = OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MIN; - static constexpr uint8_t kChannelMax = OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MAX; - static constexpr uint32_t kSupportedChannelPages = (1 << OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE); + static constexpr uint16_t kNumChannelPages = 1; + static constexpr uint32_t kSupportedChannels = OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MASK; + static constexpr uint8_t kChannelMin = OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MIN; + static constexpr uint8_t kChannelMax = OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MAX; #endif + static const uint8_t kSupportedChannelPages[kNumChannelPages]; + static constexpr int8_t kInvalidRssi = OT_RADIO_RSSI_INVALID; ///< Invalid RSSI value. static constexpr int8_t kDefaultReceiveSensitivity = -110; ///< Default receive sensitivity (in dBm). @@ -771,6 +771,63 @@ class Radio : public InstanceLocator, private NonCopyable */ Error GetRegion(uint16_t &aRegionCode) const { return otPlatRadioGetRegion(GetInstancePtr(), &aRegionCode); } + /** + * Indicates whether a given channel page is supported based on the current configurations. + * + * @param[in] aChannelPage The channel page to check. + * + * @retval TRUE The @p aChannelPage is supported by radio. + * @retval FALASE The @p aChannelPage is not supported by radio. + * + */ + static constexpr bool SupportsChannelPage(uint8_t aChannelPage) + { +#if OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT && OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT + return (aChannelPage == kChannelPage0) || (aChannelPage == kChannelPage2); +#elif OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT + return (aChannelPage == kChannelPage0); +#elif OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT + return (aChannelPage == kChannelPage2); +#elif OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT + return (aChannelPage == OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE); +#endif + } + + /** + * Returns the channel mask for a given channel page if supported by the radio. + * + * @param[in] aChannelPage The channel page. + * + * @returns The channel mask for @p aChannelPage if page is supported by the radio, otherwise zero. + * + */ + static uint32_t ChannelMaskForPage(uint8_t aChannelPage) + { + uint32_t mask = 0; + +#if OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT + if (aChannelPage == kChannelPage0) + { + mask = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK; + } +#endif + +#if OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT + if (aChannelPage == kChannelPage1) + { + mask = OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK; + } +#endif + +#if OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT + if (aChannelPage == OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE) + { + mask = OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MASK; + } +#endif + return mask; + } + private: otInstance *GetInstancePtr(void) const { return reinterpret_cast(&InstanceLocator::GetInstance()); } diff --git a/src/core/radio/trel_interface.cpp b/src/core/radio/trel_interface.cpp index d25347733..dc94b4511 100644 --- a/src/core/radio/trel_interface.cpp +++ b/src/core/radio/trel_interface.cpp @@ -352,6 +352,10 @@ void Interface::RemovePeerEntry(Peer &aEntry) mPeerTable.PopBack(); } +const Counters *Interface::GetCounters(void) const { return otPlatTrelGetCounters(&GetInstance()); } + +void Interface::ResetCounters(void) { otPlatTrelResetCounters(&GetInstance()); } + Error Interface::Send(const Packet &aPacket, bool aIsDiscovery) { Error error = kErrorNone; diff --git a/src/core/radio/trel_interface.hpp b/src/core/radio/trel_interface.hpp index 9ef09b2dd..c5750bcf8 100644 --- a/src/core/radio/trel_interface.hpp +++ b/src/core/radio/trel_interface.hpp @@ -59,6 +59,12 @@ class Link; extern "C" void otPlatTrelHandleReceived(otInstance *aInstance, uint8_t *aBuffer, uint16_t aLength); extern "C" void otPlatTrelHandleDiscoveredPeerInfo(otInstance *aInstance, const otPlatTrelPeerInfo *aInfo); +/** + * Represents a group of TREL counters. + * + */ +typedef otTrelCounters Counters; + /** * Represents a TREL link interface. * @@ -205,6 +211,14 @@ class Interface : public InstanceLocator */ const Peer *GetNextPeer(PeerIterator &aIterator) const; + /** + * Returns the number of TREL peers. + * + * @returns The number of TREL peers. + * + */ + uint16_t GetNumberOfPeers(void) const { return mPeerTable.GetLength(); } + /** * Sets the filter mode (enables/disables filtering). * @@ -228,10 +242,27 @@ class Interface : public InstanceLocator */ bool IsFilterEnabled(void) const { return mFiltered; } + /** + * Gets the TREL counters. + * + * The counters are initialized to zero when the TREL platform is initialized. + * + */ + const Counters *GetCounters(void) const; + + /** + * Resets the TREL counters. + * + */ + void ResetCounters(void); + private: +#if OPENTHREAD_COFNIG_TREL_PEER_TABLE_SIZE != 0 + static constexpr uint16_t kPeerTableSize = OPENTHREAD_COFNIG_TREL_PEER_TABLE_SIZE; +#else static constexpr uint16_t kPeerTableExtraEntries = 32; static constexpr uint16_t kPeerTableSize = Mle::kMaxRouters + Mle::kMaxChildren + kPeerTableExtraEntries; - +#endif static const char kTxtRecordExtAddressKey[]; static const char kTxtRecordExtPanIdKey[]; diff --git a/src/core/radio_cli.cmake b/src/core/radio_cli.cmake index 31e7b6dae..cec70bfa9 100644 --- a/src/core/radio_cli.cmake +++ b/src/core/radio_cli.cmake @@ -29,6 +29,8 @@ add_library(openthread-radio-cli) target_compile_definitions(openthread-radio-cli PRIVATE + OPENTHREAD_FTD=0 + OPENTHREAD_MTD=0 OPENTHREAD_RADIO=1 OPENTHREAD_RADIO_CLI=1 ) diff --git a/src/core/thread/announce_begin_server.cpp b/src/core/thread/announce_begin_server.cpp index 4db912dd2..b243d9015 100644 --- a/src/core/thread/announce_begin_server.cpp +++ b/src/core/thread/announce_begin_server.cpp @@ -71,7 +71,7 @@ void AnnounceBeginServer::HandleTmf(Coap::Message &aMessage, uint16_t period; VerifyOrExit(aMessage.IsPostRequest()); - VerifyOrExit((mask = MeshCoP::ChannelMaskTlv::GetChannelMask(aMessage)) != 0); + SuccessOrExit(MeshCoP::ChannelMaskTlv::FindIn(aMessage, mask)); SuccessOrExit(Tlv::Find(aMessage, count)); SuccessOrExit(Tlv::Find(aMessage, period)); diff --git a/src/core/thread/discover_scanner.cpp b/src/core/thread/discover_scanner.cpp index 2425e1e3a..e3c337cd3 100644 --- a/src/core/thread/discover_scanner.cpp +++ b/src/core/thread/discover_scanner.cpp @@ -205,7 +205,7 @@ Mac::TxFrame *DiscoverScanner::PrepareDiscoveryRequestFrame(Mac::TxFrame &aFrame return frame; } -void DiscoverScanner::HandleDiscoveryRequestFrameTxDone(Message &aMessage) +void DiscoverScanner::HandleDiscoveryRequestFrameTxDone(Message &aMessage, Error aError) { switch (mState) { @@ -213,15 +213,28 @@ void DiscoverScanner::HandleDiscoveryRequestFrameTxDone(Message &aMessage) break; case kStateScanning: - // Mark the Discovery Request message for direct tx to ensure it - // is not dequeued and freed by `MeshForwarder` and is ready for - // the next scan channel. Also pause message tx on `MeshForwarder` - // while listening to receive Discovery Responses. - aMessage.SetDirectTransmission(); - aMessage.SetTimestampToNow(); - Get().PauseMessageTransmissions(); - mTimer.Start(kDefaultScanDuration); - break; + if ((aError == kErrorNone) || (aError == kErrorChannelAccessFailure)) + { + // Mark the Discovery Request message for direct tx to ensure it + // is not dequeued and freed by `MeshForwarder` and is ready for + // the next scan channel. Also pause message tx on `MeshForwarder` + // while listening to receive Discovery Responses. + aMessage.SetDirectTransmission(); + aMessage.SetTimestampToNow(); + Get().PauseMessageTransmissions(); + mTimer.Start(kDefaultScanDuration); + break; + } + + // If we encounter other error failures (e.g., `kErrorDrop` due + // to queue management dropping the message or if message being + // evicted), `aMessage` may be immediately freed. This prevents + // us from reusing it to request a scan on the next scan channel. + // As a result, we stop the scan operation in such cases. + + mState = kStateScanDone; + + OT_FALL_THROUGH; case kStateScanDone: HandleDiscoverComplete(); diff --git a/src/core/thread/discover_scanner.hpp b/src/core/thread/discover_scanner.hpp index d9bdd13aa..4753802eb 100644 --- a/src/core/thread/discover_scanner.hpp +++ b/src/core/thread/discover_scanner.hpp @@ -165,7 +165,7 @@ class DiscoverScanner : public InstanceLocator, private NonCopyable // Methods used by `MeshForwarder` Mac::TxFrame *PrepareDiscoveryRequestFrame(Mac::TxFrame &aFrame); - void HandleDiscoveryRequestFrameTxDone(Message &aMessage); + void HandleDiscoveryRequestFrameTxDone(Message &aMessage, Error aError); void Stop(void) { HandleDiscoverComplete(); } // Methods used from `Mle` diff --git a/src/core/thread/energy_scan_server.cpp b/src/core/thread/energy_scan_server.cpp index c3901419c..258580580 100644 --- a/src/core/thread/energy_scan_server.cpp +++ b/src/core/thread/energy_scan_server.cpp @@ -63,12 +63,11 @@ EnergyScanServer::EnergyScanServer(Instance &aInstance) template <> void EnergyScanServer::HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { - uint8_t count; - uint16_t period; - uint16_t scanDuration; - uint32_t mask; - MeshCoP::Tlv tlv; - MeshCoP::ChannelMaskTlv channelMaskTlv; + uint8_t count; + uint16_t period; + uint16_t scanDuration; + uint32_t mask; + MeshCoP::Tlv tlv; VerifyOrExit(aMessage.IsPostRequest()); @@ -76,15 +75,13 @@ void EnergyScanServer::HandleTmf(Coap::Message &aMessage, const SuccessOrExit(Tlv::Find(aMessage, period)); SuccessOrExit(Tlv::Find(aMessage, scanDuration)); - VerifyOrExit((mask = MeshCoP::ChannelMaskTlv::GetChannelMask(aMessage)) != 0); + SuccessOrExit(MeshCoP::ChannelMaskTlv::FindIn(aMessage, mask)); FreeMessage(mReportMessage); mReportMessage = Get().NewPriorityConfirmablePostMessage(kUriEnergyReport); VerifyOrExit(mReportMessage != nullptr); - channelMaskTlv.Init(); - channelMaskTlv.SetChannelMask(mask); - SuccessOrExit(channelMaskTlv.AppendTo(*mReportMessage)); + SuccessOrExit(MeshCoP::ChannelMaskTlv::AppendTo(*mReportMessage, mask)); tlv.SetType(MeshCoP::Tlv::kEnergyList); SuccessOrExit(mReportMessage->Append(tlv)); diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index 4355447f2..df1aa2504 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -202,7 +202,7 @@ void MeshForwarder::PrepareEmptyFrame(Mac::TxFrame &aFrame, const Mac::Address & aFrame.SetPayloadLength(0); } -void MeshForwarder::RemoveMessage(Message &aMessage) +void MeshForwarder::EvictMessage(Message &aMessage) { PriorityQueue *queue = aMessage.GetPriorityQueue(); @@ -217,6 +217,8 @@ void MeshForwarder::RemoveMessage(Message &aMessage) } #endif + FinalizeMessageDirectTx(aMessage, kErrorNoBufs); + if (mSendMessage == &aMessage) { mSendMessage = nullptr; @@ -387,7 +389,7 @@ Error MeshForwarder::UpdateEcnOrDrop(Message &aMessage, bool aPreparingToSend) mTxQueueStats.UpdateFor(aMessage); #endif LogMessage(kMessageQueueMgmtDrop, aMessage); - aMessage.ClearDirectTransmission(); + FinalizeMessageDirectTx(aMessage, kErrorDrop); RemoveMessageIfNoPendingTx(aMessage); } @@ -518,7 +520,7 @@ void MeshForwarder::ApplyDirectTxQueueLimit(Message &aMessage) #endif LogMessage(kMessageFullQueueDrop, aMessage); - aMessage.ClearDirectTransmission(); + FinalizeMessageDirectTx(aMessage, kErrorDrop); RemoveMessageIfNoPendingTx(aMessage); exit: @@ -642,6 +644,7 @@ Message *MeshForwarder::PrepareNextDirectTransmission(void) mTxQueueStats.UpdateFor(*curMessage); #endif LogMessage(kMessageDrop, *curMessage, error); + FinalizeMessageDirectTx(*curMessage, error); mSendQueue.DequeueAndFree(*curMessage); continue; } @@ -1261,9 +1264,6 @@ void MeshForwarder::UpdateSendMessage(Error aFrameTxError, Mac::Address &aMacDes txError = aFrameTxError; - mSendMessage->ClearDirectTransmission(); - mSendMessage->SetOffset(0); - if (aNeighbor != nullptr) { aNeighbor->GetLinkInfo().AddMessageTxStatus(mSendMessage->GetTxSuccess()); @@ -1289,39 +1289,54 @@ void MeshForwarder::UpdateSendMessage(Error aFrameTxError, Mac::Address &aMacDes #endif LogMessage(kMessageTransmit, *mSendMessage, txError, &aMacDest); + FinalizeMessageDirectTx(*mSendMessage, txError); + RemoveMessageIfNoPendingTx(*mSendMessage); + +exit: + mScheduleTransmissionTask.Post(); +} - if (mSendMessage->GetType() == Message::kTypeIp6) +void MeshForwarder::FinalizeMessageDirectTx(Message &aMessage, Error aError) +{ + // Finalizes the direct transmission of `aMessage`. This can be + // triggered by successful delivery (all fragments reaching the + // destination), failure of any fragment, queue management + // dropping the message, or eviction of message to accommodate + // higher priority messages. + + VerifyOrExit(aMessage.IsDirectTransmission()); + + aMessage.ClearDirectTransmission(); + aMessage.SetOffset(0); + + if (aError != kErrorNone) { - if (mSendMessage->GetTxSuccess()) - { - mIpCounters.mTxSuccess++; - } - else - { - mIpCounters.mTxFailure++; - } + aMessage.SetTxSuccess(false); + } + + if (aMessage.GetType() == Message::kTypeIp6) + { + aMessage.GetTxSuccess() ? mIpCounters.mTxSuccess++ : mIpCounters.mTxFailure++; } - switch (mSendMessage->GetSubType()) + switch (aMessage.GetSubType()) { case Message::kSubTypeMleDiscoverRequest: // Note that `HandleDiscoveryRequestFrameTxDone()` may update - // `mSendMessage` and mark it again for direct transmission. - Get().HandleDiscoveryRequestFrameTxDone(*mSendMessage); + // `aMessage` and mark it again for direct transmission. + Get().HandleDiscoveryRequestFrameTxDone(aMessage, aError); break; case Message::kSubTypeMleChildIdRequest: - Get().HandleChildIdRequestTxDone(*mSendMessage); + Get().HandleChildIdRequestTxDone(aMessage); break; default: break; } - RemoveMessageIfNoPendingTx(*mSendMessage); - exit: - mScheduleTransmissionTask.Post(); + return; } bool MeshForwarder::RemoveMessageIfNoPendingTx(Message &aMessage) diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index c27029d32..a640004f9 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -552,7 +552,7 @@ class MeshForwarder : public InstanceLocator, private NonCopyable Message::Priority aPriority); Error HandleDatagram(Message &aMessage, const ThreadLinkInfo &aLinkInfo, const Mac::Address &aMacSource); void ClearReassemblyList(void); - void RemoveMessage(Message &aMessage); + void EvictMessage(Message &aMessage); void HandleDiscoverComplete(void); void HandleReceivedFrame(Mac::RxFrame &aFrame); @@ -564,6 +564,7 @@ class MeshForwarder : public InstanceLocator, private NonCopyable void UpdateNeighborLinkFailures(Neighbor &aNeighbor, Error aError, bool aAllowNeighborRemove, uint8_t aFailLimit); void HandleSentFrame(Mac::TxFrame &aFrame, Error aError); void UpdateSendMessage(Error aFrameTxError, Mac::Address &aMacDest, Neighbor *aNeighbor); + void FinalizeMessageDirectTx(Message &aMessage, Error aError); bool RemoveMessageIfNoPendingTx(Message &aMessage); void HandleTimeTick(void); diff --git a/src/core/thread/mesh_forwarder_ftd.cpp b/src/core/thread/mesh_forwarder_ftd.cpp index 4001bbeb5..e91ceb19d 100644 --- a/src/core/thread/mesh_forwarder_ftd.cpp +++ b/src/core/thread/mesh_forwarder_ftd.cpp @@ -165,6 +165,7 @@ void MeshForwarder::HandleResolved(const Ip6::Address &aEid, Error aError) if (aError != kErrorNone) { LogMessage(kMessageDrop, message, kErrorAddressQuery); + FinalizeMessageDirectTx(message, kErrorAddressQuery); mSendQueue.DequeueAndFree(message); continue; } @@ -259,7 +260,7 @@ Error MeshForwarder::EvictMessage(Message::Priority aPriority) exit: if ((error == kErrorNone) && (evict != nullptr)) { - RemoveMessage(*evict); + EvictMessage(*evict); } return error; @@ -342,6 +343,7 @@ void MeshForwarder::RemoveDataResponseMessages(void) } LogMessage(kMessageDrop, message); + FinalizeMessageDirectTx(message, kErrorDrop); mSendQueue.DequeueAndFree(message); } } diff --git a/src/core/thread/mesh_forwarder_mtd.cpp b/src/core/thread/mesh_forwarder_mtd.cpp index b88c773cd..2bdca2b04 100644 --- a/src/core/thread/mesh_forwarder_mtd.cpp +++ b/src/core/thread/mesh_forwarder_mtd.cpp @@ -68,7 +68,7 @@ Error MeshForwarder::EvictMessage(Message::Priority aPriority) if (message->GetPriority() < static_cast(aPriority)) { - RemoveMessage(*message); + EvictMessage(*message); ExitNow(error = kErrorNone); } diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index cad9cacd3..8910c35d5 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -92,6 +92,9 @@ Mle::Mle(Instance &aInstance) , mDataRequestAttempts(0) , mAnnounceChannel(0) , mAlternateChannel(0) +#if OPENTHREAD_FTD + , mLinkRequestAttempts(0) +#endif , mRloc16(Mac::kShortAddrInvalid) , mPreviousParentRloc(Mac::kShortAddrInvalid) , mAttachCounter(0) diff --git a/src/core/thread/mle_tlvs.cpp b/src/core/thread/mle_tlvs.cpp index f3081e18f..f2098f175 100644 --- a/src/core/thread/mle_tlvs.cpp +++ b/src/core/thread/mle_tlvs.cpp @@ -125,8 +125,7 @@ bool ChannelTlvValue::IsValid(void) const bool isValid = false; uint16_t channel; - VerifyOrExit(mChannelPage < BitSizeOf(uint32_t)); - VerifyOrExit((1U << mChannelPage) & Radio::kSupportedChannelPages); + VerifyOrExit(Radio::SupportsChannelPage(mChannelPage)); channel = GetChannel(); VerifyOrExit((Radio::kChannelMin <= channel) && (channel <= Radio::kChannelMax)); diff --git a/src/core/thread/network_diagnostic.cpp b/src/core/thread/network_diagnostic.cpp index 634574bc2..c331dc428 100644 --- a/src/core/thread/network_diagnostic.cpp +++ b/src/core/thread/network_diagnostic.cpp @@ -299,6 +299,15 @@ Error Server::AppendDiagTlv(uint8_t aTlvType, Message &aMessage) error = AppendMacCounters(aMessage); break; + case Tlv::kMleCounters: + { + MleCountersTlv tlv; + + tlv.Init(Get().GetCounters()); + error = tlv.AppendTo(aMessage); + break; + } + case Tlv::kVendorName: error = Tlv::Append(aMessage, GetVendorName()); break; @@ -322,12 +331,9 @@ Error Server::AppendDiagTlv(uint8_t aTlvType, Message &aMessage) tlv.Init(); - for (uint8_t page = 0; page < static_cast(BitSizeOf(Radio::kSupportedChannelPages)); page++) + for (uint8_t page : Radio::kSupportedChannelPages) { - if (Radio::kSupportedChannelPages & (1 << page)) - { - tlv.GetChannelPages()[length++] = page; - } + tlv.GetChannelPages()[length++] = page; } tlv.SetLength(length); diff --git a/src/core/thread/panid_query_server.cpp b/src/core/thread/panid_query_server.cpp index 19c40c40c..cfa139961 100644 --- a/src/core/thread/panid_query_server.cpp +++ b/src/core/thread/panid_query_server.cpp @@ -64,7 +64,7 @@ void PanIdQueryServer::HandleTmf(Coap::Message &aMessage, const uint32_t mask; VerifyOrExit(aMessage.IsPostRequest()); - VerifyOrExit((mask = MeshCoP::ChannelMaskTlv::GetChannelMask(aMessage)) != 0); + SuccessOrExit(MeshCoP::ChannelMaskTlv::FindIn(aMessage, mask)); SuccessOrExit(Tlv::Find(aMessage, panId)); @@ -105,17 +105,14 @@ void PanIdQueryServer::HandleScanResult(Mac::ActiveScanResult *aScanResult) void PanIdQueryServer::SendConflict(void) { - Error error = kErrorNone; - MeshCoP::ChannelMaskTlv channelMask; - Tmf::MessageInfo messageInfo(GetInstance()); - Coap::Message *message; + Error error = kErrorNone; + Tmf::MessageInfo messageInfo(GetInstance()); + Coap::Message *message; message = Get().NewPriorityConfirmablePostMessage(kUriPanIdConflict); VerifyOrExit(message != nullptr, error = kErrorNoBufs); - channelMask.Init(); - channelMask.SetChannelMask(mChannelMask); - SuccessOrExit(error = channelMask.AppendTo(*message)); + SuccessOrExit(error = MeshCoP::ChannelMaskTlv::AppendTo(*message, mChannelMask)); SuccessOrExit(error = Tlv::Append(*message, mPanId)); diff --git a/src/lib/spinel/CMakeLists.txt b/src/lib/spinel/CMakeLists.txt index 8d552cf08..b8be41c82 100644 --- a/src/lib/spinel/CMakeLists.txt +++ b/src/lib/spinel/CMakeLists.txt @@ -30,11 +30,23 @@ add_library(openthread-radio-spinel) add_library(openthread-spinel-ncp) add_library(openthread-spinel-rcp) +target_compile_definitions(openthread-radio-spinel PRIVATE + OPENTHREAD_FTD=0 + OPENTHREAD_MTD=0 + OPENTHREAD_RADIO=0 +) + target_compile_definitions(openthread-spinel-ncp PRIVATE + OPENTHREAD_FTD=0 + OPENTHREAD_MTD=0 + OPENTHREAD_RADIO=0 PUBLIC OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE=1 ) target_compile_definitions(openthread-spinel-rcp PRIVATE + OPENTHREAD_FTD=0 + OPENTHREAD_MTD=0 + OPENTHREAD_RADIO=0 PUBLIC OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE=0 ) @@ -65,8 +77,8 @@ set(COMMON_SOURCES set(OT_SPINEL_VENDOR_HOOK_SOURCE "" CACHE STRING "set vendor hook source file for Spinel") set(OT_SPINEL_VENDOR_HOOK_HEADER "" CACHE STRING "set vendor hook header file for Spinel") if(OT_SPINEL_VENDOR_HOOK_SOURCE) - target_compile_definitions(openthread-spinel-rcp PUBLIC "OPENTHREAD_SPINEL_CONFIG_ENABLE_VENDOR_HOOK=1") - target_compile_definitions(openthread-spinel-ncp PUBLIC "OPENTHREAD_SPINEL_CONFIG_ENABLE_VENDOR_HOOK=1") + target_compile_definitions(openthread-spinel-rcp PUBLIC "OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE=1") + target_compile_definitions(openthread-spinel-ncp PUBLIC "OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE=1") target_compile_definitions(openthread-spinel-rcp PUBLIC "OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_HEADER=\"${OT_SPINEL_VENDOR_HOOK_HEADER}\"") target_compile_definitions(openthread-spinel-ncp PUBLIC "OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_HEADER=\"${OT_SPINEL_VENDOR_HOOK_HEADER}\"") list(APPEND COMMON_SOURCES ${OT_SPINEL_VENDOR_HOOK_SOURCE_DIR}${OT_SPINEL_VENDOR_HOOK_SOURCE}) diff --git a/src/lib/spinel/example_vendor_hook.cpp b/src/lib/spinel/example_vendor_hook.cpp index 3c0a73a15..c43961b79 100644 --- a/src/lib/spinel/example_vendor_hook.cpp +++ b/src/lib/spinel/example_vendor_hook.cpp @@ -30,7 +30,7 @@ * This file shows how to implement the Radio Spinel vendor hook. */ -#if OPENTHREAD_SPINEL_CONFIG_ENABLE_VENDOR_HOOK +#if OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE #include OPENTRHEAD_SPINEL_CONFIG_VENDOR_HOOK_HEADER #include "common/log.hpp" @@ -64,4 +64,4 @@ otError RadioSpinel::VendorHandleValueIs(spinel_prop_key_t aPropKey) extern ot::Spinel::RadioSpinel &GetRadioSpinel(void); -#endif // OPENTHREAD_SPINEL_CONFIG_ENABLE_VENDOR_HOOK +#endif // OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE diff --git a/src/lib/spinel/example_vendor_hook.hpp b/src/lib/spinel/example_vendor_hook.hpp index f9dedb626..df35e8bc3 100644 --- a/src/lib/spinel/example_vendor_hook.hpp +++ b/src/lib/spinel/example_vendor_hook.hpp @@ -33,7 +33,7 @@ #ifndef SPINEL_EXTENSION_H #define SPINEL_EXTENSION_H -#if OPENTHREAD_SPINEL_CONFIG_ENABLE_VENDOR_HOOK +#if OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE #include #include "lib/spinel/radio_spinel.hpp" @@ -55,5 +55,5 @@ class VendorRadioSpinel : public ot::Spinel::RadioSpinel } // namespace Spinel } // namespace ot -#endif // OPENTHREAD_SPINEL_CONFIG_ENABLE_VENDOR_HOOK +#endif // OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE #endif // SPINEL_EXTENSION_H diff --git a/src/lib/spinel/openthread-spinel-config.h b/src/lib/spinel/openthread-spinel-config.h index 231a86838..75dd496ce 100644 --- a/src/lib/spinel/openthread-spinel-config.h +++ b/src/lib/spinel/openthread-spinel-config.h @@ -90,13 +90,13 @@ #endif /** - * @def OPENTHREAD_SPINEL_CONFIG_ENABLE_VENDOR_HOOK + * @def OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE * * Enables compilation of vendor specific code for Spinel * */ -#ifndef OPENTHREAD_SPINEL_CONFIG_ENABLE_VENDOR_HOOK -#define OPENTHREAD_SPINEL_CONFIG_ENABLE_VENDOR_HOOK 0 +#ifndef OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE +#define OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE 0 #endif /** @@ -109,4 +109,14 @@ #define OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_HEADER "lib/spinel/example_vendor_hook.hpp" #endif +/** + * @def OPENTHREAD_SPINEL_CONFIG_RCP_TX_WAIT_TIME_SECS + * + * Defines the Tx wait duration in seconds. + * + */ +#ifndef OPENTHREAD_SPINEL_CONFIG_RCP_TX_WAIT_TIME_SECS +#define OPENTHREAD_SPINEL_CONFIG_RCP_TX_WAIT_TIME_SECS 5 +#endif + #endif // OPENTHREAD_SPINEL_CONFIG_H_ diff --git a/src/lib/spinel/radio_spinel.cpp b/src/lib/spinel/radio_spinel.cpp index 7da561ae2..495a9bb1c 100644 --- a/src/lib/spinel/radio_spinel.cpp +++ b/src/lib/spinel/radio_spinel.cpp @@ -747,7 +747,7 @@ void RadioSpinel::HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, break; } } -#if OPENTHREAD_SPINEL_CONFIG_ENABLE_VENDOR_HOOK +#if OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE else if (aKey >= SPINEL_PROP_VENDOR__BEGIN && aKey < SPINEL_PROP_VENDOR__END) { error = VendorHandleValueIs(aKey); diff --git a/src/lib/spinel/radio_spinel.hpp b/src/lib/spinel/radio_spinel.hpp index bc0774d32..594ce9126 100644 --- a/src/lib/spinel/radio_spinel.hpp +++ b/src/lib/spinel/radio_spinel.hpp @@ -1065,7 +1065,7 @@ class RadioSpinel */ void RestoreProperties(void); #endif -#if OPENTHREAD_SPINEL_CONFIG_ENABLE_VENDOR_HOOK +#if OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE /** * Defines a vendor "set property handler" hook to process vendor spinel properties. * @@ -1105,9 +1105,12 @@ class RadioSpinel kStateTransmitDone, ///< Radio indicated frame transmission is done. }; - static constexpr uint32_t kUsPerMs = 1000; ///< Microseconds per millisecond. + static constexpr uint32_t kUsPerMs = 1000; ///< Microseconds per millisecond. + static constexpr uint32_t kMsPerSec = 1000; ///< Milliseconds per second. + static constexpr uint32_t kUsPerSec = kUsPerMs * kMsPerSec; ///< Microseconds per second. static constexpr uint64_t kTxWaitUs = - 5000000; ///< Maximum time of waiting for `TransmitDone` event, in microseconds. + OPENTHREAD_SPINEL_CONFIG_RCP_TX_WAIT_TIME_SECS * + kUsPerSec; ///< Maximum time of waiting for `TransmitDone` event, in microseconds. typedef otError (RadioSpinel::*ResponseHandler)(const uint8_t *aBuffer, uint16_t aLength); diff --git a/src/lib/spinel/spinel.c b/src/lib/spinel/spinel.c index 82ea55556..c85d2444c 100644 --- a/src/lib/spinel/spinel.c +++ b/src/lib/spinel/spinel.c @@ -1500,11 +1500,9 @@ const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key) const char *spinel_net_role_to_cstr(uint8_t net_role) { static const struct spinel_cstr spinel_net_cstr[] = { - {SPINEL_NET_ROLE_DETACHED, "NET_ROLE_DETACHED"}, - {SPINEL_NET_ROLE_CHILD, "NET_ROLE_CHILD"}, - {SPINEL_NET_ROLE_ROUTER, "NET_ROLE_ROUTER"}, - {SPINEL_NET_ROLE_LEADER, "NET_ROLE_LEADER"}, - {0, NULL}, + {SPINEL_NET_ROLE_DETACHED, "NET_ROLE_DETACHED"}, {SPINEL_NET_ROLE_CHILD, "NET_ROLE_CHILD"}, + {SPINEL_NET_ROLE_ROUTER, "NET_ROLE_ROUTER"}, {SPINEL_NET_ROLE_LEADER, "NET_ROLE_LEADER"}, + {SPINEL_NET_ROLE_DISABLED, "NET_ROLE_DISABLED"}, {0, NULL}, }; return spinel_to_cstr(spinel_net_cstr, net_role); diff --git a/src/lib/spinel/spinel.h b/src/lib/spinel/spinel.h index 5d8094db4..d91a039ac 100644 --- a/src/lib/spinel/spinel.h +++ b/src/lib/spinel/spinel.h @@ -598,6 +598,7 @@ typedef enum SPINEL_NET_ROLE_CHILD = 1, SPINEL_NET_ROLE_ROUTER = 2, SPINEL_NET_ROLE_LEADER = 3, + SPINEL_NET_ROLE_DISABLED = 4, } spinel_net_role_t; typedef enum @@ -2296,6 +2297,7 @@ enum * SPINEL_NET_ROLE_CHILD = 1, * SPINEL_NET_ROLE_ROUTER = 2, * SPINEL_NET_ROLE_LEADER = 3, + * SPINEL_NET_ROLE_DISABLED = 4, * */ SPINEL_PROP_NET_ROLE = SPINEL_PROP_NET__BEGIN + 3, diff --git a/src/ncp/ftd.cmake b/src/ncp/ftd.cmake index 43b5f4f80..fbf230a4f 100644 --- a/src/ncp/ftd.cmake +++ b/src/ncp/ftd.cmake @@ -30,6 +30,8 @@ add_library(openthread-ncp-ftd) target_compile_definitions(openthread-ncp-ftd PRIVATE OPENTHREAD_FTD=1 + OPENTHREAD_MTD=0 + OPENTHREAD_RADIO=0 OPENTHREAD_CONFIG_NCP_HDLC_ENABLE=1 ) diff --git a/src/ncp/mtd.cmake b/src/ncp/mtd.cmake index 6d8de8e14..5bcf3783e 100644 --- a/src/ncp/mtd.cmake +++ b/src/ncp/mtd.cmake @@ -29,7 +29,9 @@ add_library(openthread-ncp-mtd) target_compile_definitions(openthread-ncp-mtd PRIVATE + OPENTHREAD_FTD=0 OPENTHREAD_MTD=1 + OPENTHREAD_RADIO=0 OPENTHREAD_CONFIG_NCP_HDLC_ENABLE=1 ) diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp index f5b06dd55..fc233a657 100644 --- a/src/ncp/ncp_base_mtd.cpp +++ b/src/ncp/ncp_base_mtd.cpp @@ -536,6 +536,9 @@ template <> otError NcpBase::HandlePropertyGet(void) switch (otThreadGetDeviceRole(mInstance)) { case OT_DEVICE_ROLE_DISABLED: + role = SPINEL_NET_ROLE_DISABLED; + break; + case OT_DEVICE_ROLE_DETACHED: role = SPINEL_NET_ROLE_DETACHED; break; diff --git a/src/ncp/radio.cmake b/src/ncp/radio.cmake index 1350a28e8..23ec4e06e 100644 --- a/src/ncp/radio.cmake +++ b/src/ncp/radio.cmake @@ -29,6 +29,8 @@ add_library(openthread-rcp) target_compile_definitions(openthread-rcp PRIVATE + OPENTHREAD_FTD=0 + OPENTHREAD_MTD=0 OPENTHREAD_RADIO=1 OPENTHREAD_RADIO_CLI=0 ) diff --git a/src/posix/CMakeLists.txt b/src/posix/CMakeLists.txt index 25634511d..d8081d616 100644 --- a/src/posix/CMakeLists.txt +++ b/src/posix/CMakeLists.txt @@ -34,6 +34,8 @@ set(COMMON_INCLUDES ${PROJECT_SOURCE_DIR}/src/posix/platform/include ) +ot_option(OT_PLATFORM_POSIX_CONFIG_FILE OPENTHREAD_POSIX_CONFIG_CONFIGURATION_FILE_ENABLE "posix config file") + set(OT_READLINE_VALUES "readline" "edit" @@ -83,6 +85,19 @@ elseif(OT_APP_CLI) endif() endif() +set(OT_POSIX_FACTORY_CONFIG "" CACHE STRING "OpenThread factory config file") +set(OT_POSIX_PRODUCT_CONFIG "" CACHE STRING "OpenThread product config file") + +if (OT_POSIX_FACTORY_CONFIG) + target_compile_definitions(ot-config INTERFACE "OPENTHREAD_POSIX_CONFIG_FACTORY_CONFIG_FILE=\"${OT_POSIX_FACTORY_CONFIG}\"") + message(STATUS "OT_POSIX_FACTORY_CONFIG=\"${OT_POSIX_FACTORY_CONFIG}\"") +endif() + +if (OT_POSIX_PRODUCT_CONFIG) + target_compile_definitions(ot-config INTERFACE "OPENTHREAD_POSIX_CONFIG_PRODUCT_CONFIG_FILE=\"${OT_POSIX_PRODUCT_CONFIG}\"") + message(STATUS "OT_POSIX_PRODUCT_CONFIG=\"${OT_POSIX_PRODUCT_CONFIG}\"") +endif() + if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) set(CPACK_GENERATOR "DEB") set(CPACK_DEBIAN_PACKAGE_MAINTAINER "OpenThread Authors (https://github.com/openthread/openthread)") diff --git a/src/posix/platform/CMakeLists.txt b/src/posix/platform/CMakeLists.txt index e9fb7c83a..e4795834f 100644 --- a/src/posix/platform/CMakeLists.txt +++ b/src/posix/platform/CMakeLists.txt @@ -185,6 +185,7 @@ target_compile_definitions(openthread-posix PRIVATE OPENTHREAD_FTD=1 OPENTHREAD_MTD=0 + OPENTHREAD_RADIO=0 ) target_compile_options(openthread-posix PRIVATE diff --git a/src/posix/platform/daemon.cpp b/src/posix/platform/daemon.cpp index 5a85b15c2..bf905992c 100644 --- a/src/posix/platform/daemon.cpp +++ b/src/posix/platform/daemon.cpp @@ -104,7 +104,7 @@ int Daemon::OutputFormatV(const char *aFormat, va_list aArguments) VerifyOrExit(mSessionSocket != -1); -#if defined(__linux__) +#ifdef __linux__ // Don't die on SIGPIPE rval = send(mSessionSocket, buf, static_cast(rval), MSG_NOSIGNAL); #else diff --git a/src/posix/platform/multicast_routing.cpp b/src/posix/platform/multicast_routing.cpp index 40af863a6..a224ae1ab 100644 --- a/src/posix/platform/multicast_routing.cpp +++ b/src/posix/platform/multicast_routing.cpp @@ -39,7 +39,7 @@ #include #include #include -#if __linux__ +#ifdef __linux__ #include #else #error "Multicast Routing feature is not ported to non-Linux platforms yet." diff --git a/src/posix/platform/netif.cpp b/src/posix/platform/netif.cpp index 3d546eb3c..ac1da79cd 100644 --- a/src/posix/platform/netif.cpp +++ b/src/posix/platform/netif.cpp @@ -193,18 +193,18 @@ using namespace ot::Posix::Ip6Utils; #endif // OPENTHREAD_TUN_DEVICE -#if defined(__linux__) +#ifdef __linux__ static uint32_t sNetlinkSequence = 0; ///< Netlink message sequence. #endif -#if OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE && __linux__ +#if OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE && defined(__linux__) static constexpr uint32_t kOmrRoutesPriority = OPENTHREAD_POSIX_CONFIG_OMR_ROUTES_PRIORITY; static constexpr uint8_t kMaxOmrRoutesNum = OPENTHREAD_POSIX_CONFIG_MAX_OMR_ROUTES_NUM; static uint8_t sAddedOmrRoutesNum = 0; static otIp6Prefix sAddedOmrRoutes[kMaxOmrRoutesNum]; #endif -#if OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE && __linux__ +#if OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE && defined(__linux__) static constexpr uint32_t kExternalRoutePriority = OPENTHREAD_POSIX_CONFIG_EXTERNAL_ROUTE_PRIORITY; static constexpr uint8_t kMaxExternalRoutesNum = OPENTHREAD_POSIX_CONFIG_MAX_EXTERNAL_ROUTE_NUM; static uint8_t sAddedExternalRoutesNum = 0; @@ -319,7 +319,7 @@ static uint8_t NetmaskToPrefixLength(const struct sockaddr_in6 *netmask) } #endif -#if defined(__linux__) +#ifdef __linux__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-align" @@ -375,7 +375,7 @@ static void UpdateUnicastLinux(otInstance *aInstance, const otIp6AddressInfo &aA memset(&req, 0, sizeof(req)); req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); - req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL; + req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | (aIsAdded ? (NLM_F_CREATE | NLM_F_EXCL) : 0); req.nh.nlmsg_type = aIsAdded ? RTM_NEWADDR : RTM_DELADDR; req.nh.nlmsg_pid = 0; req.nh.nlmsg_seq = ++sNetlinkSequence; @@ -432,7 +432,7 @@ static void UpdateUnicastLinux(otInstance *aInstance, const otIp6AddressInfo &aA } #pragma GCC diagnostic pop -#endif // defined(__linux__) +#endif // __linux__ static void UpdateUnicast(otInstance *aInstance, const otIp6AddressInfo &aAddressInfo, bool aIsAdded) { @@ -441,7 +441,7 @@ static void UpdateUnicast(otInstance *aInstance, const otIp6AddressInfo &aAddres assert(gInstance == aInstance); assert(sIpFd >= 0); -#if defined(__linux__) +#ifdef __linux__ UpdateUnicastLinux(aInstance, aAddressInfo, aIsAdded); #elif defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__) { @@ -569,7 +569,7 @@ static void UpdateLink(otInstance *aInstance) SetLinkState(aInstance, otIp6IsEnabled(aInstance)); } -#if defined(__linux__) +#ifdef __linux__ template otError AddRoute(const uint8_t (&aAddress)[N], uint8_t aPrefixLen, uint32_t aPriority) { constexpr unsigned int kBufSize = 128; @@ -867,7 +867,7 @@ static otError DeleteIp4Route(const otIp4Cidr &aIp4Cidr) return DeleteRoute(aIp4Cidr.mAddress.mFields.m8, aIp4Cidr.mLength); } #endif -#endif // defined(__linux__) +#endif // __linux__ static void processAddressChange(const otIp6AddressInfo *aAddressInfo, bool aIsAdded, void *aContext) { @@ -952,10 +952,10 @@ void platformNetifStateChange(otInstance *aInstance, otChangedFlags aFlags) } if (OT_CHANGED_THREAD_NETDATA & aFlags) { -#if OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE && __linux__ +#if OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE && defined(__linux__) UpdateOmrRoutes(aInstance); #endif -#if OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE && __linux__ +#if OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE && defined(__linux__) UpdateExternalRoutes(aInstance); #endif #if OPENTHREAD_POSIX_CONFIG_FIREWALL_ENABLE @@ -1080,6 +1080,46 @@ static otError tryProcessIcmp6RaMessage(otInstance *aInstance, const uint8_t *da } #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE +#ifdef __linux__ +/** + * Returns whether the address is a required anycast address (RFC2373, 2.6.1). + * + */ +static bool isRequiredAnycast(const uint8_t *aAddress, uint8_t aPrefixLength) +{ + bool isRequiredAnycast = false; + uint8_t firstBytePos = aPrefixLength / 8; + uint8_t remainingBits = aPrefixLength % 8; + + if (aPrefixLength == OT_IP6_ADDRESS_BITSIZE) + { + ExitNow(); + } + + if (remainingBits != 0) + { + if ((aAddress[firstBytePos] & ((1 << remainingBits) - 1)) != 0) + { + ExitNow(); + } + firstBytePos++; + } + + for (int i = firstBytePos; i < OT_IP6_ADDRESS_SIZE; ++i) + { + if (aAddress[i] != 0) + { + ExitNow(); + } + } + + isRequiredAnycast = true; + +exit: + return isRequiredAnycast; +} +#endif // __linux__ + static void processTransmit(otInstance *aInstance) { otMessage *message = nullptr; @@ -1182,7 +1222,7 @@ static void logAddrEvent(bool isAdd, const ot::Ip6::Address &aAddress, otError e } } -#if defined(__linux__) +#ifdef __linux__ static void processNetifAddrEvent(otInstance *aInstance, struct nlmsghdr *aNetlinkMessage) { @@ -1213,6 +1253,15 @@ static void processNetifAddrEvent(otInstance *aInstance, struct nlmsghdr *aNetli addr6.sin6_family = AF_INET6; memcpy(&addr6.sin6_addr, RTA_DATA(rta), sizeof(addr6.sin6_addr)); + // Linux allows adding an IPv6 required anycast address to an interface, + // which blocks openthread deriving an address by SLAAC and will cause routing issues. + // Ignore the required anycast addresses here to allow OpenThread stack generate one when necessary, + // and Linux will prefer the non-required anycast address on the interface. + if (isRequiredAnycast(addr.GetBytes(), ifaddr->ifa_prefixlen)) + { + continue; + } + if (aNetlinkMessage->nlmsg_type == RTM_NEWADDR) { if (!addr.IsMulticast()) @@ -1308,7 +1357,7 @@ static void processNetifLinkEvent(otInstance *aInstance, struct nlmsghdr *aNetli } #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE && OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE - if (isUp && sActiveNat64Cidr.mLength > 0) + if (isUp && otNat64GetTranslatorState(gInstance) == OT_NAT64_STATE_ACTIVE) { // Recover NAT64 route. if ((error = AddIp4Route(sActiveNat64Cidr, kNat64RoutePriority)) != OT_ERROR_NONE) @@ -1324,7 +1373,7 @@ static void processNetifLinkEvent(otInstance *aInstance, struct nlmsghdr *aNetli otLogWarnPlat("[netif] Failed to sync netif state with host: %s", otThreadErrorToString(error)); } } -#endif // defined(__linux__) +#endif // __linux__ #if defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__) @@ -1558,7 +1607,7 @@ static void processNetifInfoEvent(otInstance *aInstance, struct rt_msghdr *rtm) #endif -#if defined(__linux__) +#ifdef __linux__ #define ERR_RTA(errmsg, requestPayloadLength) \ ((struct rtattr *)((char *)(errmsg)) + NLMSG_ALIGN(sizeof(struct nlmsgerr)) + NLMSG_ALIGN(requestPayloadLength)) @@ -1632,7 +1681,7 @@ static void HandleNetlinkResponse(struct nlmsghdr *msg) return; } -#endif // defined(__linux__) +#endif // __linux__ static void processNetlinkEvent(otInstance *aInstance) { @@ -1641,7 +1690,7 @@ static void processNetlinkEvent(otInstance *aInstance) union { -#if defined(__linux__) +#ifdef __linux__ nlmsghdr nlMsg; #else rt_msghdr rtMsg; @@ -1651,7 +1700,7 @@ static void processNetlinkEvent(otInstance *aInstance) length = recv(sNetlinkFd, msgBuffer.buffer, sizeof(msgBuffer.buffer), 0); -#if defined(__linux__) +#ifdef __linux__ #define HEADER_SIZE sizeof(nlmsghdr) #else #define HEADER_SIZE sizeof(rt_msghdr) @@ -1664,7 +1713,7 @@ static void processNetlinkEvent(otInstance *aInstance) ExitNow(); } -#if defined(__linux__) +#ifdef __linux__ for (struct nlmsghdr *msg = &msgBuffer.nlMsg; NLMSG_OK(msg, static_cast(length)); msg = NLMSG_NEXT(msg, length)) { @@ -1680,7 +1729,7 @@ static void processNetlinkEvent(otInstance *aInstance) #endif switch (msg->nlmsg_type) { -#if defined(__linux__) +#ifdef __linux__ case NLMSG_DONE: // NLMSG_DONE indicates the end of the netlink message, exits now ExitNow(); @@ -1705,7 +1754,7 @@ static void processNetlinkEvent(otInstance *aInstance) break; #endif -#if !defined(__linux__) +#ifndef __linux__ case RTM_IFINFO: processNetifInfoEvent(aInstance, msg); break; @@ -1742,7 +1791,7 @@ static void mldListenerInit(void) memcpy(&mreq6.ipv6mr_multiaddr, kMLDv2MulticastAddress.mFields.m8, sizeof(kMLDv2MulticastAddress.mFields.m8)); VerifyOrDie(setsockopt(sMLDMonitorFd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6)) == 0, OT_EXIT_FAILURE); -#if defined(__linux__) +#ifdef __linux__ VerifyOrDie(setsockopt(sMLDMonitorFd, SOL_SOCKET, SO_BINDTODEVICE, gNetifName, static_cast(strnlen(gNetifName, IFNAMSIZ))) == 0, OT_EXIT_FAILURE); @@ -1827,7 +1876,7 @@ static void processMLDEvent(otInstance *aInstance) } #endif -#if defined(__linux__) +#ifdef __linux__ static void SetAddrGenModeToNone(void) { struct @@ -2004,7 +2053,7 @@ static void platformConfigureTunDevice(otPlatformConfig *aPlatformConfig) static void platformConfigureNetLink(void) { -#if defined(__linux__) +#ifdef __linux__ sNetlinkFd = SocketWithCloseExec(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE, kSocketNonBlock); #elif defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__) sNetlinkFd = SocketWithCloseExec(PF_ROUTE, SOCK_RAW, 0, kSocketNonBlock); @@ -2032,7 +2081,7 @@ static void platformConfigureNetLink(void) } #endif -#if defined(__linux__) +#ifdef __linux__ { struct sockaddr_nl sa; @@ -2084,7 +2133,7 @@ void platformNetifInit(otPlatformConfig *aPlatformConfig) mldListenerInit(); #endif -#if __linux__ +#ifdef __linux__ SetAddrGenModeToNone(); #endif } diff --git a/src/posix/platform/openthread-core-posix-config.h b/src/posix/platform/openthread-core-posix-config.h index 2b3297a0a..ebe784f45 100644 --- a/src/posix/platform/openthread-core-posix-config.h +++ b/src/posix/platform/openthread-core-posix-config.h @@ -34,6 +34,8 @@ #ifndef OPENTHREAD_CORE_POSIX_CONFIG_H_ #define OPENTHREAD_CORE_POSIX_CONFIG_H_ +#include "openthread-posix-daemon-config.h" + #ifndef OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS #define OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS 256 #endif diff --git a/src/posix/platform/openthread-posix-config.h b/src/posix/platform/openthread-posix-config.h index cc8afe5cb..f39c6f2ac 100644 --- a/src/posix/platform/openthread-posix-config.h +++ b/src/posix/platform/openthread-posix-config.h @@ -51,40 +51,6 @@ #define OPENTHREAD_POSIX_CONFIG_RCP_PTY_ENABLE 1 #endif -/** - * @def OPENTHREAD_POSIX_CONFIG_DAEMON_SOCKET_BASENAME - * - * Define socket basename used by POSIX app daemon. - * - */ -#ifndef OPENTHREAD_POSIX_CONFIG_DAEMON_SOCKET_BASENAME -#ifdef __linux__ -#define OPENTHREAD_POSIX_CONFIG_DAEMON_SOCKET_BASENAME "/run/openthread-%s" -#else -#define OPENTHREAD_POSIX_CONFIG_DAEMON_SOCKET_BASENAME "/tmp/openthread-%s" -#endif -#endif - -/** - * @def OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE - * - * Define to 1 to enable POSIX daemon. - * - */ -#ifndef OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE -#define OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE 0 -#endif - -/** - * @def OPENTHREAD_POSIX_CONFIG_DAEMON_CLI_ENABLE - * - * Define to 1 to enable CLI for the posix daemon. - * - */ -#ifndef OPENTHREAD_POSIX_CONFIG_DAEMON_CLI_ENABLE -#define OPENTHREAD_POSIX_CONFIG_DAEMON_CLI_ENABLE 1 -#endif - /** * @def OPENTHREAD_POSIX_CONFIG_RCP_BUS * @@ -453,4 +419,14 @@ #define OPENTHREAD_POSIX_CONFIG_EXIT_ON_INFRA_NETIF_LOST_ENABLE 1 #endif +/** + * @def OPENTHREAD_POSIX_CONFIG_TREL_TX_PACKET_POOL_SIZE + * + * This setting configures the capacity of TREL packet pool for transmission. + * + */ +#ifndef OPENTHREAD_POSIX_CONFIG_TREL_TX_PACKET_POOL_SIZE +#define OPENTHREAD_POSIX_CONFIG_TREL_TX_PACKET_POOL_SIZE 5 +#endif + #endif // OPENTHREAD_PLATFORM_CONFIG_H_ diff --git a/src/posix/platform/openthread-posix-daemon-config.h b/src/posix/platform/openthread-posix-daemon-config.h new file mode 100644 index 000000000..d7e8b6c33 --- /dev/null +++ b/src/posix/platform/openthread-posix-daemon-config.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2023, 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. + */ + +#ifndef OPENTHREAD_POSIX_DAEMON_CONFIG_H_ +#define OPENTHREAD_POSIX_DAEMON_CONFIG_H_ + +/** + * @file + * @brief + * This file includes the POSIX daemon specific configurations. + */ + +/** + * @def OPENTHREAD_POSIX_CONFIG_DAEMON_SOCKET_BASENAME + * + * Define socket basename used by POSIX app daemon. + * + */ +#ifndef OPENTHREAD_POSIX_CONFIG_DAEMON_SOCKET_BASENAME +#ifdef __linux__ +#define OPENTHREAD_POSIX_CONFIG_DAEMON_SOCKET_BASENAME "/run/openthread-%s" +#else +#define OPENTHREAD_POSIX_CONFIG_DAEMON_SOCKET_BASENAME "/tmp/openthread-%s" +#endif +#endif + +/** + * @def OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE + * + * Define to 1 to enable POSIX daemon. + * + */ +#ifndef OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE +#define OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE 0 +#endif + +/** + * @def OPENTHREAD_POSIX_CONFIG_DAEMON_CLI_ENABLE + * + * Define to 1 to enable CLI for the posix daemon. + * + */ +#ifndef OPENTHREAD_POSIX_CONFIG_DAEMON_CLI_ENABLE +#define OPENTHREAD_POSIX_CONFIG_DAEMON_CLI_ENABLE 1 +#endif + +#endif // OPENTHREAD_POSIX_DAEMON_CONFIG_H_ diff --git a/src/posix/platform/radio.cpp b/src/posix/platform/radio.cpp index 44d011606..8828f9bee 100644 --- a/src/posix/platform/radio.cpp +++ b/src/posix/platform/radio.cpp @@ -71,7 +71,7 @@ void Radio::Init(const char *aUrl) spinel_iid_t iidList[Spinel::kSpinelHeaderMaxNumIid]; struct ot::Spinel::RadioSpinelCallbacks callbacks; - mRadioUrl = aUrl; + mRadioUrl.Init(aUrl); VerifyOrDie(mRadioUrl.GetPath() != nullptr, OT_EXIT_INVALID_ARGUMENTS); memset(&callbacks, 0, sizeof(callbacks)); diff --git a/src/posix/platform/radio.hpp b/src/posix/platform/radio.hpp index 00c958c2f..49cdfdf3d 100644 --- a/src/posix/platform/radio.hpp +++ b/src/posix/platform/radio.hpp @@ -35,7 +35,7 @@ #include "posix/platform/radio_url.hpp" #include "posix/platform/spi_interface.hpp" #include "posix/platform/vendor_interface.hpp" -#if OPENTHREAD_SPINEL_CONFIG_ENABLE_VENDOR_HOOK +#if OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE #ifdef OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_HEADER #include OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_HEADER #endif @@ -110,7 +110,7 @@ class Radio #endif RadioUrl mRadioUrl; -#if OPENTHREAD_ENABLE_SPINEL_VENDOR_HOOK +#if OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE Spinel::VendorRadioSpinel mRadioSpinel; #else Spinel::RadioSpinel mRadioSpinel; diff --git a/src/posix/platform/radio_url.cpp b/src/posix/platform/radio_url.cpp index bd34d9c65..db0c13461 100644 --- a/src/posix/platform/radio_url.cpp +++ b/src/posix/platform/radio_url.cpp @@ -135,7 +135,7 @@ const char *otSysGetRadioUrlHelpString(void) namespace ot { namespace Posix { -RadioUrl::RadioUrl(const char *aUrl) +void RadioUrl::Init(const char *aUrl) { if (aUrl != nullptr) { diff --git a/src/posix/platform/radio_url.hpp b/src/posix/platform/radio_url.hpp index 32b2c4c16..02460705b 100644 --- a/src/posix/platform/radio_url.hpp +++ b/src/posix/platform/radio_url.hpp @@ -52,7 +52,20 @@ class RadioUrl : public ot::Url::Url * @param[in] aUrl The null-terminated URL string. * */ - RadioUrl(const char *aUrl); + explicit RadioUrl(const char *aUrl) { Init(aUrl); }; + + /** + * Initializes the radio URL. + * + * @param[in] aUrl The null-terminated URL string. + * + */ + void Init(const char *aUrl); + + RadioUrl(const RadioUrl &) = delete; + RadioUrl(RadioUrl &&) = delete; + RadioUrl &operator=(const RadioUrl &) = delete; + RadioUrl &operator=(RadioUrl &&) = delete; private: enum diff --git a/src/posix/platform/trel.cpp b/src/posix/platform/trel.cpp index a925cb84c..ea06bca88 100644 --- a/src/posix/platform/trel.cpp +++ b/src/posix/platform/trel.cpp @@ -51,22 +51,22 @@ #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE -#define TREL_MAX_PACKET_SIZE 1400 -#define TREL_PACKET_POOL_SIZE 5 +static constexpr uint16_t kMaxPacketSize = 1400; // The max size of a TREL packet. typedef struct TxPacket { struct TxPacket *mNext; - uint8_t mBuffer[TREL_MAX_PACKET_SIZE]; + uint8_t mBuffer[kMaxPacketSize]; uint16_t mLength; otSockAddr mDestSockAddr; } TxPacket; -static uint8_t sRxPacketBuffer[TREL_MAX_PACKET_SIZE]; -static uint16_t sRxPacketLength; -static TxPacket sTxPacketPool[TREL_PACKET_POOL_SIZE]; -static TxPacket *sFreeTxPacketHead; // A singly linked list of free/available `TxPacket` from pool. -static TxPacket *sTxPacketQueueTail; // A circular linked list for queued tx packets. +static uint8_t sRxPacketBuffer[kMaxPacketSize]; +static uint16_t sRxPacketLength; +static TxPacket sTxPacketPool[OPENTHREAD_POSIX_CONFIG_TREL_TX_PACKET_POOL_SIZE]; +static TxPacket *sFreeTxPacketHead; // A singly linked list of free/available `TxPacket` from pool. +static TxPacket *sTxPacketQueueTail; // A circular linked list for queued tx packets. +static otPlatTrelCounters sCounters; static char sInterfaceName[IFNAMSIZ + 1]; static bool sInitialized = false; @@ -187,11 +187,19 @@ static otError SendPacket(const uint8_t *aBuffer, uint16_t aLength, const otSock error = OT_ERROR_INVALID_STATE; } } + else + { + ++sCounters.mTxPackets; + sCounters.mTxBytes += aLength; + } exit: otLogDebgPlat("[trel] SendPacket([%s]:%u) err:%s pkt:%s", Ip6AddrToString(&aDestSockAddr->mAddress), aDestSockAddr->mPort, otThreadErrorToString(error), BufferToString(aBuffer, aLength)); - + if (error != OT_ERROR_NONE) + { + ++sCounters.mTxFailure; + } return error; } @@ -219,6 +227,8 @@ static void ReceivePacket(int aSocket, otInstance *aInstance) if (sEnabled) { + ++sCounters.mRxPackets; + sCounters.mRxBytes += sRxPacketLength; otPlatTrelHandleReceived(aInstance, sRxPacketBuffer, sRxPacketLength); } } @@ -306,6 +316,8 @@ static void EnqueuePacket(const uint8_t *aBuffer, uint16_t aLength, const otSock return; } +static void ResetCounters() { memset(&sCounters, 0, sizeof(sCounters)); } + //--------------------------------------------------------------------------------------------------------------------- // trelDnssd // @@ -456,7 +468,7 @@ void otPlatTrelSend(otInstance *aInstance, VerifyOrExit(sEnabled); - assert(aUdpPayloadLen <= TREL_MAX_PACKET_SIZE); + assert(aUdpPayloadLen <= kMaxPacketSize); // We try to send the packet immediately. If it fails (e.g., // network is down) `SendPacket()` returns `OT_ERROR_ABORT`. If @@ -486,6 +498,21 @@ void otPlatTrelRegisterService(otInstance *aInstance, uint16_t aPort, const uint return; } +// We keep counters at the platform layer because TREL failures can only be captured accurately within +// the platform layer as the platform sometimes only queues the packet and the packet will be sent later +// and the error is only known after sent. +const otPlatTrelCounters *otPlatTrelGetCounters(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return &sCounters; +} + +void otPlatTrelResetCounters(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + ResetCounters(); +} + //--------------------------------------------------------------------------------------------------------------------- // platformTrel system @@ -507,6 +534,8 @@ void platformTrelInit(const char *aTrelUrl) InitPacketQueue(); sInitialized = true; + + ResetCounters(); } void platformTrelDeinit(void) diff --git a/src/posix/platform/udp.cpp b/src/posix/platform/udp.cpp index 6d7c880a3..4161672eb 100644 --- a/src/posix/platform/udp.cpp +++ b/src/posix/platform/udp.cpp @@ -323,7 +323,12 @@ otError otPlatUdpBindToNetif(otUdpSocket *aUdpSocket, otNetifIdentifier aNetifId case OT_NETIF_BACKBONE: { #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE -#if __linux__ + if (otSysGetInfraNetifName() == nullptr || otSysGetInfraNetifName()[0] == '\0') + { + otLogWarnPlat("No backbone interface given, %s fails.", __func__); + ExitNow(error = OT_ERROR_INVALID_ARGS); + } +#ifdef __linux__ VerifyOrExit(setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, otSysGetInfraNetifName(), strlen(otSysGetInfraNetifName())) == 0, error = OT_ERROR_FAILED); diff --git a/tests/fuzz/CMakeLists.txt b/tests/fuzz/CMakeLists.txt index 39ca67b23..c2d5da2b7 100644 --- a/tests/fuzz/CMakeLists.txt +++ b/tests/fuzz/CMakeLists.txt @@ -33,6 +33,8 @@ set(COMMON_INCLUDES set(COMMON_COMPILE_OPTIONS -DOPENTHREAD_FTD=1 + -DOPENTHREAD_MTD=0 + -DOPENTHREAD_RADIO=0 -DOPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE=1 ) diff --git a/tests/scripts/expect/cli-debug.exp b/tests/scripts/expect/cli-debug.exp new file mode 100644 index 000000000..6c5ced74a --- /dev/null +++ b/tests/scripts/expect/cli-debug.exp @@ -0,0 +1,35 @@ +#!/usr/bin/expect -f +# +# Copyright (c) 2023, 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. +# + +source "tests/scripts/expect/_common.exp" + +spawn_node 1 + +send "debug\n" +expect_line "Done" diff --git a/tests/scripts/thread-cert/border_router/test_plat_udp_accessiblity.py b/tests/scripts/thread-cert/border_router/test_plat_udp_accessiblity.py index 5ed84bc0b..ea491a97f 100755 --- a/tests/scripts/thread-cert/border_router/test_plat_udp_accessiblity.py +++ b/tests/scripts/thread-cert/border_router/test_plat_udp_accessiblity.py @@ -74,6 +74,7 @@ def test(self): router.start() self.simulator.go(config.ROUTER_STARTUP_DELAY) self.assertEqual('router', router.get_state()) + router.srp_client_stop() # Router1 can ping to/from the Host on infra link. self.assertTrue(router.ping(br.get_rloc())) diff --git a/tests/scripts/thread-cert/border_router/test_publish_meshcop_service.py b/tests/scripts/thread-cert/border_router/test_publish_meshcop_service.py index d0dafad0a..67567946e 100755 --- a/tests/scripts/thread-cert/border_router/test_publish_meshcop_service.py +++ b/tests/scripts/thread-cert/border_router/test_publish_meshcop_service.py @@ -105,6 +105,7 @@ def test(self): br1.set_active_dataset(updateExisting=True, network_name='ot-br1-1') br1.start() self.simulator.go(config.BORDER_ROUTER_STARTUP_DELAY) + self.simulator.go(5) # Needs to wait extra some time to update meshcop service on state changes. self.check_meshcop_service(br1, host) # verify that there are two meshcop services @@ -147,6 +148,7 @@ def test(self): } br1.set_active_dataset(**dataset) + self.simulator.go(10) self.assertEqual(len(host.browse_mdns_services('_meshcop._udp')), 2) self.check_meshcop_service(br1, host) diff --git a/tests/scripts/thread-cert/border_router/test_trel_connectivity.py b/tests/scripts/thread-cert/border_router/test_trel_connectivity.py index 33487d836..20ed03932 100755 --- a/tests/scripts/thread-cert/border_router/test_trel_connectivity.py +++ b/tests/scripts/thread-cert/border_router/test_trel_connectivity.py @@ -143,6 +143,23 @@ def test(self): self.assertTrue(med1.ping(router2_mleid)) self.assertTrue(sed1.ping(router2_mleid)) + counters = br1.get_trel_counters() + print('br1 trel counters', counters) + self.assertTrue(counters['Inbound']['packets'] > 0) + self.assertTrue(counters['Inbound']['bytes'] > 0) + self.assertTrue(counters['Outbound']['packets'] > 0) + self.assertTrue(counters['Outbound']['bytes'] > 0) + self.assertTrue(counters['Outbound']['failures'] >= 0) + + br1.reset_trel_counters() + counters = br1.get_trel_counters() + print('br1 trel counters after reset', counters) + self.assertTrue(counters['Inbound']['packets'] == 0) + self.assertTrue(counters['Inbound']['bytes'] == 0) + self.assertTrue(counters['Outbound']['packets'] == 0) + self.assertTrue(counters['Outbound']['bytes'] == 0) + self.assertTrue(counters['Outbound']['failures'] == 0) + def verify(self, pv: PacketVerifier): pkts: PacketFilter = pv.pkts BR1_RLOC16 = pv.vars['BR1_RLOC16'] diff --git a/tests/scripts/thread-cert/node.py b/tests/scripts/thread-cert/node.py index 607d53214..5359848e8 100755 --- a/tests/scripts/thread-cert/node.py +++ b/tests/scripts/thread-cert/node.py @@ -1262,7 +1262,7 @@ def srp_client_enable_auto_start_mode(self): self._expect_done() def srp_client_disable_auto_start_mode(self): - self.send_command(f'srp client autostart able') + self.send_command(f'srp client autostart disable') self._expect_done() def srp_client_get_server_address(self): @@ -1390,6 +1390,30 @@ def is_trel_enabled(self) -> Union[None, bool]: raise + def get_trel_counters(self): + cmd = 'trel counters' + self.send_command(cmd) + result = self._expect_command_output() + + counters = {} + for line in result: + m = re.match(r'(\w+)\:[^\d]+(\d+)[^\d]+(\d+)(?:[^\d]+(\d+))?', line) + if m: + groups = m.groups() + sub_counters = { + 'packets': int(groups[1]), + 'bytes': int(groups[2]), + } + if groups[3]: + sub_counters['failures'] = int(groups[3]) + counters[groups[0]] = sub_counters + return counters + + def reset_trel_counters(self): + cmd = 'trel counters reset' + self.send_command(cmd) + self._expect_done() + def _encode_txt_entry(self, entry): """Encodes the TXT entry to the DNS-SD TXT record format as a HEX string. diff --git a/tests/scripts/thread-cert/requirements.txt b/tests/scripts/thread-cert/requirements.txt index 99b97972c..8afe42ded 100644 --- a/tests/scripts/thread-cert/requirements.txt +++ b/tests/scripts/thread-cert/requirements.txt @@ -16,7 +16,7 @@ ptyprocess==0.7.0 # via pexpect py==1.11.0 # via pyshark -pycryptodome==3.17 +pycryptodome==3.19.1 # via -r requirements.in pyshark==0.4.6 # via -r requirements.in diff --git a/tests/scripts/thread-cert/test_dnssd.py b/tests/scripts/thread-cert/test_dnssd.py index 0110c1efb..38c4f85ef 100755 --- a/tests/scripts/thread-cert/test_dnssd.py +++ b/tests/scripts/thread-cert/test_dnssd.py @@ -237,10 +237,6 @@ def _config_srp_client_services(self, weight, addrs, subtypes=''): - client.netdata_show() - srp_server_port = client.get_srp_server_port() - - client.srp_client_start(server.get_mleid(), srp_server_port) client.srp_client_set_host_name(hostname) client.srp_client_set_host_address(*addrs) client.srp_client_add_service(instancename, SERVICE + subtypes, port, priority, weight) diff --git a/tests/scripts/thread-cert/test_srp_auto_host_address.py b/tests/scripts/thread-cert/test_srp_auto_host_address.py index f714e6c4a..88d0718aa 100755 --- a/tests/scripts/thread-cert/test_srp_auto_host_address.py +++ b/tests/scripts/thread-cert/test_srp_auto_host_address.py @@ -86,10 +86,8 @@ def test(self): self.simulator.go(5) #------------------------------------------------------------------- - # Enable auto start mode on SRP client + # Check auto start mode on SRP client - self.assertEqual(client.srp_client_get_state(), 'Disabled') - client.srp_client_enable_auto_start_mode() self.assertEqual(client.srp_client_get_auto_start_mode(), 'Enabled') self.simulator.go(2) diff --git a/tests/scripts/thread-cert/test_srp_auto_start_mode.py b/tests/scripts/thread-cert/test_srp_auto_start_mode.py index 8fbcdda2d..ee0cfabcd 100755 --- a/tests/scripts/thread-cert/test_srp_auto_start_mode.py +++ b/tests/scripts/thread-cert/test_srp_auto_start_mode.py @@ -107,10 +107,8 @@ def test(self): self.simulator.go(5) #------------------------------------------------------------------- - # Enable auto start mode on client and check that server1 is selected + # Check auto start mode on client and check that server1 is selected - self.assertEqual(client.srp_client_get_state(), 'Disabled') - client.srp_client_enable_auto_start_mode() self.assertEqual(client.srp_client_get_auto_start_mode(), 'Enabled') self.simulator.go(2) diff --git a/tests/scripts/thread-cert/test_srp_client_change_lease.py b/tests/scripts/thread-cert/test_srp_client_change_lease.py index 37b03d3df..e55df6448 100755 --- a/tests/scripts/thread-cert/test_srp_client_change_lease.py +++ b/tests/scripts/thread-cert/test_srp_client_change_lease.py @@ -89,7 +89,6 @@ def test(self): self.assertEqual(server.get_state(), 'leader') self.simulator.go(5) - client.srp_server_set_enabled(False) client.start() self.simulator.go(config.ROUTER_STARTUP_DELAY) self.assertEqual(client.get_state(), 'router') @@ -98,9 +97,10 @@ def test(self): # 1. Register a single service and verify that it works. # + self.assertEqual(client.srp_client_get_auto_start_mode(), 'Enabled') + client.srp_client_set_host_name('my-host') client.srp_client_set_host_address('2001::1') - client.srp_client_start(server.get_addrs()[0], client.get_srp_server_port()) client.srp_client_add_service('my-service', '_ipps._tcp', 12345) self.simulator.go(2) diff --git a/tests/scripts/thread-cert/test_srp_client_save_server_info.py b/tests/scripts/thread-cert/test_srp_client_save_server_info.py index cb277e5fc..5018aad08 100755 --- a/tests/scripts/thread-cert/test_srp_client_save_server_info.py +++ b/tests/scripts/thread-cert/test_srp_client_save_server_info.py @@ -105,8 +105,6 @@ def test(self): client.srp_client_set_host_address('2001::1') client.srp_client_add_service('my-service', '_ipps._tcp', 12345) - self.assertEqual(client.srp_client_get_state(), 'Disabled') - client.srp_client_enable_auto_start_mode() self.assertEqual(client.srp_client_get_auto_start_mode(), 'Enabled') self.simulator.go(WAIT_TIME) diff --git a/tests/scripts/thread-cert/test_srp_lease.py b/tests/scripts/thread-cert/test_srp_lease.py index 6d147117c..b259c21a5 100755 --- a/tests/scripts/thread-cert/test_srp_lease.py +++ b/tests/scripts/thread-cert/test_srp_lease.py @@ -83,7 +83,6 @@ def test(self): self.assertEqual(server.get_state(), 'leader') self.simulator.go(5) - client.srp_server_set_enabled(False) client.start() self.simulator.go(config.ROUTER_STARTUP_DELAY) self.assertEqual(client.get_state(), 'router') @@ -92,9 +91,10 @@ def test(self): # 1. Register a single service and verify that it works. # + self.assertEqual(client.srp_client_get_auto_start_mode(), 'Enabled') + client.srp_client_set_host_name('my-host') client.srp_client_set_host_address('2001::1') - client.srp_client_start(server.get_addrs()[0], client.get_srp_server_port()) client.srp_client_add_service('my-service', '_ipps._tcp', 12345) self.simulator.go(2) @@ -113,7 +113,7 @@ def test(self): self.assertEqual(server.srp_server_get_service('my-service', '_ipps._tcp')['deleted'], 'true') # Start the client again, the same service should be successfully registered. - client.srp_client_start(server.get_addrs()[0], client.get_srp_server_port()) + client.srp_client_enable_auto_start_mode() self.simulator.go(2) self.check_host_and_service(server, client) @@ -131,7 +131,7 @@ def test(self): self.assertEqual(len(server.srp_server_get_services()), 0) # Start the client again, the same service should be successfully registered. - client.srp_client_start(server.get_addrs()[0], client.get_srp_server_port()) + client.srp_client_enable_auto_start_mode() self.simulator.go(2) self.check_host_and_service(server, client) diff --git a/tests/scripts/thread-cert/test_srp_name_conflicts.py b/tests/scripts/thread-cert/test_srp_name_conflicts.py index 4451eab2d..984547f70 100755 --- a/tests/scripts/thread-cert/test_srp_name_conflicts.py +++ b/tests/scripts/thread-cert/test_srp_name_conflicts.py @@ -101,9 +101,10 @@ def test(self): # 1. Register a single service and verify that it works. # + self.assertEqual(client_1.srp_client_get_auto_start_mode(), 'Enabled') + client_1.srp_client_set_host_name('my-host-1') client_1.srp_client_set_host_address('2001::1') - client_1.srp_client_start(server.get_addrs()[0], client_1.get_srp_server_port()) client_1.srp_client_add_service('my-service-1', '_ipps._tcp', 12345) self.simulator.go(2) @@ -139,9 +140,10 @@ def test(self): # 2. Register with the same host name from the second client and it should fail. # + self.assertEqual(client_2.srp_client_get_auto_start_mode(), 'Enabled') + client_2.srp_client_set_host_name('my-host-1') client_2.srp_client_set_host_address('2001::2') - client_2.srp_client_start(server.get_addrs()[0], client_2.get_srp_server_port()) client_2.srp_client_add_service('my-service-2', '_ipps._tcp', 12345) self.simulator.go(2) @@ -160,9 +162,9 @@ def test(self): # 3. Register with the same service name from the second client and it should fail. # + client_2.srp_client_enable_auto_start_mode() client_2.srp_client_set_host_name('my-host-2') client_2.srp_client_set_host_address('2001::2') - client_2.srp_client_start(server.get_addrs()[0], client_2.get_srp_server_port()) client_2.srp_client_add_service('my-service-1', '_ipps._tcp', 12345) self.simulator.go(2) @@ -182,9 +184,9 @@ def test(self): # from the second client and it should pass. # + client_2.srp_client_enable_auto_start_mode() client_2.srp_client_set_host_name('my-host-2') client_2.srp_client_set_host_address('2001::2') - client_2.srp_client_start(server.get_addrs()[0], client_2.get_srp_server_port()) client_2.srp_client_add_service('my-service-1', '_ipps2._tcp', 12345) self.simulator.go(2) @@ -209,9 +211,9 @@ def test(self): # 5. Register with different host & service instance name, it should succeed. # + client_2.srp_client_enable_auto_start_mode() client_2.srp_client_set_host_name('my-host-2') client_2.srp_client_set_host_address('2001::2') - client_2.srp_client_start(server.get_addrs()[0], client_2.get_srp_server_port()) client_2.srp_client_add_service('my-service-2', '_ipps._tcp', 12345) self.simulator.go(2) @@ -241,9 +243,9 @@ def test(self): client_1.srp_client_remove_service('my-service-1', '_ipps._tcp') self.simulator.go(2) + client_2.srp_client_enable_auto_start_mode() client_2.srp_client_set_host_name('my-host-2') client_2.srp_client_set_host_address('2001::2') - client_2.srp_client_start(server.get_addrs()[0], client_2.get_srp_server_port()) client_2.srp_client_add_service('my-service-1', '_ipps._tcp', 12345) self.simulator.go(2) @@ -284,10 +286,10 @@ def test(self): # Client 2 registers the same host & service instance name with Client 1. client_2.srp_client_stop() + client_2.srp_client_enable_auto_start_mode() client_2.srp_client_clear_host() client_2.srp_client_set_host_name('my-host-1') client_2.srp_client_set_host_address('2001::2') - client_2.srp_client_start(server.get_addrs()[0], client_2.get_srp_server_port()) client_2.srp_client_add_service('my-service-1', '_ipps._tcp', 12345) self.simulator.go(2) diff --git a/tests/scripts/thread-cert/test_srp_register_500_services.py b/tests/scripts/thread-cert/test_srp_register_500_services.py index 54719ddc9..e69fc3e2f 100644 --- a/tests/scripts/thread-cert/test_srp_register_500_services.py +++ b/tests/scripts/thread-cert/test_srp_register_500_services.py @@ -132,13 +132,11 @@ def clients(): for fed in feds(): self.assertEqual(fed.get_state(), 'child') - server_addr = server.get_rloc() - for clientid in CLIENT_IDS: client = self.nodes[clientid] + self.assertEqual(client.srp_client_get_auto_start_mode(), 'Enabled') client.srp_client_set_host_name(f'client{clientid}') client.srp_client_set_host_address(f'2001::{clientid}') - client.srp_client_start(server_addr, client.get_srp_server_port()) for instanceid in INSTANCE_IDS: client.srp_client_add_service(f'client{clientid}_{instanceid}', SERVICE_NAME, SERVICE_PORT) diff --git a/tests/scripts/thread-cert/test_srp_register_single_service.py b/tests/scripts/thread-cert/test_srp_register_single_service.py index 621ad578c..33d298b72 100755 --- a/tests/scripts/thread-cert/test_srp_register_single_service.py +++ b/tests/scripts/thread-cert/test_srp_register_single_service.py @@ -89,9 +89,10 @@ def test(self): # 1. Register a single service and verify that it works. # + self.assertEqual(client.srp_client_get_auto_start_mode(), 'Enabled') + client.srp_client_set_host_name('my-host') client.srp_client_set_host_address('2001::1') - client.srp_client_start(server.get_addrs()[0], client.get_srp_server_port()) client.srp_client_add_service('my-service', '_ipps._tcp', 12345, 0, 0, ['abc', 'def=', 'xyz=XYZ']) self.simulator.go(2) diff --git a/tests/scripts/thread-cert/test_srp_server_reboot_port.py b/tests/scripts/thread-cert/test_srp_server_reboot_port.py index 411b598a5..d78dc118b 100755 --- a/tests/scripts/thread-cert/test_srp_server_reboot_port.py +++ b/tests/scripts/thread-cert/test_srp_server_reboot_port.py @@ -84,11 +84,9 @@ def test(self): self.assertEqual(server.get_state(), 'router') # - # 1. Enable auto start mode on client and check that server is used. + # 1. Check auto start mode on client and check that server is used. # - self.assertEqual(client.srp_client_get_state(), 'Disabled') - client.srp_client_enable_auto_start_mode() self.assertEqual(client.srp_client_get_auto_start_mode(), 'Enabled') self.simulator.go(2) self.assertEqual(client.srp_client_get_state(), 'Enabled') diff --git a/tests/scripts/thread-cert/test_srp_ttl.py b/tests/scripts/thread-cert/test_srp_ttl.py index 93cc81881..9c3a149db 100755 --- a/tests/scripts/thread-cert/test_srp_ttl.py +++ b/tests/scripts/thread-cert/test_srp_ttl.py @@ -85,9 +85,10 @@ def test(self): self.simulator.go(config.ROUTER_STARTUP_DELAY) self.assertEqual(client.get_state(), 'router') + self.assertEqual(client.srp_client_get_auto_start_mode(), 'Enabled') + client.srp_client_set_host_name('my-host') client.srp_client_set_host_address('2001::1') - client.srp_client_start(server.get_addrs()[0], client.get_srp_server_port()) client.srp_client_add_service('my-service', '_ipps._tcp', 12345) self.simulator.go(2) diff --git a/tests/toranj/cli/test-020-net-diag-vendor-info.py b/tests/toranj/cli/test-020-net-diag-vendor-info.py index 6f205cd25..f923dde19 100755 --- a/tests/toranj/cli/test-020-net-diag-vendor-info.py +++ b/tests/toranj/cli/test-020-net-diag-vendor-info.py @@ -68,6 +68,7 @@ VENDOR_MODEL_TLV = 26 VENDOR_SW_VERSION_TLV = 27 THREAD_STACK_VERSION_TLV = 28 +MLE_COUNTERS_TLV = 34 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Check setting vendor name, model, ans sw version @@ -176,6 +177,10 @@ else: verify(False) +result = r2.cli('networkdiagnostic get', r1_rloc, MLE_COUNTERS_TLV) +print(len(result) >= 1) +verify(result[1].startswith("MLE Counters:")) + # ----------------------------------------------------------------------------------------------------------------------- # Test finished diff --git a/tests/toranj/cli/test-400-srp-client-server.py b/tests/toranj/cli/test-400-srp-client-server.py index a74d26153..e65d6fffb 100755 --- a/tests/toranj/cli/test-400-srp-client-server.py +++ b/tests/toranj/cli/test-400-srp-client-server.py @@ -61,11 +61,10 @@ verify(server.srp_server_get_state() == 'disabled') verify(server.srp_server_get_addr_mode() == 'unicast') verify(client.srp_client_get_state() == 'Disabled') -verify(client.srp_client_get_auto_start_mode() == 'Disabled') +verify(client.srp_client_get_auto_start_mode() == 'Enabled') # Start server and client and register single service server.srp_server_enable() -client.srp_client_enable_auto_start_mode() client.srp_client_set_host_name('host') client.srp_client_set_host_address('fd00::cafe') diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index e14e30ad5..f44ffaeea 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -39,10 +39,14 @@ set(COMMON_INCLUDES_RCP set(COMMON_COMPILE_OPTIONS -DOPENTHREAD_FTD=1 + -DOPENTHREAD_MTD=0 + -DOPENTHREAD_RADIO=0 -DOPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE=1 ) set(COMMON_COMPILE_OPTIONS_RCP + -DOPENTHREAD_FTD=0 + -DOPENTHREAD_MTD=0 -DOPENTHREAD_RADIO=1 -DOPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE=1 -DOPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE=0 diff --git a/tests/unit/test_dns.cpp b/tests/unit/test_dns.cpp index a8408aad4..4566cde9c 100644 --- a/tests/unit/test_dns.cpp +++ b/tests/unit/test_dns.cpp @@ -56,20 +56,30 @@ void TestDnsName(void) const char *mExpectedReadName; }; - Instance *instance; - MessagePool *messagePool; - Message *message; - uint8_t buffer[kMaxSize]; - uint16_t len; - uint16_t offset; - char label[Dns::Name::kMaxLabelSize]; - uint8_t labelLength; - char name[Dns::Name::kMaxNameSize]; - const char *subDomain; - const char *domain; - const char *domain2; - const char *fullName; - const char *suffixName; + struct TestMatches + { + const char *mFullName; + const char *mFirstLabel; + const char *mLabels; + const char *mDomain; + bool mShouldMatch; + }; + + Instance *instance; + MessagePool *messagePool; + Message *message; + uint8_t buffer[kMaxSize]; + uint16_t len; + uint16_t offset; + Dns::Name::LabelBuffer label; + uint8_t labelLength; + Dns::Name::Buffer name; + const char *subDomain; + const char *domain; + const char *domain2; + const char *fullName; + const char *suffixName; + Dns::Name dnsName; static const uint8_t kEncodedName1[] = {7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0}; static const uint8_t kEncodedName2[] = {3, 'f', 'o', 'o', 1, 'a', 2, 'b', 'b', 3, 'e', 'd', 'u', 0}; @@ -139,6 +149,20 @@ void TestDnsName(void) static const char kBadLabel[] = "badlabel"; static const char kBadName[] = "bad.name"; + static const TestMatches kTestMatches[] = { + {"foo.bar.local.", "foo", "bar", "local.", true}, + {"foo.bar.local.", nullptr, "foo.bar", "local.", true}, + {"foo.bar.local.", "foo", "ba", "local.", false}, + {"foo.bar.local.", "fooooo", "bar", "local.", false}, + {"foo.bar.local.", "foo", "bar", "locall.", false}, + {"foo.bar.local.", "f", "bar", "local.", false}, + {"foo.bar.local.", "foo", "barr", "local.", false}, + {"foo.bar.local.", "foo", "bar", ".local.", false}, + {"My Lovely Instance._mt._udp.local.", "mY lovely instancE", "_mt._udp", "local.", true}, + {"My Lovely Instance._mt._udp.local.", nullptr, "mY lovely instancE._mt._udp", "local.", true}, + {"_s1._sub._srv._udp.default.service.arpa.", "_s1", "_sub._srv._udp", "default.service.arpa.", true}, + }; + printf("================================================================\n"); printf("TestDnsName()\n"); @@ -254,42 +278,68 @@ void TestDnsName(void) fullName = "my-service._ipps._tcp.default.service.arpa."; suffixName = "default.service.arpa."; - SuccessOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, sizeof(name))); + SuccessOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name)); + VerifyOrQuit(strcmp(name, "my-service._ipps._tcp") == 0); + + fullName = "my-service._ipps._tcp.default.service.arpa"; + suffixName = "default.service.arpa"; + SuccessOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name)); VerifyOrQuit(strcmp(name, "my-service._ipps._tcp") == 0); + fullName = "my-service._ipps._tcp.default.service.arpa"; + suffixName = "default.service.arpa."; + VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name) == kErrorParse); + + fullName = "my-service._ipps._tcp.default.service.arpa."; + suffixName = "default.service.arpa"; + VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name) == kErrorParse); + fullName = "my.service._ipps._tcp.default.service.arpa."; suffixName = "_ipps._tcp.default.service.arpa."; - SuccessOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, sizeof(name))); + SuccessOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name)); VerifyOrQuit(strcmp(name, "my.service") == 0); fullName = "my-service._ipps._tcp.default.service.arpa."; suffixName = "DeFault.SerVice.ARPA."; - SuccessOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, sizeof(name))); + SuccessOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name)); + VerifyOrQuit(strcmp(name, "my-service._ipps._tcp") == 0); + + fullName = "my-service._ipps._tcp.default.service.arpa"; + suffixName = "DeFault.SerVice.ARPA"; + SuccessOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name)); VerifyOrQuit(strcmp(name, "my-service._ipps._tcp") == 0); fullName = "my-service._ipps._tcp.default.service.arpa."; suffixName = "efault.service.arpa."; - VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, sizeof(name)) == kErrorParse); + VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name) == kErrorParse); + + fullName = "my-service._ipps._tcp.default.service.arpa"; + suffixName = "efault.service.arpa"; + VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name) == kErrorParse); fullName = "my-service._ipps._tcp.default.service.arpa."; suffixName = "xdefault.service.arpa."; - VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, sizeof(name)) == kErrorParse); + VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name) == kErrorParse); fullName = "my-service._ipps._tcp.default.service.arpa."; suffixName = ".default.service.arpa."; - VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, sizeof(name)) == kErrorParse); + VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name) == kErrorParse); fullName = "my-service._ipps._tcp.default.service.arpa."; suffixName = "default.service.arp."; - VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, sizeof(name)) == kErrorParse); + VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name) == kErrorParse); fullName = "default.service.arpa."; suffixName = "default.service.arpa."; - VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, sizeof(name)) == kErrorParse); + VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name) == kErrorParse); + + fullName = "default.service.arpa"; + suffixName = "default.service.arpa"; + VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name) == kErrorParse); fullName = "efault.service.arpa."; suffixName = "default.service.arpa."; - VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, sizeof(name)) == kErrorParse); + VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name) == kErrorParse); fullName = "my-service._ipps._tcp.default.service.arpa."; suffixName = "default.service.arpa."; @@ -342,7 +392,7 @@ void TestDnsName(void) // Read entire name offset = 0; - SuccessOrQuit(Dns::Name::ReadName(*message, offset, name, sizeof(name))); + SuccessOrQuit(Dns::Name::ReadName(*message, offset, name)); printf("Read name =\"%s\"\n", name); @@ -496,6 +546,53 @@ void TestDnsName(void) VerifyOrQuit(memcmp(buffer, test.mEncodedData, len) == 0, "Encoded name data does not match expected data"); } + printf("----------------------------------------------------------------\n"); + printf("Name::Matches() variations\n"); + + for (const TestMatches &test : kTestMatches) + { + printf(" \"%s\"\n", test.mFullName); + + dnsName.Set(test.mFullName); + VerifyOrQuit(dnsName.Matches(test.mFirstLabel, test.mLabels, test.mDomain) == test.mShouldMatch); + + IgnoreError(message->SetLength(0)); + SuccessOrQuit(dnsName.AppendTo(*message)); + + dnsName.SetFromMessage(*message, 0); + VerifyOrQuit(dnsName.Matches(test.mFirstLabel, test.mLabels, test.mDomain) == test.mShouldMatch); + } + + IgnoreError(message->SetLength(0)); + dnsName.SetFromMessage(*message, 0); + SuccessOrQuit(Dns::Name::AppendLabel("Name.With.Dot", *message)); + SuccessOrQuit(Dns::Name::AppendName("_srv._udp.local.", *message)); + + VerifyOrQuit(dnsName.Matches("Name.With.Dot", "_srv._udp", "local.")); + VerifyOrQuit(dnsName.Matches("nAme.with.dOT", "_srv._udp", "local.")); + VerifyOrQuit(dnsName.Matches("Name.With.Dot", "_srv", "_udp.local.")); + + VerifyOrQuit(!dnsName.Matches("Name", "With.Dot._srv._udp", "local.")); + VerifyOrQuit(!dnsName.Matches("Name.", "With.Dot._srv._udp", "local.")); + VerifyOrQuit(!dnsName.Matches("Name.With", "Dot._srv._udp", "local.")); + + VerifyOrQuit(!dnsName.Matches("Name.With.Dott", "_srv._udp", "local.")); + VerifyOrQuit(!dnsName.Matches("Name.With.Dot.", "_srv._udp", "local.")); + VerifyOrQuit(!dnsName.Matches("Name.With.Dot", "_srv._tcp", "local.")); + VerifyOrQuit(!dnsName.Matches("Name.With.Dot", "_srv._udp", "arpa.")); + + offset = 0; + SuccessOrQuit(Dns::Name::ReadName(*message, offset, name)); + dnsName.Set(name); + + VerifyOrQuit(dnsName.Matches("Name.With.Dot", "_srv._udp", "local.")); + VerifyOrQuit(dnsName.Matches("nAme.with.dOT", "_srv._udp", "local.")); + VerifyOrQuit(dnsName.Matches("Name.With.Dot", "_srv", "_udp.local.")); + VerifyOrQuit(!dnsName.Matches("Name.With.Dott", "_srv._udp", "local.")); + VerifyOrQuit(!dnsName.Matches("Name.With.Dot.", "_srv._udp", "local.")); + VerifyOrQuit(!dnsName.Matches("Name.With.Dot", "_srv._tcp", "local.")); + VerifyOrQuit(!dnsName.Matches("Name.With.Dot", "_srv._udp", "arpa.")); + message->Free(); testFreeInstance(instance); } @@ -528,6 +625,13 @@ void TestDnsCompressedName(void) static const char *kName3Labels[] = {"ISI", "ARPA"}; static const char *kName4Labels[] = {"Human.Readable", "F", "ISI", "ARPA"}; + static const char *kName1MultiLabels[] = {"F.ISI", "ARPA"}; + static const char *kName2MultiLabels1[] = {"FOO", "F.ISI.ARPA."}; + static const char *kName2MultiLabels2[] = {"FOO.F.", "ISI.ARPA."}; + + static const char kName1BadMultiLabels[] = "F.ISI.ARPA.MORE"; + static const char kName2BadMultiLabels[] = "FOO.F.IS"; + static const char kExpectedReadName1[] = "F.ISI.ARPA."; static const char kExpectedReadName2[] = "FOO.F.ISI.ARPA."; static const char kExpectedReadName3[] = "ISI.ARPA."; @@ -633,17 +737,41 @@ void TestDnsCompressedName(void) "Name::ReadLabel() failed at end of the name"); offset = name1Offset; - SuccessOrQuit(Dns::Name::ReadName(*message, offset, name, sizeof(name))); + SuccessOrQuit(Dns::Name::ReadName(*message, offset, name)); printf("Read name =\"%s\"\n", name); VerifyOrQuit(strcmp(name, kExpectedReadName1) == 0, "Name::ReadName() did not return expected name"); VerifyOrQuit(offset == name1Offset + sizeof(kEncodedName), "Name::ReadName() returned incorrect offset"); offset = name1Offset; - for (const char *nameLabel : kName1Labels) { SuccessOrQuit(Dns::Name::CompareLabel(*message, offset, nameLabel)); } + SuccessOrQuit(Dns::Name::CompareName(*message, offset, ".")); + + offset = name1Offset; + for (const char *nameLabel : kName1Labels) + { + SuccessOrQuit(Dns::Name::CompareMultipleLabels(*message, offset, nameLabel)); + } + SuccessOrQuit(Dns::Name::CompareName(*message, offset, ".")); + + offset = name1Offset; + SuccessOrQuit(Dns::Name::CompareMultipleLabels(*message, offset, kExpectedReadName1)); + SuccessOrQuit(Dns::Name::CompareName(*message, offset, ".")); + + offset = name1Offset; + VerifyOrQuit(Dns::Name::CompareMultipleLabels(*message, offset, kBadName) == kErrorNotFound); + + offset = name1Offset; + VerifyOrQuit(Dns::Name::CompareMultipleLabels(*message, offset, kName1BadMultiLabels) == kErrorNotFound); + + offset = name1Offset; + for (const char *nameLabels : kName1MultiLabels) + { + SuccessOrQuit(Dns::Name::CompareMultipleLabels(*message, offset, nameLabels)); + } + SuccessOrQuit(Dns::Name::CompareName(*message, offset, ".")); offset = name1Offset; SuccessOrQuit(Dns::Name::CompareName(*message, offset, kExpectedReadName1)); @@ -690,17 +818,48 @@ void TestDnsCompressedName(void) "Name::ReadLabel() failed at end of the name"); offset = name2Offset; - SuccessOrQuit(Dns::Name::ReadName(*message, offset, name, sizeof(name))); + SuccessOrQuit(Dns::Name::ReadName(*message, offset, name)); printf("Read name =\"%s\"\n", name); VerifyOrQuit(strcmp(name, kExpectedReadName2) == 0, "Name::ReadName() did not return expected name"); VerifyOrQuit(offset == name2Offset + kName2EncodedSize, "Name::ReadName() returned incorrect offset"); offset = name2Offset; - for (const char *nameLabel : kName2Labels) { SuccessOrQuit(Dns::Name::CompareLabel(*message, offset, nameLabel)); } + SuccessOrQuit(Dns::Name::CompareName(*message, offset, ".")); + + offset = name2Offset; + for (const char *nameLabel : kName2Labels) + { + SuccessOrQuit(Dns::Name::CompareMultipleLabels(*message, offset, nameLabel)); + } + SuccessOrQuit(Dns::Name::CompareName(*message, offset, ".")); + + offset = name2Offset; + SuccessOrQuit(Dns::Name::CompareMultipleLabels(*message, offset, kExpectedReadName2)); + SuccessOrQuit(Dns::Name::CompareName(*message, offset, ".")); + + offset = name2Offset; + VerifyOrQuit(Dns::Name::CompareMultipleLabels(*message, offset, kBadName) == kErrorNotFound); + + offset = name2Offset; + VerifyOrQuit(Dns::Name::CompareMultipleLabels(*message, offset, kName2BadMultiLabels) == kErrorNotFound); + + offset = name2Offset; + for (const char *nameLabels : kName2MultiLabels1) + { + SuccessOrQuit(Dns::Name::CompareMultipleLabels(*message, offset, nameLabels)); + } + SuccessOrQuit(Dns::Name::CompareName(*message, offset, ".")); + + offset = name2Offset; + for (const char *nameLabels : kName2MultiLabels2) + { + SuccessOrQuit(Dns::Name::CompareMultipleLabels(*message, offset, nameLabels)); + } + SuccessOrQuit(Dns::Name::CompareName(*message, offset, ".")); offset = name2Offset; SuccessOrQuit(Dns::Name::CompareName(*message, offset, kExpectedReadName2)); @@ -747,17 +906,28 @@ void TestDnsCompressedName(void) "Name::ReadLabel() failed at end of the name"); offset = name3Offset; - SuccessOrQuit(Dns::Name::ReadName(*message, offset, name, sizeof(name))); + SuccessOrQuit(Dns::Name::ReadName(*message, offset, name)); printf("Read name =\"%s\"\n", name); VerifyOrQuit(strcmp(name, kExpectedReadName3) == 0, "Name::ReadName() did not return expected name"); VerifyOrQuit(offset == name3Offset + kName3EncodedSize, "Name::ReadName() returned incorrect offset"); offset = name3Offset; - for (const char *nameLabel : kName3Labels) { SuccessOrQuit(Dns::Name::CompareLabel(*message, offset, nameLabel)); } + SuccessOrQuit(Dns::Name::CompareName(*message, offset, ".")); + + offset = name3Offset; + for (const char *nameLabel : kName3Labels) + { + SuccessOrQuit(Dns::Name::CompareMultipleLabels(*message, offset, nameLabel)); + } + SuccessOrQuit(Dns::Name::CompareName(*message, offset, ".")); + + offset = name3Offset; + SuccessOrQuit(Dns::Name::CompareMultipleLabels(*message, offset, kExpectedReadName3)); + SuccessOrQuit(Dns::Name::CompareName(*message, offset, ".")); offset = name3Offset; SuccessOrQuit(Dns::Name::CompareName(*message, offset, kExpectedReadName3)); @@ -801,17 +971,24 @@ void TestDnsCompressedName(void) // `ReadName()` for name-4 should still succeed since only the first label contains dot char offset = name4Offset; - SuccessOrQuit(Dns::Name::ReadName(*message, offset, name, sizeof(name))); + SuccessOrQuit(Dns::Name::ReadName(*message, offset, name)); printf("Read name =\"%s\"\n", name); VerifyOrQuit(strcmp(name, kExpectedReadName4) == 0, "Name::ReadName() did not return expected name"); VerifyOrQuit(offset == name4Offset + kName4EncodedSize, "Name::ParseName() returned incorrect offset"); offset = name4Offset; - for (const char *nameLabel : kName4Labels) { SuccessOrQuit(Dns::Name::CompareLabel(*message, offset, nameLabel)); } + SuccessOrQuit(Dns::Name::CompareName(*message, offset, ".")); + + offset = name4Offset; + for (const char *nameLabel : kName4Labels) + { + SuccessOrQuit(Dns::Name::CompareMultipleLabels(*message, offset, nameLabel)); + } + SuccessOrQuit(Dns::Name::CompareName(*message, offset, ".")); offset = name4Offset; SuccessOrQuit(Dns::Name::CompareName(*message, offset, *message, offset), "Name::CompareName() with itself failed"); @@ -848,11 +1025,11 @@ void TestDnsCompressedName(void) SuccessOrQuit(Dns::Name::CompareName(*message2, offset, dnsName4)); offset = 0; - SuccessOrQuit(Dns::Name::ReadName(*message2, offset, name, sizeof(name))); + SuccessOrQuit(Dns::Name::ReadName(*message2, offset, name)); printf("- Name1 after `AppendTo()`: \"%s\"\n", name); - SuccessOrQuit(Dns::Name::ReadName(*message2, offset, name, sizeof(name))); + SuccessOrQuit(Dns::Name::ReadName(*message2, offset, name)); printf("- Name2 after `AppendTo()`: \"%s\"\n", name); - SuccessOrQuit(Dns::Name::ReadName(*message2, offset, name, sizeof(name))); + SuccessOrQuit(Dns::Name::ReadName(*message2, offset, name)); printf("- Name3 after `AppendTo()`: \"%s\"\n", name); // `ReadName()` for name-4 will fail due to first label containing dot char. @@ -913,9 +1090,9 @@ void TestHeaderAndResourceRecords(void) Dns::ResourceRecord record; Ip6::Address hostAddress; - char label[Dns::Name::kMaxLabelSize]; - char name[Dns::Name::kMaxNameSize]; - uint8_t buffer[kMaxSize]; + Dns::Name::LabelBuffer label; + Dns::Name::Buffer name; + uint8_t buffer[kMaxSize]; printf("================================================================\n"); printf("TestHeaderAndResourceRecords()\n"); @@ -1050,7 +1227,7 @@ void TestHeaderAndResourceRecords(void) SuccessOrQuit(Dns::ResourceRecord::ReadRecord(*message, offset, ptrRecord)); VerifyOrQuit(ptrRecord.GetTtl() == kTtl, "Read PTR is incorrect"); - SuccessOrQuit(ptrRecord.ReadPtrName(*message, offset, label, sizeof(label), name, sizeof(name))); + SuccessOrQuit(ptrRecord.ReadPtrName(*message, offset, label, name)); VerifyOrQuit(strcmp(label, instanceLabel) == 0, "Inst label is incorrect"); VerifyOrQuit(strcmp(name, kServiceName) == 0); @@ -1077,7 +1254,7 @@ void TestHeaderAndResourceRecords(void) VerifyOrQuit(numRecords == prevNumRecords - 1, "Incorrect num records"); SuccessOrQuit(Dns::ResourceRecord::ReadRecord(*message, offset, ptrRecord)); VerifyOrQuit(ptrRecord.GetTtl() == kTtl, "Read PTR is incorrect"); - SuccessOrQuit(ptrRecord.ReadPtrName(*message, offset, label, sizeof(label), name, sizeof(name))); + SuccessOrQuit(ptrRecord.ReadPtrName(*message, offset, label, name)); printf(" \"%s\" PTR %u %d inst:\"%s\" at \"%s\"\n", kServiceName, ptrRecord.GetTtl(), ptrRecord.GetLength(), label, name); } @@ -1125,7 +1302,7 @@ void TestHeaderAndResourceRecords(void) VerifyOrQuit(srvRecord.GetPort() == kSrvPort); VerifyOrQuit(srvRecord.GetWeight() == kSrvWeight); VerifyOrQuit(srvRecord.GetPriority() == kSrvPriority); - SuccessOrQuit(srvRecord.ReadTargetHostName(*message, offset, name, sizeof(name))); + SuccessOrQuit(srvRecord.ReadTargetHostName(*message, offset, name)); VerifyOrQuit(strcmp(name, kHostName) == 0); printf(" \"%s\" SRV %u %d %d %d %d \"%s\"\n", instanceName, srvRecord.GetTtl(), srvRecord.GetLength(), srvRecord.GetPort(), srvRecord.GetWeight(), srvRecord.GetPriority(), name); diff --git a/tests/unit/test_dns_client.cpp b/tests/unit/test_dns_client.cpp index 59efab72d..74c5598c0 100644 --- a/tests/unit/test_dns_client.cpp +++ b/tests/unit/test_dns_client.cpp @@ -357,10 +357,10 @@ struct BrowseInfo { void Reset(void) { mCallbackCount = 0; } - uint16_t mCallbackCount; - Error mError; - char mServiceName[Dns::Name::kMaxNameSize]; - uint16_t mNumInstances; + uint16_t mCallbackCount; + Error mError; + Dns::Name::Buffer mServiceName; + uint16_t mNumInstances; }; static BrowseInfo sBrowseInfo; @@ -384,8 +384,8 @@ void BrowseCallback(otError aError, const otDnsBrowseResponse *aResponse, void * for (uint16_t index = 0;; index++) { - char instLabel[Dns::Name::kMaxLabelSize]; - Error error; + Dns::Name::LabelBuffer instLabel; + Error error; error = response.GetServiceInstance(index, instLabel, sizeof(instLabel)); @@ -423,7 +423,7 @@ struct ResolveServiceInfo uint16_t mCallbackCount; Error mError; Dns::Client::ServiceInfo mInfo; - char mNameBuffer[Dns::Name::kMaxNameSize]; + Dns::Name::Buffer mNameBuffer; uint8_t mTxtBuffer[kMaxTxtBuffer]; Ip6::Address mHostAddresses[kMaxHostAddresses]; uint8_t mNumHostAddresses; @@ -434,8 +434,8 @@ static ResolveServiceInfo sResolveServiceInfo; void ServiceCallback(otError aError, const otDnsServiceResponse *aResponse, void *aContext) { const Dns::Client::ServiceResponse &response = AsCoreType(aResponse); - char instLabel[Dns::Name::kMaxLabelSize]; - char serviceName[Dns::Name::kMaxNameSize]; + Dns::Name::LabelBuffer instLabel; + Dns::Name::Buffer serviceName; Log("ServiceCallback"); Log(" Error: %s", ErrorToString(aError)); @@ -912,8 +912,8 @@ void TestDnsClient(void) //---------------------------------------------------------------------------------------------------------------------- -char sLastSubscribeName[Dns::Name::kMaxNameSize]; -char sLastUnsubscribeName[Dns::Name::kMaxNameSize]; +Dns::Name::Buffer sLastSubscribeName; +Dns::Name::Buffer sLastUnsubscribeName; void QuerySubscribe(void *aContext, const char *aFullName) { diff --git a/tests/unit/test_heap_string.cpp b/tests/unit/test_heap_string.cpp index cc72d5af2..3feb4b65f 100644 --- a/tests/unit/test_heap_string.cpp +++ b/tests/unit/test_heap_string.cpp @@ -171,11 +171,15 @@ void VerifyData(const Heap::Data &aData, const uint8_t *aBytes, uint16_t aLength PrintData(aData); + VerifyOrQuit(aData.Matches(aBytes, aLength)); + VerifyOrQuit(!aData.Matches(aBytes, aLength + 1)); + if (aLength == 0) { VerifyOrQuit(aData.IsNull()); VerifyOrQuit(aData.GetBytes() == nullptr); VerifyOrQuit(aData.GetLength() == 0); + VerifyOrQuit(aData.Matches(nullptr, 0)); } else { @@ -186,6 +190,10 @@ void VerifyData(const Heap::Data &aData, const uint8_t *aBytes, uint16_t aLength aData.CopyBytesTo(buffer); VerifyOrQuit(memcmp(buffer, aBytes, aLength) == 0, "CopyBytesTo() failed"); + + VerifyOrQuit(aData.Matches(buffer, aLength)); + buffer[aLength - 1]++; + VerifyOrQuit(!aData.Matches(buffer, aLength)); } } @@ -223,6 +231,10 @@ void TestHeapData(void) printf("After constructor\n"); VerifyData(data, nullptr, 0); + VerifyOrQuit(data.Matches(nullptr, 0)); + VerifyOrQuit(data.Matches(kData1, 0)); + VerifyOrQuit(!data.Matches(kData1, 1)); + printf("------------------------------------------------------------------------------------\n"); printf("SetFrom(aBuffer, aLength)\n"); diff --git a/tests/unit/test_platform.cpp b/tests/unit/test_platform.cpp index 361711428..2ede8e8e8 100644 --- a/tests/unit/test_platform.cpp +++ b/tests/unit/test_platform.cpp @@ -424,6 +424,10 @@ OT_TOOL_WEAK void otPlatTrelDisable(otInstance *) {} OT_TOOL_WEAK void otPlatTrelSend(otInstance *, const uint8_t *, uint16_t, const otSockAddr *) {} OT_TOOL_WEAK void otPlatTrelRegisterService(otInstance *, uint16_t, const uint8_t *, uint8_t) {} + +OT_TOOL_WEAK const otPlatTrelCounters *otPlatTrelGetCounters(otInstance *) { return nullptr; } + +OT_TOOL_WEAK void otPlatTrelResetCounters(otInstance *) {} #endif #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE diff --git a/tests/unit/test_platform.h b/tests/unit/test_platform.h index 97a9d79d9..7197feb7e 100644 --- a/tests/unit/test_platform.h +++ b/tests/unit/test_platform.h @@ -40,6 +40,7 @@ #include #include #include +#include #include "common/code_utils.hpp" #include "instance/instance.hpp" diff --git a/tests/unit/test_routing_manager.cpp b/tests/unit/test_routing_manager.cpp index ef2a53bf1..6fc0a37d5 100644 --- a/tests/unit/test_routing_manager.cpp +++ b/tests/unit/test_routing_manager.cpp @@ -58,6 +58,9 @@ static const char kInfraIfAddress[] = "fe80::1"; static constexpr uint32_t kValidLitime = 2000; static constexpr uint32_t kPreferredLifetime = 1800; +static constexpr uint32_t kRioValidLifetime = 1800; +static constexpr uint32_t kRioDeprecatingLifetime = 300; + static constexpr uint16_t kMaxRaSize = 800; static constexpr uint16_t kMaxDeprecatingPrefixes = 16; @@ -224,6 +227,8 @@ void SendRouterAdvert(const Ip6::Address &aAddress, const Icmp6Packet &aP void SendNeighborAdvert(const Ip6::Address &aAddress, const Ip6::Nd::NeighborAdvertMessage &aNaMessage); void DiscoverNat64Prefix(const Ip6::Prefix &aPrefix); +extern "C" { + #if OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...) { @@ -243,8 +248,6 @@ void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat //---------------------------------------------------------------------------------------------------------------------- // `otPlatRadio -extern "C" { - otRadioCaps otPlatRadioGetCaps(otInstance *) { return OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_CSMA_BACKOFF; } otError otPlatRadioTransmit(otInstance *, otRadioFrame *) @@ -339,6 +342,36 @@ otError otPlatInfraIfSendIcmp6Nd(uint32_t aInfraIfIndex, return OT_ERROR_NONE; } +//---------------------------------------------------------------------------------------------------------------------- + +Array sHeapAllocatedPtrs; + +#if OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE + +void *otPlatCAlloc(size_t aNum, size_t aSize) +{ + void *ptr = calloc(aNum, aSize); + + SuccessOrQuit(sHeapAllocatedPtrs.PushBack(ptr)); + + return ptr; +} + +void otPlatFree(void *aPtr) +{ + if (aPtr != nullptr) + { + void **entry = sHeapAllocatedPtrs.Find(aPtr); + + VerifyOrQuit(entry != nullptr, "A heap allocated item is freed twice"); + sHeapAllocatedPtrs.Remove(*entry); + } + + free(aPtr); +} + +#endif + } // extern "C" //--------------------------------------------------------------------------------------------------------------------- @@ -533,35 +566,6 @@ void ValidateRouterAdvert(const Icmp6Packet &aPacket) //---------------------------------------------------------------------------------------------------------------------- -Array sHeapAllocatedPtrs; - -#if OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE - -void *otPlatCAlloc(size_t aNum, size_t aSize) -{ - void *ptr = calloc(aNum, aSize); - - SuccessOrQuit(sHeapAllocatedPtrs.PushBack(ptr)); - - return ptr; -} - -void otPlatFree(void *aPtr) -{ - if (aPtr != nullptr) - { - void **entry = sHeapAllocatedPtrs.Find(aPtr); - - VerifyOrQuit(entry != nullptr, "A heap allocated item is freed twice"); - sHeapAllocatedPtrs.Remove(*entry); - } - - free(aPtr); -} -#endif - -//---------------------------------------------------------------------------------------------------------------------- - void LogRouterAdvert(const Icmp6Packet &aPacket) { Ip6::Nd::RouterAdvertMessage raMsg(aPacket); @@ -1382,6 +1386,8 @@ void TestOmrSelection(void) VerifyOrQuit(sRsEmitted); VerifyOrQuit(sRaValidated); VerifyOrQuit(sExpectedRios.SawAll()); + VerifyOrQuit(sExpectedRios[0].mLifetime == kRioValidLifetime); + Log("Received RA was validated"); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1409,17 +1415,20 @@ void TestOmrSelection(void) AdvanceTime(100); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Make sure BR emits RA with new OMR prefix now. + // Make sure BR emits RA with the new OMR prefix now, and deprecates the old OMR prefix. sRaValidated = false; sExpectedPio = kPioAdvertisingLocalOnLink; sExpectedRios.Clear(); sExpectedRios.Add(omrPrefix); + sExpectedRios.Add(localOmr); AdvanceTime(20000); VerifyOrQuit(sRaValidated); VerifyOrQuit(sExpectedRios.SawAll()); + VerifyOrQuit(sExpectedRios[0].mLifetime == kRioValidLifetime); + VerifyOrQuit(sExpectedRios[1].mLifetime <= kRioDeprecatingLifetime); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check Network Data. We should now see that the local OMR prefix @@ -1437,16 +1446,20 @@ void TestOmrSelection(void) AdvanceTime(100); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Make sure BR emits RA with local OMR prefix again. + // Make sure BR emits RA with local OMR prefix again and start + // deprecating the previously added OMR prefix. sRaValidated = false; sExpectedRios.Clear(); + sExpectedRios.Add(omrPrefix); sExpectedRios.Add(localOmr); AdvanceTime(20000); VerifyOrQuit(sRaValidated); VerifyOrQuit(sExpectedRios.SawAll()); + VerifyOrQuit(sExpectedRios[0].mLifetime <= kRioDeprecatingLifetime); + VerifyOrQuit(sExpectedRios[1].mLifetime == kRioValidLifetime); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check Network Data. We should see that the local OMR prefix is @@ -1455,6 +1468,21 @@ void TestOmrSelection(void) VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false); VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet); + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Wait enough for old deprecating OMR prefix deprecating to expire. + + sRaValidated = false; + sExpectedRios.Clear(); + sExpectedRios.Add(omrPrefix); + sExpectedRios.Add(localOmr); + + AdvanceTime(310000); + + VerifyOrQuit(sRaValidated); + VerifyOrQuit(sExpectedRios.SawAll()); + VerifyOrQuit(sExpectedRios[0].mLifetime == 0); + VerifyOrQuit(sExpectedRios[1].mLifetime == kRioValidLifetime); + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SuccessOrQuit(sInstance->Get().SetEnabled(false)); @@ -2023,7 +2051,10 @@ void TestDomainPrefixAsOmr(void) VerifyOrQuit(sExpectedRios[1].mPrefix == localOmr); VerifyOrQuit(sExpectedRios[1].mSawInRa); - VerifyOrQuit(sExpectedRios[1].mLifetime == 0); + VerifyOrQuit(sExpectedRios[1].mLifetime <= kRioDeprecatingLifetime); + + // Wait long enough for deprecating RIO prefix to expire + AdvanceTime(3200000); sRaValidated = false; sExpectedPio = kPioAdvertisingLocalOnLink; diff --git a/tools/otci/tests/test_otci.py b/tools/otci/tests/test_otci.py index 8e5a598c5..011c8a379 100644 --- a/tools/otci/tests/test_otci.py +++ b/tools/otci/tests/test_otci.py @@ -406,8 +406,6 @@ def _test_otci_srp(self, client: OTCI, server: OTCI): self.assertEqual([], server.srp_server_get_hosts()) self.assertEqual('running', server.srp_server_get_state()) - self.assertFalse(client.srp_client_get_autostart()) - client.srp_client_enable_autostart() self.assertTrue(client.srp_client_get_autostart()) client.wait(3) self.assertTrue(client.srp_client_get_state())