• 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 "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