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 "simul_utils.h"
30
31 #include <errno.h>
32 #include <ifaddrs.h>
33 #include <net/if.h>
34 #include <sys/time.h>
35
36 #include "lib/platform/exit_code.h"
37 #include "utils/code_utils.h"
38
39 #define ExpectOrExitWithErrorMsg(aCondition, aErrorMsg) \
40 do \
41 { \
42 if (!(aCondition)) \
43 { \
44 perror(aErrorMsg); \
45 otLogWarnPlat("%s: %s", aErrorMsg, strerror(errno)); \
46 goto exit; \
47 } \
48 } while (false)
49
50 #define UTILS_SOCKET_LOCAL_HOST_ADDR "127.0.0.1"
51 #define UTILS_SOCKET_GROUP_ADDR "224.0.0.116"
52 #define UTILS_SOCKET_GROUP_ADDR6 "ff02::116"
53
54 const char *gLocalInterface = UTILS_SOCKET_LOCAL_HOST_ADDR;
55
utilsAddFdToFdSet(int aFd,fd_set * aFdSet,int * aMaxFd)56 void utilsAddFdToFdSet(int aFd, fd_set *aFdSet, int *aMaxFd)
57 {
58 otEXPECT(aFd >= 0);
59 otEXPECT(aFdSet != NULL);
60
61 FD_SET(aFd, aFdSet);
62
63 otEXPECT(aMaxFd != NULL);
64
65 if (*aMaxFd < aFd)
66 {
67 *aMaxFd = aFd;
68 }
69
70 exit:
71 return;
72 }
73
IsAddressLinkLocal(const struct in6_addr * aAddress)74 static bool IsAddressLinkLocal(const struct in6_addr *aAddress)
75 {
76 return ((aAddress->s6_addr[0] & 0xff) == 0xfe) && ((aAddress->s6_addr[1] & 0xc0) == 0x80);
77 }
78
InitRxSocket(utilsSocket * aSocket,const struct in_addr * aIp4Address,unsigned int aIfIndex)79 static void InitRxSocket(utilsSocket *aSocket, const struct in_addr *aIp4Address, unsigned int aIfIndex)
80 {
81 int fd;
82 int one = 1;
83 int rval;
84
85 fd = socket(aIp4Address ? AF_INET : AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
86 ExpectOrExitWithErrorMsg(fd != -1, "socket(RxFd)");
87
88 rval = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
89 ExpectOrExitWithErrorMsg(rval != -1, "setsockopt(RxFd, SO_REUSEADDR)");
90
91 rval = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
92 ExpectOrExitWithErrorMsg(rval != -1, "setsockopt(RxFd, SO_REUSEPORT)");
93
94 if (aIp4Address)
95 {
96 struct ip_mreqn mreq;
97 struct sockaddr_in *sockaddr = &aSocket->mGroupAddr.mSockAddr4;
98
99 rval = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, aIp4Address, sizeof(*aIp4Address));
100 ExpectOrExitWithErrorMsg(rval != -1, "setsockopt(RxFd, IP_MULTICAST_IF)");
101
102 memset(sockaddr, 0, sizeof(*sockaddr));
103 sockaddr->sin_family = AF_INET;
104 sockaddr->sin_port = htons(aSocket->mPortBase);
105 ExpectOrExitWithErrorMsg(inet_pton(AF_INET, UTILS_SOCKET_GROUP_ADDR, &sockaddr->sin_addr),
106 "inet_pton(AF_INET)");
107
108 memset(&mreq, 0, sizeof(mreq));
109 mreq.imr_multiaddr = sockaddr->sin_addr;
110 mreq.imr_address = *aIp4Address; // This address is used to identify the network interface
111
112 rval = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
113 ExpectOrExitWithErrorMsg(rval != -1, "setsockopt(RxFd, IP_ADD_MEMBERSHIP)");
114
115 rval = bind(fd, (struct sockaddr *)sockaddr, sizeof(*sockaddr));
116 ExpectOrExitWithErrorMsg(rval != -1, "bind(RxFd)");
117 }
118 else
119 {
120 struct ipv6_mreq mreq;
121 struct sockaddr_in6 *sockaddr = &aSocket->mGroupAddr.mSockAddr6;
122
123 rval = setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &aIfIndex, sizeof(aIfIndex));
124 ExpectOrExitWithErrorMsg(rval != -1, "setsockopt(RxFd, IPV6_MULTICAST_IF)");
125
126 memset(sockaddr, 0, sizeof(*sockaddr));
127 sockaddr->sin6_family = AF_INET6;
128 sockaddr->sin6_port = htons(aSocket->mPortBase);
129 sockaddr->sin6_scope_id = aIfIndex; // This specifies network interface for link local scope
130 ExpectOrExitWithErrorMsg(inet_pton(AF_INET6, UTILS_SOCKET_GROUP_ADDR6, &sockaddr->sin6_addr),
131 "inet_pton(AF_INET6)");
132
133 memset(&mreq, 0, sizeof(mreq));
134 mreq.ipv6mr_multiaddr = sockaddr->sin6_addr;
135 mreq.ipv6mr_interface = aIfIndex;
136
137 rval = setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
138 ExpectOrExitWithErrorMsg(rval != -1, "setsockopt(RxFd, IPV6_JOIN_GROUP)");
139
140 rval = bind(fd, (struct sockaddr *)sockaddr, sizeof(*sockaddr));
141 ExpectOrExitWithErrorMsg(rval != -1, "bind(RxFd)");
142 }
143
144 aSocket->mRxFd = fd;
145
146 exit:
147 if (aSocket->mRxFd == -1)
148 {
149 DieNow(OT_EXIT_FAILURE);
150 }
151 }
152
InitTxSocketIp6(utilsSocket * aSocket,const struct in6_addr * aAddress,unsigned int aIfIndex)153 void InitTxSocketIp6(utilsSocket *aSocket, const struct in6_addr *aAddress, unsigned int aIfIndex)
154 {
155 int fd;
156 int one = 1;
157 int rval;
158 struct sockaddr_in6 sockaddr;
159
160 fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
161 ExpectOrExitWithErrorMsg(fd != -1, "socket(TxFd)");
162
163 memset(&sockaddr, 0, sizeof(sockaddr));
164 sockaddr.sin6_family = AF_INET6;
165 sockaddr.sin6_addr = *aAddress;
166 sockaddr.sin6_port = htons(aSocket->mPort);
167 if (IsAddressLinkLocal(aAddress))
168 {
169 sockaddr.sin6_scope_id = aIfIndex;
170 }
171
172 rval = setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &aIfIndex, sizeof(aIfIndex));
173 ExpectOrExitWithErrorMsg(rval != -1, "setsockopt(TxFd, IPV6_MULTICAST_IF)");
174
175 rval = setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &one, sizeof(one));
176 ExpectOrExitWithErrorMsg(rval != -1, "setsockopt(TxFd, IPV6_MULTICAST_LOOP)");
177
178 rval = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
179 ExpectOrExitWithErrorMsg(rval != -1, "bind(TxFd)");
180
181 aSocket->mTxFd = fd;
182
183 exit:
184 if (aSocket->mTxFd == -1)
185 {
186 DieNow(OT_EXIT_FAILURE);
187 }
188 }
189
InitTxSocketIp4(utilsSocket * aSocket,const struct in_addr * aAddress)190 static void InitTxSocketIp4(utilsSocket *aSocket, const struct in_addr *aAddress)
191 {
192 int fd;
193 int one = 1;
194 int rval;
195 struct sockaddr_in sockaddr;
196
197 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
198 // Prepare `mTxFd`
199
200 fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
201 ExpectOrExitWithErrorMsg(fd != -1, "socket(TxFd)");
202
203 memset(&sockaddr, 0, sizeof(sockaddr));
204 sockaddr.sin_family = AF_INET;
205 sockaddr.sin_port = htons(aSocket->mPort);
206 sockaddr.sin_addr = *aAddress;
207
208 rval = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &sockaddr.sin_addr, sizeof(sockaddr.sin_addr));
209 ExpectOrExitWithErrorMsg(rval != -1, "setsockopt(TxFd, IP_MULTICAST_IF)");
210
211 rval = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &one, sizeof(one));
212 ExpectOrExitWithErrorMsg(rval != -1, "setsockopt(TxFd, IP_MULTICAST_LOOP)");
213
214 rval = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
215 ExpectOrExitWithErrorMsg(rval != -1, "bind(TxFd)");
216
217 aSocket->mTxFd = fd;
218
219 exit:
220 if (aSocket->mTxFd == -1)
221 {
222 DieNow(OT_EXIT_FAILURE);
223 }
224 }
225
TryInitSocketIfname(utilsSocket * aSocket,const char * aLocalInterface)226 static bool TryInitSocketIfname(utilsSocket *aSocket, const char *aLocalInterface)
227 {
228 const struct in6_addr *addr6 = NULL;
229 const struct in6_addr *addr6ll = NULL;
230 const struct in_addr *addr4 = NULL;
231 struct ifaddrs *ifaddr = NULL;
232 unsigned int ifIndex = 0;
233
234 otEXPECT((ifIndex = if_nametoindex(aLocalInterface)));
235
236 if (getifaddrs(&ifaddr) == -1)
237 {
238 DieNow(OT_EXIT_ERROR_ERRNO);
239 }
240
241 for (struct ifaddrs *ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
242 {
243 if (ifa->ifa_addr == NULL || strcmp(ifa->ifa_name, aLocalInterface) != 0)
244 {
245 continue;
246 }
247
248 if (ifa->ifa_addr->sa_family == AF_INET)
249 {
250 addr4 = &((const struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
251 }
252 else if (ifa->ifa_addr->sa_family == AF_INET6)
253 {
254 addr6 = &((const struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
255 if (IsAddressLinkLocal(addr6))
256 {
257 addr6ll = addr6;
258 }
259 }
260 }
261
262 // Prefer
263 // 1. IPv6 link local address
264 // 2. IPv4 addresses
265 // 3. IPv6 addresses
266 if (addr6ll)
267 {
268 InitTxSocketIp6(aSocket, addr6ll, ifIndex);
269 addr6 = addr6ll;
270 }
271 else if (addr4)
272 {
273 InitTxSocketIp4(aSocket, addr4);
274 addr6 = NULL;
275 }
276 else if (addr6)
277 {
278 InitTxSocketIp6(aSocket, addr6, ifIndex);
279 }
280 else
281 {
282 fprintf(stderr, "No sock address for TX socket!\n");
283 DieNow(OT_EXIT_FAILURE);
284 }
285
286 InitRxSocket(aSocket, (addr6 ? NULL : addr4), ifIndex);
287 aSocket->mInitialized = true;
288 aSocket->mUseIp6 = (addr6 != NULL);
289
290 exit:
291 freeifaddrs(ifaddr);
292 return aSocket->mInitialized;
293 }
294
TryInitSocketIp4(utilsSocket * aSocket,const char * aLocalInterface)295 static bool TryInitSocketIp4(utilsSocket *aSocket, const char *aLocalInterface)
296 {
297 struct in_addr addr4;
298
299 ExpectOrExitWithErrorMsg(inet_pton(AF_INET, aLocalInterface, &addr4), "inet_pton(AF_INET)");
300
301 InitTxSocketIp4(aSocket, &addr4);
302 InitRxSocket(aSocket, &addr4, 0);
303 aSocket->mInitialized = true;
304 aSocket->mUseIp6 = false;
305
306 exit:
307 return aSocket->mInitialized;
308 }
309
TryInitSocketIp6(utilsSocket * aSocket,const char * aLocalInterface)310 static bool TryInitSocketIp6(utilsSocket *aSocket, const char *aLocalInterface)
311 {
312 struct in6_addr addr6;
313 struct ifaddrs *ifaddr = NULL;
314
315 ExpectOrExitWithErrorMsg(inet_pton(AF_INET6, aLocalInterface, &addr6), "inet_pton(AF_INET6)");
316
317 if (getifaddrs(&ifaddr) == -1)
318 {
319 perror("getifaddrs");
320 DieNow(OT_EXIT_ERROR_ERRNO);
321 }
322
323 for (struct ifaddrs *ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
324 {
325 const struct sockaddr_in6 *sockaddr6;
326 unsigned int ifIndex;
327
328 if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET6)
329 {
330 continue;
331 }
332
333 sockaddr6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
334 if (memcmp(&sockaddr6->sin6_addr, &addr6, sizeof(addr6)))
335 {
336 continue;
337 }
338
339 ifIndex = if_nametoindex(ifa->ifa_name);
340 if (ifIndex == 0)
341 {
342 perror("if_nametoindex");
343 DieNow(OT_EXIT_ERROR_ERRNO);
344 }
345
346 InitTxSocketIp6(aSocket, &addr6, ifIndex);
347 InitRxSocket(aSocket, NULL, ifIndex);
348 aSocket->mInitialized = true;
349 aSocket->mUseIp6 = true;
350 break;
351 }
352
353 exit:
354 freeifaddrs(ifaddr);
355 return aSocket->mInitialized;
356 }
357
utilsInitSocket(utilsSocket * aSocket,uint16_t aPortBase)358 void utilsInitSocket(utilsSocket *aSocket, uint16_t aPortBase)
359 {
360 aSocket->mInitialized = false;
361 aSocket->mPortBase = aPortBase;
362 aSocket->mTxFd = -1;
363 aSocket->mRxFd = -1;
364 aSocket->mPort = (uint16_t)(aSocket->mPortBase + gNodeId);
365
366 if (!TryInitSocketIfname(aSocket, gLocalInterface) && !TryInitSocketIp4(aSocket, gLocalInterface) &&
367 !TryInitSocketIp6(aSocket, gLocalInterface))
368 {
369 fprintf(stderr, "Failed to simulate node %d on %s\n", gNodeId, gLocalInterface);
370 DieNow(OT_EXIT_FAILURE);
371 }
372 }
373
utilsDeinitSocket(utilsSocket * aSocket)374 void utilsDeinitSocket(utilsSocket *aSocket)
375 {
376 if (aSocket->mInitialized)
377 {
378 close(aSocket->mRxFd);
379 close(aSocket->mTxFd);
380 aSocket->mInitialized = false;
381 }
382 }
383
utilsAddSocketRxFd(const utilsSocket * aSocket,fd_set * aFdSet,int * aMaxFd)384 void utilsAddSocketRxFd(const utilsSocket *aSocket, fd_set *aFdSet, int *aMaxFd)
385 {
386 otEXPECT(aSocket->mInitialized);
387 utilsAddFdToFdSet(aSocket->mRxFd, aFdSet, aMaxFd);
388
389 exit:
390 return;
391 }
392
utilsAddSocketTxFd(const utilsSocket * aSocket,fd_set * aFdSet,int * aMaxFd)393 void utilsAddSocketTxFd(const utilsSocket *aSocket, fd_set *aFdSet, int *aMaxFd)
394 {
395 otEXPECT(aSocket->mInitialized);
396 utilsAddFdToFdSet(aSocket->mTxFd, aFdSet, aMaxFd);
397
398 exit:
399 return;
400 }
401
utilsCanSocketReceive(const utilsSocket * aSocket,const fd_set * aReadFdSet)402 bool utilsCanSocketReceive(const utilsSocket *aSocket, const fd_set *aReadFdSet)
403 {
404 return aSocket->mInitialized && FD_ISSET(aSocket->mRxFd, aReadFdSet);
405 }
406
utilsCanSocketSend(const utilsSocket * aSocket,const fd_set * aWriteFdSet)407 bool utilsCanSocketSend(const utilsSocket *aSocket, const fd_set *aWriteFdSet)
408 {
409 return aSocket->mInitialized && FD_ISSET(aSocket->mTxFd, aWriteFdSet);
410 }
411
utilsReceiveFromSocket(const utilsSocket * aSocket,void * aBuffer,uint16_t aBufferSize,uint16_t * aSenderNodeId)412 uint16_t utilsReceiveFromSocket(const utilsSocket *aSocket,
413 void *aBuffer,
414 uint16_t aBufferSize,
415 uint16_t *aSenderNodeId)
416 {
417 ssize_t rval;
418 uint16_t len = 0;
419 union
420 {
421 struct sockaddr_in sockaddr4;
422 struct sockaddr_in6 sockaddr6;
423 } sockaddr;
424 socklen_t socklen = aSocket->mUseIp6 ? sizeof(sockaddr.sockaddr6) : sizeof(sockaddr.sockaddr4);
425
426 memset(&sockaddr, 0, sizeof(sockaddr));
427
428 rval = recvfrom(aSocket->mRxFd, (char *)aBuffer, aBufferSize, 0, (struct sockaddr *)&sockaddr, &socklen);
429
430 if (rval > 0)
431 {
432 uint16_t senderPort = ntohs(aSocket->mUseIp6 ? sockaddr.sockaddr6.sin6_port : sockaddr.sockaddr4.sin_port);
433
434 if (aSenderNodeId != NULL)
435 {
436 *aSenderNodeId = (uint16_t)(senderPort - aSocket->mPortBase);
437 }
438
439 len = (uint16_t)rval;
440 }
441 else if (rval == 0)
442 {
443 assert(false);
444 }
445 else if (errno != EINTR && errno != EAGAIN)
446 {
447 perror("recvfrom(RxFd)");
448 DieNow(OT_EXIT_ERROR_ERRNO);
449 }
450
451 return len;
452 }
453
utilsSendOverSocket(const utilsSocket * aSocket,const void * aBuffer,uint16_t aBufferLength)454 void utilsSendOverSocket(const utilsSocket *aSocket, const void *aBuffer, uint16_t aBufferLength)
455 {
456 ssize_t rval;
457
458 rval =
459 sendto(aSocket->mTxFd, (const char *)aBuffer, aBufferLength, 0, (const struct sockaddr *)&aSocket->mGroupAddr,
460 (aSocket->mUseIp6 ? sizeof(aSocket->mGroupAddr.mSockAddr6) : sizeof(aSocket->mGroupAddr.mSockAddr4)));
461
462 if (rval < 0)
463 {
464 perror("sendto(sTxFd)");
465 DieNow(OT_EXIT_ERROR_ERRNO);
466 }
467 }
468