1 /*
2 * Copyright (c) 2024, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <gmock/gmock.h>
30 #include <gtest/gtest.h>
31
32 #include "host/posix/infra_if.hpp"
33 #include "host/posix/netif.hpp"
34
35 // Only Test on linux platform for now.
36 #ifdef __linux__
37
38 class InfraIfDependencyTest : public otbr::InfraIf::Dependencies
39 {
40 public:
InfraIfDependencyTest(void)41 InfraIfDependencyTest(void)
42 : mInfraIfIndex(0)
43 , mIsRunning(false)
44 , mSetInfraIfInvoked(false)
45 , mIcmp6NdDataLen(0)
46 , mHandleIcmp6NdInvoked(false)
47 {
48 memset(mIcmp6NdData, 0, sizeof(mIcmp6NdData));
49 }
50
SetInfraIf(unsigned int aInfraIfIndex,bool aIsRunning,const std::vector<otbr::Ip6Address> & aIp6Addresses)51 otbrError SetInfraIf(unsigned int aInfraIfIndex,
52 bool aIsRunning,
53 const std::vector<otbr::Ip6Address> &aIp6Addresses) override
54 {
55 mInfraIfIndex = aInfraIfIndex;
56 mIsRunning = aIsRunning;
57 mIp6Addresses = aIp6Addresses;
58 mSetInfraIfInvoked = true;
59
60 return OTBR_ERROR_NONE;
61 }
62
HandleIcmp6Nd(uint32_t aInfraIfIndex,const otbr::Ip6Address & aSrcAddress,const uint8_t * aData,uint16_t aDataLen)63 otbrError HandleIcmp6Nd(uint32_t aInfraIfIndex,
64 const otbr::Ip6Address &aSrcAddress,
65 const uint8_t *aData,
66 uint16_t aDataLen) override
67 {
68 mInfraIfIndex = aInfraIfIndex;
69 mIcmp6NdSrcAddress = aSrcAddress;
70 memcpy(mIcmp6NdData, aData, aDataLen);
71 mIcmp6NdDataLen = aDataLen;
72 mHandleIcmp6NdInvoked = true;
73
74 return OTBR_ERROR_NONE;
75 }
76
77 unsigned int mInfraIfIndex;
78 bool mIsRunning;
79 std::vector<otbr::Ip6Address> mIp6Addresses;
80 bool mSetInfraIfInvoked;
81
82 otbr::Ip6Address mIcmp6NdSrcAddress;
83 uint8_t mIcmp6NdData[1280];
84 uint16_t mIcmp6NdDataLen;
85 bool mHandleIcmp6NdInvoked;
86 };
87
TEST(InfraIf,DepsSetInfraIfInvokedCorrectly_AfterSpecifyingInfraIf)88 TEST(InfraIf, DepsSetInfraIfInvokedCorrectly_AfterSpecifyingInfraIf)
89 {
90 const std::string fakeInfraIf = "wlx123";
91
92 // Utilize the Netif module to create a network interface as the fake infrastructure interface.
93 otbr::Netif::Dependencies defaultNetifDep;
94 otbr::Netif netif(defaultNetifDep);
95 EXPECT_EQ(netif.Init(fakeInfraIf), OTBR_ERROR_NONE);
96
97 const otIp6Address kTestAddr = {
98 {0xfd, 0x35, 0x7a, 0x7d, 0x0f, 0x16, 0xe7, 0xe3, 0x73, 0xf3, 0x09, 0x00, 0x8e, 0xbe, 0x1b, 0x65}};
99 std::vector<otbr::Ip6AddressInfo> addrs = {
100 {kTestAddr, 64, 0, 1, 0},
101 };
102 netif.UpdateIp6UnicastAddresses(addrs);
103
104 InfraIfDependencyTest testInfraIfDep;
105 otbr::InfraIf infraIf(testInfraIfDep);
106 EXPECT_EQ(infraIf.SetInfraIf(fakeInfraIf.c_str()), OTBR_ERROR_NONE);
107
108 EXPECT_NE(testInfraIfDep.mInfraIfIndex, 0);
109 EXPECT_EQ(testInfraIfDep.mIsRunning, false);
110 EXPECT_EQ(testInfraIfDep.mIp6Addresses.size(), 1);
111 EXPECT_THAT(testInfraIfDep.mIp6Addresses, ::testing::Contains(otbr::Ip6Address(kTestAddr)));
112
113 netif.Deinit();
114 }
115
TEST(InfraIf,DepsUpdateInfraIfStateInvokedCorrectly_AfterInfraIfStateChange)116 TEST(InfraIf, DepsUpdateInfraIfStateInvokedCorrectly_AfterInfraIfStateChange)
117 {
118 const std::string fakeInfraIf = "wlx123";
119 otbr::MainloopContext context;
120
121 // Utilize the Netif module to create a network interface as the fake infrastructure interface.
122 otbr::Netif::Dependencies defaultNetifDep;
123 otbr::Netif netif(defaultNetifDep);
124 EXPECT_EQ(netif.Init(fakeInfraIf), OTBR_ERROR_NONE);
125
126 const otIp6Address kTestAddr1 = {
127 {0xfd, 0x35, 0x7a, 0x7d, 0x0f, 0x16, 0xe7, 0xe3, 0x73, 0xf3, 0x09, 0x00, 0x8e, 0xbe, 0x1b, 0x65}};
128 const otIp6Address kTestAddr2 = {
129 {0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0xa5, 0x42, 0xb7, 0x91, 0x80, 0xc3, 0xf8}};
130 std::vector<otbr::Ip6AddressInfo> addrs = {
131 {kTestAddr1, 64, 0, 1, 0},
132 {kTestAddr2, 64, 0, 1, 0},
133 };
134 netif.UpdateIp6UnicastAddresses(addrs);
135
136 InfraIfDependencyTest testInfraIfDep;
137 otbr::InfraIf infraIf(testInfraIfDep);
138 infraIf.Init();
139 EXPECT_EQ(infraIf.SetInfraIf(fakeInfraIf.c_str()), OTBR_ERROR_NONE);
140
141 EXPECT_EQ(testInfraIfDep.mIsRunning, false);
142 EXPECT_EQ(testInfraIfDep.mIp6Addresses.size(), 2);
143
144 netif.SetNetifState(true);
145 testInfraIfDep.mSetInfraIfInvoked = false;
146
147 while (!testInfraIfDep.mSetInfraIfInvoked)
148 {
149 context.mMaxFd = -1;
150 context.mTimeout = {100, 0};
151 FD_ZERO(&context.mReadFdSet);
152 FD_ZERO(&context.mWriteFdSet);
153 FD_ZERO(&context.mErrorFdSet);
154
155 infraIf.UpdateFdSet(context);
156 int rval = select(context.mMaxFd + 1, &context.mReadFdSet, &context.mWriteFdSet, &context.mErrorFdSet,
157 &context.mTimeout);
158 if (rval < 0)
159 {
160 perror("select failed");
161 exit(EXIT_FAILURE);
162 }
163 infraIf.Process(context);
164 }
165 EXPECT_EQ(testInfraIfDep.mIsRunning, true);
166
167 addrs.clear();
168 netif.UpdateIp6UnicastAddresses(addrs);
169 testInfraIfDep.mSetInfraIfInvoked = false;
170 while (!testInfraIfDep.mSetInfraIfInvoked)
171 {
172 context.mMaxFd = -1;
173 context.mTimeout = {100, 0};
174 FD_ZERO(&context.mReadFdSet);
175 FD_ZERO(&context.mWriteFdSet);
176 FD_ZERO(&context.mErrorFdSet);
177
178 infraIf.UpdateFdSet(context);
179 int rval = select(context.mMaxFd + 1, &context.mReadFdSet, &context.mWriteFdSet, &context.mErrorFdSet,
180 &context.mTimeout);
181 if (rval < 0)
182 {
183 perror("select failed");
184 exit(EXIT_FAILURE);
185 }
186 infraIf.Process(context);
187 }
188 EXPECT_EQ(testInfraIfDep.mIp6Addresses.size(), 0);
189 EXPECT_EQ(testInfraIfDep.mIsRunning, false);
190
191 infraIf.Deinit();
192 netif.Deinit();
193 }
194
TEST(InfraIf,DepsHandleIcmp6NdInvokedCorrectly_AfterInfraIfReceivesIcmp6Nd)195 TEST(InfraIf, DepsHandleIcmp6NdInvokedCorrectly_AfterInfraIfReceivesIcmp6Nd)
196 {
197 const std::string fakeInfraIf = "wlx123";
198 otbr::MainloopContext context;
199
200 // Utilize the Netif module to create a network interface as the fake infrastructure interface.
201 otbr::Netif::Dependencies defaultNetifDep;
202 otbr::Netif netif(defaultNetifDep);
203 EXPECT_EQ(netif.Init(fakeInfraIf), OTBR_ERROR_NONE);
204
205 const otIp6Address kLinkLocalAddr = {
206 {0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0xa5, 0x42, 0xb7, 0x91, 0x80, 0xc3, 0xf8}};
207 const otIp6Address kPeerLinkLocalAddr = {
208 {0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xe5, 0x5b, 0xff, 0xfe, 0xc6, 0x8a, 0xf3}};
209 std::vector<otbr::Ip6AddressInfo> addrs = {{kLinkLocalAddr, 64, 0, 1, 0}};
210 netif.UpdateIp6UnicastAddresses(addrs);
211
212 InfraIfDependencyTest testInfraIfDep;
213 otbr::InfraIf infraIf(testInfraIfDep);
214 infraIf.Init();
215 EXPECT_EQ(infraIf.SetInfraIf(fakeInfraIf.c_str()), OTBR_ERROR_NONE);
216 netif.SetNetifState(true);
217
218 // Let the fake infrastructure interface receive a fake Icmp6 Nd message
219 // - Source Address: fe80::dee5:5bff:fec6:8af3
220 const uint8_t kTestMsg[] = {
221 0x60, 0x06, 0xce, 0x11, 0x00, 0x48, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
222 0xde, 0xe5, 0x5b, 0xff, 0xfe, 0xc6, 0x8a, 0xf3, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
223 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x86, 0x00, 0xac, 0xf5, 0x00, 0x00, 0x00, 0x00,
224 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
225 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00,
226 0xfd, 0x38, 0x5f, 0xf4, 0x61, 0x0b, 0x40, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
227 0x18, 0x02, 0x40, 0x00, 0x00, 0x00, 0x07, 0x08, 0xfd, 0x9f, 0x5c, 0xfa, 0x66, 0x3e, 0x00, 0x01,
228 };
229 const uint8_t kTestMsgBodyOffset = 40;
230 const uint16_t kTestMsgBodySize = sizeof(kTestMsg) - kTestMsgBodyOffset;
231 netif.Ip6Receive(kTestMsg, sizeof(kTestMsg));
232
233 while (!testInfraIfDep.mHandleIcmp6NdInvoked)
234 {
235 context.mMaxFd = -1;
236 context.mTimeout = {100, 0};
237 FD_ZERO(&context.mReadFdSet);
238 FD_ZERO(&context.mWriteFdSet);
239 FD_ZERO(&context.mErrorFdSet);
240
241 infraIf.UpdateFdSet(context);
242 int rval = select(context.mMaxFd + 1, &context.mReadFdSet, &context.mWriteFdSet, &context.mErrorFdSet,
243 &context.mTimeout);
244 if (rval < 0)
245 {
246 perror("select failed");
247 exit(EXIT_FAILURE);
248 }
249 infraIf.Process(context);
250 }
251 EXPECT_EQ(testInfraIfDep.mIcmp6NdSrcAddress, otbr::Ip6Address(kPeerLinkLocalAddr));
252 EXPECT_EQ(testInfraIfDep.mIcmp6NdDataLen, kTestMsgBodySize);
253 EXPECT_EQ(memcmp(testInfraIfDep.mIcmp6NdData, kTestMsg + kTestMsgBodyOffset, kTestMsgBodySize), 0);
254
255 infraIf.Deinit();
256 netif.Deinit();
257 }
258 #endif // __linux__
259