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 <arpa/inet.h>
33 #include <cstring>
34 #include <fstream>
35 #include <ifaddrs.h>
36 #include <iostream>
37 #include <net/if.h>
38 #include <netinet/in.h>
39 #include <netinet/ip6.h>
40 #include <netinet/udp.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <string>
45 #include <sys/ioctl.h>
46 #include <sys/select.h>
47 #include <sys/socket.h>
48 #include <sys/types.h>
49 #include <vector>
50
51 #ifdef __linux__
52 #include <linux/if_link.h>
53 #endif
54
55 #include <openthread/ip6.h>
56
57 #include "common/code_utils.hpp"
58 #include "common/mainloop.hpp"
59 #include "common/types.hpp"
60 #include "ncp/posix/netif.hpp"
61 #include "utils/socket_utils.hpp"
62
63 // Only Test on linux platform for now.
64 #ifdef __linux__
65
66 static constexpr size_t kMaxIp6Size = 1280;
67
GetAllIp6Addrs(const char * aInterfaceName)68 std::vector<std::string> GetAllIp6Addrs(const char *aInterfaceName)
69 {
70 struct ifaddrs *ifaddr, *ifa;
71 int family;
72 std::vector<std::string> ip6Addrs;
73
74 if (getifaddrs(&ifaddr) == -1)
75 {
76 perror("getifaddrs");
77 exit(EXIT_FAILURE);
78 }
79
80 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
81 {
82 if (ifa->ifa_addr == NULL)
83 {
84 continue;
85 }
86
87 family = ifa->ifa_addr->sa_family;
88 if (family == AF_INET6 && strcmp(ifa->ifa_name, aInterfaceName) == 0)
89 {
90 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)ifa->ifa_addr;
91 char addrstr[INET6_ADDRSTRLEN];
92 if (inet_ntop(AF_INET6, &(in6->sin6_addr), addrstr, sizeof(addrstr)) == NULL)
93 {
94 perror("inet_ntop");
95 exit(EXIT_FAILURE);
96 }
97
98 ip6Addrs.emplace_back(addrstr);
99 }
100 }
101
102 freeifaddrs(ifaddr);
103
104 return ip6Addrs;
105 }
106
ParseHex(char * aStr,unsigned char * aAddr)107 static int ParseHex(char *aStr, unsigned char *aAddr)
108 {
109 int len = 0;
110
111 while (*aStr)
112 {
113 int tmp;
114 if (aStr[1] == 0)
115 {
116 return -1;
117 }
118 if (sscanf(aStr, "%02x", &tmp) != 1)
119 {
120 return -1;
121 }
122 aAddr[len] = tmp;
123 len++;
124 aStr += 2;
125 }
126
127 return len;
128 }
129
GetAllIp6MulAddrs(const char * aInterfaceName)130 std::vector<std::string> GetAllIp6MulAddrs(const char *aInterfaceName)
131 {
132 const char *kPathIgmp6 = "/proc/net/igmp6";
133 std::string line;
134 std::vector<std::string> ip6MulAddrs;
135
136 std::ifstream file(kPathIgmp6);
137 if (!file.is_open())
138 {
139 perror("Cannot open IGMP6 file");
140 exit(EXIT_FAILURE);
141 }
142
143 while (std::getline(file, line))
144 {
145 char interfaceName[256] = {0};
146 char hexa[256] = {0};
147 int index;
148 int users;
149 unsigned char addr[16];
150
151 sscanf(line.c_str(), "%d%s%s%d", &index, interfaceName, hexa, &users);
152 if (strcmp(interfaceName, aInterfaceName) == 0)
153 {
154 char addrStr[INET6_ADDRSTRLEN];
155 ParseHex(hexa, addr);
156 if (inet_ntop(AF_INET6, addr, addrStr, sizeof(addrStr)) == NULL)
157 {
158 perror("inet_ntop");
159 exit(EXIT_FAILURE);
160 }
161 ip6MulAddrs.emplace_back(addrStr);
162 }
163 }
164
165 file.close();
166
167 return ip6MulAddrs;
168 }
169
Ip6SendEmptyImpl(const uint8_t * aData,uint16_t aLength)170 otbrError Ip6SendEmptyImpl(const uint8_t *aData, uint16_t aLength)
171 {
172 OTBR_UNUSED_VARIABLE(aData);
173 OTBR_UNUSED_VARIABLE(aLength);
174 return OTBR_ERROR_NONE;
175 }
176
TEST(Netif,WpanInitWithFullInterfaceName)177 TEST(Netif, WpanInitWithFullInterfaceName)
178 {
179 const char *wpan = "wpan0";
180 int sockfd;
181 struct ifreq ifr;
182
183 otbr::Netif netif;
184 EXPECT_EQ(netif.Init(wpan, Ip6SendEmptyImpl), OT_ERROR_NONE);
185
186 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
187 if (sockfd < 0)
188 {
189 FAIL() << "Error creating socket: " << std::strerror(errno);
190 }
191
192 memset(&ifr, 0, sizeof(ifr));
193 strncpy(ifr.ifr_name, wpan, IFNAMSIZ - 1);
194
195 EXPECT_GE(ioctl(sockfd, SIOCGIFFLAGS, &ifr), 0) << "'" << wpan << "' not found";
196
197 netif.Deinit();
198 }
199
TEST(Netif,WpanInitWithFormatInterfaceName)200 TEST(Netif, WpanInitWithFormatInterfaceName)
201 {
202 const char *wpan = "tun%d";
203 const char *if_name = "tun0";
204 int sockfd;
205 struct ifreq ifr;
206
207 otbr::Netif netif;
208 EXPECT_EQ(netif.Init(wpan, Ip6SendEmptyImpl), OT_ERROR_NONE);
209
210 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
211 if (sockfd < 0)
212 {
213 FAIL() << "Error creating socket: " << std::strerror(errno);
214 }
215
216 memset(&ifr, 0, sizeof(ifr));
217 strncpy(ifr.ifr_name, if_name, IFNAMSIZ - 1);
218
219 EXPECT_GE(ioctl(sockfd, SIOCGIFFLAGS, &ifr), 0) << "'" << if_name << "' not found";
220
221 netif.Deinit();
222 }
223
TEST(Netif,WpanInitWithEmptyInterfaceName)224 TEST(Netif, WpanInitWithEmptyInterfaceName)
225 {
226 const char *if_name = "wpan0";
227 int sockfd;
228 struct ifreq ifr;
229
230 otbr::Netif netif;
231 EXPECT_EQ(netif.Init("", Ip6SendEmptyImpl), OT_ERROR_NONE);
232
233 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
234 if (sockfd < 0)
235 {
236 FAIL() << "Error creating socket: " << std::strerror(errno);
237 }
238
239 memset(&ifr, 0, sizeof(ifr));
240 strncpy(ifr.ifr_name, if_name, IFNAMSIZ - 1);
241
242 EXPECT_GE(ioctl(sockfd, SIOCGIFFLAGS, &ifr), 0) << "'" << if_name << "' not found";
243
244 netif.Deinit();
245 }
246
TEST(Netif,WpanInitWithInvalidInterfaceName)247 TEST(Netif, WpanInitWithInvalidInterfaceName)
248 {
249 const char *invalid_netif_name = "invalid_netif_name";
250
251 otbr::Netif netif;
252 EXPECT_EQ(netif.Init(invalid_netif_name, Ip6SendEmptyImpl), OTBR_ERROR_INVALID_ARGS);
253 }
254
TEST(Netif,WpanMtuSize)255 TEST(Netif, WpanMtuSize)
256 {
257 const char *wpan = "wpan0";
258 int sockfd;
259 struct ifreq ifr;
260
261 otbr::Netif netif;
262 EXPECT_EQ(netif.Init(wpan, Ip6SendEmptyImpl), OT_ERROR_NONE);
263
264 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
265 if (sockfd < 0)
266 {
267 FAIL() << "Error creating socket: " << std::strerror(errno);
268 }
269
270 memset(&ifr, 0, sizeof(ifr));
271 strncpy(ifr.ifr_name, wpan, IFNAMSIZ - 1);
272 EXPECT_GE(ioctl(sockfd, SIOCGIFMTU, &ifr), 0) << "Error getting MTU for '" << wpan << "': " << std::strerror(errno);
273 EXPECT_EQ(ifr.ifr_mtu, kMaxIp6Size) << "MTU isn't set correctly";
274
275 netif.Deinit();
276 }
277
TEST(Netif,WpanDeinit)278 TEST(Netif, WpanDeinit)
279 {
280 const char *wpan = "wpan0";
281 int sockfd;
282 struct ifreq ifr;
283
284 otbr::Netif netif;
285 EXPECT_EQ(netif.Init(wpan, Ip6SendEmptyImpl), OT_ERROR_NONE);
286
287 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
288 if (sockfd < 0)
289 {
290 FAIL() << "Error creating socket: " << std::strerror(errno);
291 }
292
293 memset(&ifr, 0, sizeof(ifr));
294 strncpy(ifr.ifr_name, wpan, IFNAMSIZ - 1);
295 EXPECT_GE(ioctl(sockfd, SIOCGIFFLAGS, &ifr), 0) << "'" << wpan << "' not found";
296
297 netif.Deinit();
298 EXPECT_LT(ioctl(sockfd, SIOCGIFFLAGS, &ifr), 0) << "'" << wpan << "' isn't shutdown";
299 }
300
TEST(Netif,WpanAddrGenMode)301 TEST(Netif, WpanAddrGenMode)
302 {
303 otbr::Netif netif;
304 EXPECT_EQ(netif.Init("wpan0", Ip6SendEmptyImpl), OT_ERROR_NONE);
305
306 std::fstream file("/proc/sys/net/ipv6/conf/wpan0/addr_gen_mode", std::ios::in);
307 if (!file.is_open())
308 {
309 FAIL() << "wpan0 interface doesn't exist!";
310 }
311 std::string fileContents((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
312
313 EXPECT_EQ(std::stoi(fileContents), IN6_ADDR_GEN_MODE_NONE);
314
315 netif.Deinit();
316 }
317
TEST(Netif,WpanIfHasCorrectUnicastAddresses_AfterUpdatingUnicastAddresses)318 TEST(Netif, WpanIfHasCorrectUnicastAddresses_AfterUpdatingUnicastAddresses)
319 {
320 const char *wpan = "wpan0";
321
322 const otIp6Address kLl = {
323 {0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x14, 0x03, 0x32, 0x4c, 0xc2, 0xf8, 0xd0}};
324 const otIp6Address kMlEid = {
325 {0xfd, 0x0d, 0x07, 0xfc, 0xa1, 0xb9, 0xf0, 0x50, 0x03, 0xf1, 0x47, 0xce, 0x85, 0xd3, 0x07, 0x7f}};
326 const otIp6Address kMlRloc = {
327 {0xfd, 0x0d, 0x07, 0xfc, 0xa1, 0xb9, 0xf0, 0x50, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0xb8, 0x00}};
328 const otIp6Address kMlAloc = {
329 {0xfd, 0x0d, 0x07, 0xfc, 0xa1, 0xb9, 0xf0, 0x50, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0xfc, 0x00}};
330
331 const char *kLlStr = "fe80::8014:332:4cc2:f8d0";
332 const char *kMlEidStr = "fd0d:7fc:a1b9:f050:3f1:47ce:85d3:77f";
333 const char *kMlRlocStr = "fd0d:7fc:a1b9:f050:0:ff:fe00:b800";
334 const char *kMlAlocStr = "fd0d:7fc:a1b9:f050:0:ff:fe00:fc00";
335
336 otbr::Netif netif;
337 EXPECT_EQ(netif.Init(wpan, Ip6SendEmptyImpl), OT_ERROR_NONE);
338
339 otbr::Ip6AddressInfo testArray1[] = {
340 {kLl, 64, 0, 1, 0},
341 {kMlEid, 64, 0, 1, 1},
342 {kMlRloc, 64, 0, 1, 1},
343 };
344 std::vector<otbr::Ip6AddressInfo> testVec1(testArray1,
345 testArray1 + sizeof(testArray1) / sizeof(otbr::Ip6AddressInfo));
346 netif.UpdateIp6UnicastAddresses(testVec1);
347 std::vector<std::string> wpan_addrs = GetAllIp6Addrs(wpan);
348 EXPECT_EQ(wpan_addrs.size(), 3);
349 EXPECT_THAT(wpan_addrs, ::testing::Contains(kLlStr));
350 EXPECT_THAT(wpan_addrs, ::testing::Contains(kMlEidStr));
351 EXPECT_THAT(wpan_addrs, ::testing::Contains(kMlRlocStr));
352
353 otbr::Ip6AddressInfo testArray2[] = {
354 {kLl, 64, 0, 1, 0},
355 {kMlEid, 64, 0, 1, 1},
356 {kMlRloc, 64, 0, 1, 1},
357 {kMlAloc, 64, 0, 1, 1},
358 };
359 std::vector<otbr::Ip6AddressInfo> testVec2(testArray2,
360 testArray2 + sizeof(testArray2) / sizeof(otbr::Ip6AddressInfo));
361 netif.UpdateIp6UnicastAddresses(testVec2);
362 wpan_addrs = GetAllIp6Addrs(wpan);
363 EXPECT_EQ(wpan_addrs.size(), 4);
364 EXPECT_THAT(wpan_addrs, ::testing::Contains(kLlStr));
365 EXPECT_THAT(wpan_addrs, ::testing::Contains(kMlEidStr));
366 EXPECT_THAT(wpan_addrs, ::testing::Contains(kMlRlocStr));
367 EXPECT_THAT(wpan_addrs, ::testing::Contains(kMlAlocStr));
368
369 std::vector<otbr::Ip6AddressInfo> testVec3;
370 netif.UpdateIp6UnicastAddresses(testVec3);
371 wpan_addrs = GetAllIp6Addrs(wpan);
372 EXPECT_EQ(wpan_addrs.size(), 0);
373
374 netif.Deinit();
375 }
376
TEST(Netif,WpanIfHasCorrectMulticastAddresses_AfterUpdatingMulticastAddresses)377 TEST(Netif, WpanIfHasCorrectMulticastAddresses_AfterUpdatingMulticastAddresses)
378 {
379 const char *wpan = "wpan0";
380 otbr::Netif netif;
381 EXPECT_EQ(netif.Init(wpan, Ip6SendEmptyImpl), OT_ERROR_NONE);
382
383 otbr::Ip6Address kDefaultMulAddr1 = {
384 {0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}};
385 const char *kDefaultMulAddr1Str = "ff01::1";
386 const char *kDefaultMulAddr2Str = "ff02::1";
387 const char *kDefaultMulAddr3Str = "ff02::2";
388
389 otbr::Ip6Address kMulAddr1 = {
390 {0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc}};
391 otbr::Ip6Address kMulAddr2 = {
392 {0xff, 0x32, 0x00, 0x40, 0xfd, 0x0d, 0x07, 0xfc, 0xa1, 0xb9, 0xf0, 0x50, 0x00, 0x00, 0x00, 0x01}};
393 const char *kMulAddr1Str = "ff03::fc";
394 const char *kMulAddr2Str = "ff32:40:fd0d:7fc:a1b9:f050:0:1";
395
396 otbr::Ip6Address testArray1[] = {
397 kMulAddr1,
398 };
399 std::vector<otbr::Ip6Address> testVec1(testArray1, testArray1 + sizeof(testArray1) / sizeof(otbr::Ip6Address));
400 netif.UpdateIp6MulticastAddresses(testVec1);
401 std::vector<std::string> wpanMulAddrs = GetAllIp6MulAddrs(wpan);
402 EXPECT_EQ(wpanMulAddrs.size(), 4);
403 EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kMulAddr1Str));
404 EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr1Str));
405 EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr2Str));
406 EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr3Str));
407
408 otbr::Ip6Address testArray2[] = {kMulAddr1, kMulAddr2};
409 std::vector<otbr::Ip6Address> testVec2(testArray2, testArray2 + sizeof(testArray2) / sizeof(otbr::Ip6Address));
410 netif.UpdateIp6MulticastAddresses(testVec2);
411 wpanMulAddrs = GetAllIp6MulAddrs(wpan);
412 EXPECT_EQ(wpanMulAddrs.size(), 5);
413 EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kMulAddr1Str));
414 EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kMulAddr2Str));
415 EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr1Str));
416 EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr2Str));
417 EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr3Str));
418
419 otbr::Ip6Address testArray3[] = {kDefaultMulAddr1};
420 std::vector<otbr::Ip6Address> testVec3(testArray3, testArray3 + sizeof(testArray3) / sizeof(otbr::Ip6Address));
421 netif.UpdateIp6MulticastAddresses(testVec3);
422 wpanMulAddrs = GetAllIp6MulAddrs(wpan);
423 EXPECT_EQ(wpanMulAddrs.size(), 3);
424 EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr1Str));
425 EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr2Str));
426 EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr3Str));
427
428 std::vector<otbr::Ip6Address> empty;
429 netif.UpdateIp6MulticastAddresses(empty);
430 wpanMulAddrs = GetAllIp6MulAddrs(wpan);
431 EXPECT_EQ(wpanMulAddrs.size(), 3);
432 EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr1Str));
433 EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr2Str));
434 EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr3Str));
435
436 netif.Deinit();
437 }
438
TEST(Netif,WpanIfStateChangesCorrectly_AfterSettingNetifState)439 TEST(Netif, WpanIfStateChangesCorrectly_AfterSettingNetifState)
440 {
441 otbr::Netif netif;
442 const char *wpan = "wpan0";
443 EXPECT_EQ(netif.Init(wpan, Ip6SendEmptyImpl), OTBR_ERROR_NONE);
444
445 int fd = SocketWithCloseExec(AF_INET6, SOCK_DGRAM, IPPROTO_IP, kSocketNonBlock);
446 if (fd < 0)
447 {
448 perror("Failed to create test socket");
449 exit(EXIT_FAILURE);
450 }
451
452 struct ifreq ifr;
453 memset(&ifr, 0, sizeof(ifr));
454 strncpy(ifr.ifr_name, wpan, IFNAMSIZ - 1);
455
456 netif.SetNetifState(true);
457 ioctl(fd, SIOCGIFFLAGS, &ifr);
458 EXPECT_EQ(ifr.ifr_flags & IFF_UP, IFF_UP);
459
460 netif.SetNetifState(false);
461 ioctl(fd, SIOCGIFFLAGS, &ifr);
462 EXPECT_EQ(ifr.ifr_flags & IFF_UP, 0);
463
464 netif.Deinit();
465 }
466
TEST(Netif,WpanIfRecvIp6PacketCorrectly_AfterReceivingFromNetif)467 TEST(Netif, WpanIfRecvIp6PacketCorrectly_AfterReceivingFromNetif)
468 {
469 otbr::Netif netif;
470 EXPECT_EQ(netif.Init("wpan0", Ip6SendEmptyImpl), OTBR_ERROR_NONE);
471
472 const otIp6Address kOmr = {
473 {0xfd, 0x2a, 0xc3, 0x0c, 0x87, 0xd3, 0x00, 0x01, 0xed, 0x1c, 0x0c, 0x91, 0xcc, 0xb6, 0x57, 0x8b}};
474 std::vector<otbr::Ip6AddressInfo> addrs = {
475 {kOmr, 64, 0, 1, 0},
476 };
477 netif.UpdateIp6UnicastAddresses(addrs);
478 netif.SetNetifState(true);
479
480 // Receive UDP packets on wpan address with specified port.
481 int sockFd;
482 const uint16_t port = 12345;
483 struct sockaddr_in6 listenAddr;
484 const char *listenIp = "fd2a:c30c:87d3:1:ed1c:c91:ccb6:578b";
485 uint8_t recvBuf[kMaxIp6Size];
486
487 if ((sockFd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
488 {
489 perror("socket creation failed");
490 exit(EXIT_FAILURE);
491 }
492
493 memset(&listenAddr, 0, sizeof(listenAddr));
494 listenAddr.sin6_family = AF_INET6;
495 listenAddr.sin6_port = htons(port);
496 inet_pton(AF_INET6, listenIp, &(listenAddr.sin6_addr));
497
498 if (bind(sockFd, (const struct sockaddr *)&listenAddr, sizeof(listenAddr)) < 0)
499 {
500 perror("bind failed");
501 exit(EXIT_FAILURE);
502 }
503
504 // Udp Packet
505 // Ip6 source: fd2a:c30c:87d3:1:ed1c:c91:ccb6:578a
506 // Ip6 destination: fd2a:c30c:87d3:1:ed1c:c91:ccb6:578b
507 // Udp destination port: 12345
508 // Udp payload: "Hello Otbr Netif!"
509 const uint8_t udpPacket[] = {0x60, 0x0e, 0xea, 0x69, 0x00, 0x19, 0x11, 0x40, 0xfd, 0x2a, 0xc3, 0x0c, 0x87,
510 0xd3, 0x00, 0x01, 0xed, 0x1c, 0x0c, 0x91, 0xcc, 0xb6, 0x57, 0x8a, 0xfd, 0x2a,
511 0xc3, 0x0c, 0x87, 0xd3, 0x00, 0x01, 0xed, 0x1c, 0x0c, 0x91, 0xcc, 0xb6, 0x57,
512 0x8b, 0xe7, 0x08, 0x30, 0x39, 0x00, 0x19, 0x36, 0x81, 0x48, 0x65, 0x6c, 0x6c,
513 0x6f, 0x20, 0x4f, 0x74, 0x62, 0x72, 0x20, 0x4e, 0x65, 0x74, 0x69, 0x66, 0x21};
514 netif.Ip6Receive(udpPacket, sizeof(udpPacket));
515
516 socklen_t len = sizeof(listenAddr);
517 int n = recvfrom(sockFd, (char *)recvBuf, kMaxIp6Size, MSG_WAITALL, (struct sockaddr *)&listenAddr, &len);
518 std::string udpPayload(reinterpret_cast<const char *>(recvBuf), n);
519 EXPECT_EQ(udpPayload, "Hello Otbr Netif!");
520
521 close(sockFd);
522 netif.Deinit();
523 }
524
TEST(Netif,WpanIfSendIp6PacketCorrectly_AfterReceivingOnIf)525 TEST(Netif, WpanIfSendIp6PacketCorrectly_AfterReceivingOnIf)
526 {
527 bool received = false;
528 std::string receivedPayload;
529 const char *hello = "Hello Otbr Netif!";
530
531 auto Ip6SendTestImpl = [&received, &receivedPayload](const uint8_t *aData, uint16_t aLength) {
532 const ip6_hdr *ipv6_header = reinterpret_cast<const ip6_hdr *>(aData);
533 if (ipv6_header->ip6_nxt == IPPROTO_UDP)
534 {
535 const uint8_t *udpPayload = aData + aLength - ntohs(ipv6_header->ip6_plen) + sizeof(udphdr);
536 uint16_t udpPayloadLen = ntohs(ipv6_header->ip6_plen) - sizeof(udphdr);
537 receivedPayload = std::string(reinterpret_cast<const char *>(udpPayload), udpPayloadLen);
538
539 received = true;
540 }
541
542 return OTBR_ERROR_NONE;
543 };
544
545 otbr::Netif netif;
546 EXPECT_EQ(netif.Init("wpan0", Ip6SendTestImpl), OT_ERROR_NONE);
547
548 // OMR Prefix: fd76:a5d1:fcb0:1707::/64
549 const otIp6Address kOmr = {
550 {0xfd, 0x76, 0xa5, 0xd1, 0xfc, 0xb0, 0x17, 0x07, 0xf3, 0xc7, 0xd8, 0x8c, 0xef, 0xd1, 0x24, 0xa9}};
551 std::vector<otbr::Ip6AddressInfo> addrs = {
552 {kOmr, 64, 0, 1, 0},
553 };
554 netif.UpdateIp6UnicastAddresses(addrs);
555 netif.SetNetifState(true);
556
557 // Send a UDP packet destined to an address with OMR prefix.
558 {
559 int sockFd;
560 const uint16_t destPort = 12345;
561 struct sockaddr_in6 destAddr;
562 const char *destIp = "fd76:a5d1:fcb0:1707:3f1:47ce:85d3:77f";
563
564 if ((sockFd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
565 {
566 perror("socket creation failed");
567 exit(EXIT_FAILURE);
568 }
569
570 memset(&destAddr, 0, sizeof(destAddr));
571 destAddr.sin6_family = AF_INET6;
572 destAddr.sin6_port = htons(destPort);
573 inet_pton(AF_INET6, destIp, &(destAddr.sin6_addr));
574
575 if (sendto(sockFd, hello, strlen(hello), MSG_CONFIRM, (const struct sockaddr *)&destAddr, sizeof(destAddr)) < 0)
576 {
577 FAIL() << "Failed to send UDP packet through WPAN interface";
578 }
579 close(sockFd);
580 }
581
582 otbr::MainloopContext context;
583 while (!received)
584 {
585 context.mMaxFd = -1;
586 context.mTimeout = {100, 0};
587 FD_ZERO(&context.mReadFdSet);
588 FD_ZERO(&context.mWriteFdSet);
589 FD_ZERO(&context.mErrorFdSet);
590
591 netif.UpdateFdSet(&context);
592 int rval = select(context.mMaxFd + 1, &context.mReadFdSet, &context.mWriteFdSet, &context.mErrorFdSet,
593 &context.mTimeout);
594 if (rval < 0)
595 {
596 perror("select failed");
597 exit(EXIT_FAILURE);
598 }
599 netif.Process(&context);
600 }
601
602 EXPECT_STREQ(receivedPayload.c_str(), hello);
603
604 netif.Deinit();
605 }
606 #endif // __linux__
607