• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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