diff --git a/src/transport/raw/PeerAddress.h b/src/transport/raw/PeerAddress.h index 535f0ff9102d48..7c7f80db6c3f1d 100644 --- a/src/transport/raw/PeerAddress.h +++ b/src/transport/raw/PeerAddress.h @@ -101,6 +101,8 @@ class PeerAddress bool IsInitialized() const { return mTransportType != Type::kUndefined; } + bool IsMulticast() { return Type::kUdp == mTransportType && mIPAddress.IsIPv6Multicast(); } + bool operator==(const PeerAddress & other) const { return (mTransportType == other.mTransportType) && (mIPAddress == other.mIPAddress) && (mPort == other.mPort) && @@ -201,6 +203,22 @@ class PeerAddress return TCP(addr).SetPort(port).SetInterface(interface); } + static PeerAddress Multicast(chip::FabricId fabric, chip::GroupId group) + { + constexpr uint8_t scope = 0x05; // Site-Local + constexpr uint8_t prefixLength = 0x40; // 64-bit long network prefix field + // The network prefix portion of the Multicast Address is the 64-bit bitstring formed by concatenating: + // * 0xFD to designate a locally assigned ULA prefix + // * The upper 56-bits of the Fabric ID for the network in big-endian order + const uint64_t prefix = 0xfd00000000000000 | ((fabric >> 8) & 0x00ffffffffffffff); + // The 32-bit group identifier portion of the Multicast Address is the 32-bits formed by: + // * The lower 8-bits of the Fabric ID + // * 0x00 + // * The 16-bits Group Identifier in big-endian order + uint32_t groupId = static_cast((fabric << 24) & 0xff000000) | group; + return UDP(Inet::IPAddress::MakeIPv6PrefixMulticast(scope, prefixLength, prefix, groupId)); + } + private: Inet::IPAddress mIPAddress = {}; Type mTransportType = Type::kUndefined; diff --git a/src/transport/raw/tests/BUILD.gn b/src/transport/raw/tests/BUILD.gn index bcc2aada1995fd..ae606987ed5b7d 100644 --- a/src/transport/raw/tests/BUILD.gn +++ b/src/transport/raw/tests/BUILD.gn @@ -39,7 +39,10 @@ static_library("helpers") { chip_test_suite("tests") { output_name = "libRawTransportTests" - test_sources = [ "TestMessageHeader.cpp" ] + test_sources = [ + "TestMessageHeader.cpp", + "TestPeerAddress.cpp", + ] if (current_os != "mac") { test_sources += [ "TestTCP.cpp" ] diff --git a/src/transport/raw/tests/TestPeerAddress.cpp b/src/transport/raw/tests/TestPeerAddress.cpp new file mode 100644 index 00000000000000..b6d67e8342b7b0 --- /dev/null +++ b/src/transport/raw/tests/TestPeerAddress.cpp @@ -0,0 +1,95 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2016-2017 Nest Labs, Inc. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +using namespace chip; + +/** + * Test correct identification of IPv6 multicast addresses. + */ +void TestPeerAddressMulticast(nlTestSuite * inSuite, void * inContext) +{ + constexpr chip::FabricId fabric = 0xa1a2a4a8b1b2b4b8; + constexpr chip::GroupId group = 0xe10f; + chip::Transport::PeerAddress addr = chip::Transport::PeerAddress::Multicast(fabric, group); + NL_TEST_ASSERT(inSuite, chip::Transport::Type::kUdp == addr.GetTransportType()); + NL_TEST_ASSERT(inSuite, addr.IsMulticast()); + + const Inet::IPAddress & ip = addr.GetIPAddress(); + NL_TEST_ASSERT(inSuite, ip.IsIPv6Multicast()); + NL_TEST_ASSERT(inSuite, chip::Inet::IPAddressType::kIPv6 == ip.Type()); + + constexpr uint8_t expected[NL_INET_IPV6_ADDR_LEN_IN_BYTES] = { 0xff, 0x35, 0x00, 0x40, 0xfd, 0xa1, 0xa2, 0xa4, + 0xa8, 0xb1, 0xb2, 0xb4, 0xb8, 0x00, 0xe1, 0x0f }; + uint8_t result[NL_INET_IPV6_ADDR_LEN_IN_BYTES]; + uint8_t * p = result; + ip.WriteAddress(p); + NL_TEST_ASSERT(inSuite, !memcmp(expected, result, NL_INET_IPV6_ADDR_LEN_IN_BYTES)); +} + +/** + * Test Suite. It lists all the test functions. + */ + +// clang-format off +static const nlTest sTests[] = +{ + NL_TEST_DEF("PeerAddress Multicast", TestPeerAddressMulticast), + NL_TEST_SENTINEL() +}; +// clang-format on + +int TestPeerAddress(void) +{ + // clang-format off + nlTestSuite theSuite = + { + "PeerAddress", + &sTests[0], + nullptr, + nullptr + }; + // clang-format on + + // Run test suit againt one context. + nlTestRunner(&theSuite, nullptr); + + return (nlTestRunnerStats(&theSuite)); +} + +CHIP_REGISTER_TEST_SUITE(TestPeerAddress)