• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2019-21, 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 "platform-simulation.h"
30 
31 #include <openthread/random_noncrypto.h>
32 #include <openthread/platform/trel.h>
33 
34 #include "utils/code_utils.h"
35 
36 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
37 
38 // Change DEBUG_LOG to all extra logging
39 #define DEBUG_LOG 0
40 
41 // The IPv4 group for receiving
42 #define TREL_SIM_GROUP "224.0.0.116"
43 #define TREL_SIM_PORT 9200
44 
45 #define TREL_MAX_PACKET_SIZE 1800
46 
47 #define TREL_MAX_PENDING_TX 64
48 
49 #define TREL_MAX_SERVICE_TXT_DATA_LEN 128
50 
51 typedef enum MessageType
52 {
53     TREL_DATA_MESSAGE,
54     TREL_DNSSD_BROWSE_MESSAGE,
55     TREL_DNSSD_ADD_SERVICE_MESSAGE,
56     TREL_DNSSD_REMOVE_SERVICE_MESSAGE,
57 } MessageType;
58 
59 typedef struct Message
60 {
61     MessageType mType;
62     otSockAddr  mSockAddr;                   // Destination (when TREL_DATA_MESSAGE), or peer addr (when DNS-SD service)
63     uint16_t    mDataLength;                 // mData length
64     uint8_t     mData[TREL_MAX_PACKET_SIZE]; // TREL UDP packet (when TREL_DATA_MESSAGE), or service TXT data.
65 } Message;
66 
67 static uint8_t sNumPendingTx = 0;
68 static Message sPendingTx[TREL_MAX_PENDING_TX];
69 
70 static int      sTxFd       = -1;
71 static int      sRxFd       = -1;
72 static uint16_t sPortOffset = 0;
73 static bool     sEnabled    = false;
74 static uint16_t sUdpPort;
75 
76 static bool     sServiceRegistered = false;
77 static uint16_t sServicePort;
78 static uint8_t  sServiceTxtLength;
79 static char     sServiceTxtData[TREL_MAX_SERVICE_TXT_DATA_LEN];
80 
81 #if DEBUG_LOG
dumpBuffer(const void * aBuffer,uint16_t aLength)82 static void dumpBuffer(const void *aBuffer, uint16_t aLength)
83 {
84     const uint8_t *buffer = (const uint8_t *)aBuffer;
85     fprintf(stderr, "[ (len:%d) ", aLength);
86 
87     while (aLength--)
88     {
89         fprintf(stderr, "%02x ", *buffer++);
90     }
91 
92     fprintf(stderr, "]");
93 }
94 
messageTypeToString(MessageType aType)95 static const char *messageTypeToString(MessageType aType)
96 {
97     const char *str = "unknown";
98 
99     switch (aType)
100     {
101     case TREL_DATA_MESSAGE:
102         str = "data";
103         break;
104     case TREL_DNSSD_BROWSE_MESSAGE:
105         str = "browse";
106         break;
107     case TREL_DNSSD_ADD_SERVICE_MESSAGE:
108         str = "add-service";
109         break;
110     case TREL_DNSSD_REMOVE_SERVICE_MESSAGE:
111         str = "remove-service";
112         break;
113     }
114 
115     return str;
116 }
117 #endif
118 
initFds(void)119 static void initFds(void)
120 {
121     int                fd;
122     int                one = 1;
123     struct sockaddr_in sockaddr;
124     struct ip_mreqn    mreq;
125 
126     memset(&sockaddr, 0, sizeof(sockaddr));
127 
128     otEXPECT_ACTION((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1, perror("socket(sTxFd)"));
129 
130     sUdpPort                 = (uint16_t)(TREL_SIM_PORT + sPortOffset + gNodeId);
131     sockaddr.sin_family      = AF_INET;
132     sockaddr.sin_port        = htons(sUdpPort);
133     sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
134 
135     otEXPECT_ACTION(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &sockaddr.sin_addr, sizeof(sockaddr.sin_addr)) != -1,
136                     perror("setsockopt(sTxFd, IP_MULTICAST_IF)"));
137 
138     otEXPECT_ACTION(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &one, sizeof(one)) != -1,
139                     perror("setsockopt(sTxFd, IP_MULTICAST_LOOP)"));
140 
141     otEXPECT_ACTION(bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != -1, perror("bind(sTxFd)"));
142 
143     // Tx fd is successfully initialized.
144     sTxFd = fd;
145 
146     otEXPECT_ACTION((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1, perror("socket(sRxFd)"));
147 
148     otEXPECT_ACTION(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) != -1,
149                     perror("setsockopt(sRxFd, SO_REUSEADDR)"));
150     otEXPECT_ACTION(setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) != -1,
151                     perror("setsockopt(sRxFd, SO_REUSEPORT)"));
152 
153     memset(&mreq, 0, sizeof(mreq));
154     inet_pton(AF_INET, TREL_SIM_GROUP, &mreq.imr_multiaddr);
155 
156     // Always use loopback device to send simulation packets.
157     mreq.imr_address.s_addr = inet_addr("127.0.0.1");
158 
159     otEXPECT_ACTION(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &mreq.imr_address, sizeof(mreq.imr_address)) != -1,
160                     perror("setsockopt(sRxFd, IP_MULTICAST_IF)"));
161     otEXPECT_ACTION(setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) != -1,
162                     perror("setsockopt(sRxFd, IP_ADD_MEMBERSHIP)"));
163 
164     sockaddr.sin_family      = AF_INET;
165     sockaddr.sin_port        = htons((uint16_t)(TREL_SIM_PORT + sPortOffset));
166     sockaddr.sin_addr.s_addr = inet_addr(TREL_SIM_GROUP);
167 
168     otEXPECT_ACTION(bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != -1, perror("bind(sRxFd)"));
169 
170     // Rx fd is successfully initialized.
171     sRxFd = fd;
172 
173 exit:
174     if (sRxFd == -1 || sTxFd == -1)
175     {
176         exit(EXIT_FAILURE);
177     }
178 }
179 
deinitFds(void)180 static void deinitFds(void)
181 {
182     if (sRxFd != -1)
183     {
184         close(sRxFd);
185     }
186 
187     if (sTxFd != -1)
188     {
189         close(sTxFd);
190     }
191 }
192 
getMessageSize(const Message * aMessage)193 static uint16_t getMessageSize(const Message *aMessage)
194 {
195     return (uint16_t)(&aMessage->mData[aMessage->mDataLength] - (const uint8_t *)aMessage);
196 }
197 
sendPendingTxMessages(void)198 static void sendPendingTxMessages(void)
199 {
200     ssize_t            rval;
201     struct sockaddr_in sockaddr;
202 
203     memset(&sockaddr, 0, sizeof(sockaddr));
204     sockaddr.sin_family = AF_INET;
205     inet_pton(AF_INET, TREL_SIM_GROUP, &sockaddr.sin_addr);
206 
207     sockaddr.sin_port = htons((uint16_t)(TREL_SIM_PORT + sPortOffset));
208 
209     for (uint8_t i = 0; i < sNumPendingTx; i++)
210     {
211         uint16_t size = getMessageSize(&sPendingTx[i]);
212 
213 #if DEBUG_LOG
214         fprintf(stderr, "\r\n[trel-sim] Sending message (num:%d, type:%s, port:%u)\r\n", i,
215                 messageTypeToString(sPendingTx[i].mType), sPendingTx[i].mSockAddr.mPort);
216 #endif
217 
218         rval = sendto(sTxFd, &sPendingTx[i], size, 0, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
219 
220         if (rval < 0)
221         {
222             perror("sendto(sTxFd)");
223             exit(EXIT_FAILURE);
224         }
225     }
226 
227     sNumPendingTx = 0;
228 }
229 
sendBrowseMessage(void)230 static void sendBrowseMessage(void)
231 {
232     Message *message;
233 
234     assert(sNumPendingTx < TREL_MAX_PENDING_TX);
235     message = &sPendingTx[sNumPendingTx++];
236 
237     message->mType       = TREL_DNSSD_BROWSE_MESSAGE;
238     message->mDataLength = 0;
239 
240 #if DEBUG_LOG
241     fprintf(stderr, "\r\n[trel-sim] sendBrowseMessage()\r\n");
242 #endif
243 }
244 
sendServiceMessage(MessageType aType)245 static void sendServiceMessage(MessageType aType)
246 {
247     Message *message;
248 
249     assert((aType == TREL_DNSSD_ADD_SERVICE_MESSAGE) || (aType == TREL_DNSSD_REMOVE_SERVICE_MESSAGE));
250 
251     assert(sNumPendingTx < TREL_MAX_PENDING_TX);
252     message = &sPendingTx[sNumPendingTx++];
253 
254     message->mType = aType;
255     memset(&message->mSockAddr, 0, sizeof(otSockAddr));
256     message->mSockAddr.mPort = sServicePort;
257     message->mDataLength     = sServiceTxtLength;
258     memcpy(message->mData, sServiceTxtData, sServiceTxtLength);
259 
260 #if DEBUG_LOG
261     fprintf(stderr, "\r\n[trel-sim] sendServiceMessage(%s): service-port:%u, txt-len:%u\r\n",
262             aType == TREL_DNSSD_ADD_SERVICE_MESSAGE ? "add" : "remove", sServicePort, sServiceTxtLength);
263 #endif
264 }
265 
processMessage(otInstance * aInstance,Message * aMessage,uint16_t aLength)266 static void processMessage(otInstance *aInstance, Message *aMessage, uint16_t aLength)
267 {
268     otPlatTrelPeerInfo peerInfo;
269 
270 #if DEBUG_LOG
271     fprintf(stderr, "\r\n[trel-sim] processMessage(len:%u, type:%s, port:%u)\r\n", aLength,
272             messageTypeToString(aMessage->mType), aMessage->mSockAddr.mPort);
273 #endif
274 
275     otEXPECT(aLength > 0);
276     otEXPECT(getMessageSize(aMessage) == aLength);
277 
278     switch (aMessage->mType)
279     {
280     case TREL_DATA_MESSAGE:
281         otEXPECT(aMessage->mSockAddr.mPort == sUdpPort);
282         otPlatTrelHandleReceived(aInstance, aMessage->mData, aMessage->mDataLength);
283         break;
284 
285     case TREL_DNSSD_BROWSE_MESSAGE:
286         sendServiceMessage(TREL_DNSSD_ADD_SERVICE_MESSAGE);
287         break;
288 
289     case TREL_DNSSD_ADD_SERVICE_MESSAGE:
290     case TREL_DNSSD_REMOVE_SERVICE_MESSAGE:
291         memset(&peerInfo, 0, sizeof(peerInfo));
292         peerInfo.mRemoved   = (aMessage->mType == TREL_DNSSD_REMOVE_SERVICE_MESSAGE);
293         peerInfo.mTxtData   = aMessage->mData;
294         peerInfo.mTxtLength = (uint8_t)(aMessage->mDataLength);
295         peerInfo.mSockAddr  = aMessage->mSockAddr;
296         otPlatTrelHandleDiscoveredPeerInfo(aInstance, &peerInfo);
297         break;
298     }
299 
300 exit:
301     return;
302 }
303 
304 //---------------------------------------------------------------------------------------------------------------------
305 // otPlatTrel
306 
otPlatTrelEnable(otInstance * aInstance,uint16_t * aUdpPort)307 void otPlatTrelEnable(otInstance *aInstance, uint16_t *aUdpPort)
308 {
309     OT_UNUSED_VARIABLE(aInstance);
310 
311     *aUdpPort = sUdpPort;
312 
313 #if DEBUG_LOG
314     fprintf(stderr, "\r\n[trel-sim] otPlatTrelEnable() *aUdpPort=%u\r\n", *aUdpPort);
315 #endif
316 
317     if (!sEnabled)
318     {
319         sEnabled = true;
320         sendBrowseMessage();
321     }
322 }
323 
otPlatTrelDisable(otInstance * aInstance)324 void otPlatTrelDisable(otInstance *aInstance)
325 {
326     OT_UNUSED_VARIABLE(aInstance);
327 
328 #if DEBUG_LOG
329     fprintf(stderr, "\r\n[trel-sim] otPlatTrelDisable()\r\n");
330 #endif
331 
332     if (sEnabled)
333     {
334         sEnabled = false;
335 
336         if (sServiceRegistered)
337         {
338             sendServiceMessage(TREL_DNSSD_REMOVE_SERVICE_MESSAGE);
339             sServiceRegistered = false;
340         }
341     }
342 }
343 
otPlatTrelRegisterService(otInstance * aInstance,uint16_t aPort,const uint8_t * aTxtData,uint8_t aTxtLength)344 void otPlatTrelRegisterService(otInstance *aInstance, uint16_t aPort, const uint8_t *aTxtData, uint8_t aTxtLength)
345 {
346     OT_UNUSED_VARIABLE(aInstance);
347 
348     assert(aTxtLength <= TREL_MAX_SERVICE_TXT_DATA_LEN);
349 
350     if (sServiceRegistered)
351     {
352         sendServiceMessage(TREL_DNSSD_REMOVE_SERVICE_MESSAGE);
353     }
354 
355     sServiceRegistered = true;
356     sServicePort       = aPort;
357     sServiceTxtLength  = aTxtLength;
358     memcpy(sServiceTxtData, aTxtData, aTxtLength);
359 
360     sendServiceMessage(TREL_DNSSD_ADD_SERVICE_MESSAGE);
361 
362 #if DEBUG_LOG
363     fprintf(stderr, "\r\n[trel-sim] otPlatTrelRegisterService(aPort:%d, aTxtData:", aPort);
364     dumpBuffer(aTxtData, aTxtLength);
365     fprintf(stderr, ")\r\n");
366 #endif
367 }
368 
otPlatTrelSend(otInstance * aInstance,const uint8_t * aUdpPayload,uint16_t aUdpPayloadLen,const otSockAddr * aDestSockAddr)369 void otPlatTrelSend(otInstance *      aInstance,
370                     const uint8_t *   aUdpPayload,
371                     uint16_t          aUdpPayloadLen,
372                     const otSockAddr *aDestSockAddr)
373 {
374     OT_UNUSED_VARIABLE(aInstance);
375 
376     Message *message;
377 
378     assert(sNumPendingTx < TREL_MAX_PENDING_TX);
379     assert(aUdpPayloadLen <= TREL_MAX_PACKET_SIZE);
380 
381     message = &sPendingTx[sNumPendingTx++];
382 
383     message->mType       = TREL_DATA_MESSAGE;
384     message->mSockAddr   = *aDestSockAddr;
385     message->mDataLength = aUdpPayloadLen;
386     memcpy(message->mData, aUdpPayload, aUdpPayloadLen);
387 
388 #if DEBUG_LOG
389     fprintf(stderr, "\r\n[trel-sim] otPlatTrelSend(len:%u, port:%u)\r\n", aUdpPayloadLen, aDestSockAddr->mPort);
390 #endif
391 }
392 
393 //---------------------------------------------------------------------------------------------------------------------
394 // platformTrel system
395 
platformTrelInit(uint32_t aSpeedUpFactor)396 void platformTrelInit(uint32_t aSpeedUpFactor)
397 {
398     char *str;
399 
400     str = getenv("PORT_OFFSET");
401 
402     if (str != NULL)
403     {
404         char *endptr;
405 
406         sPortOffset = (uint16_t)strtol(str, &endptr, 0);
407 
408         if (*endptr != '\0')
409         {
410             fprintf(stderr, "\r\nInvalid PORT_OFFSET: %s\r\n", str);
411             exit(EXIT_FAILURE);
412         }
413 
414         sPortOffset *= (MAX_NETWORK_SIZE + 1);
415     }
416 
417     initFds();
418 
419     OT_UNUSED_VARIABLE(aSpeedUpFactor);
420 }
421 
platformTrelDeinit(void)422 void platformTrelDeinit(void)
423 {
424     deinitFds();
425 }
426 
platformTrelUpdateFdSet(fd_set * aReadFdSet,fd_set * aWriteFdSet,struct timeval * aTimeout,int * aMaxFd)427 void platformTrelUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, struct timeval *aTimeout, int *aMaxFd)
428 {
429     OT_UNUSED_VARIABLE(aTimeout);
430 
431     // Always ready to receive
432     if (aReadFdSet != NULL)
433     {
434         FD_SET(sRxFd, aReadFdSet);
435 
436         if (aMaxFd != NULL && *aMaxFd < sRxFd)
437         {
438             *aMaxFd = sRxFd;
439         }
440     }
441 
442     if ((aWriteFdSet != NULL) && (sNumPendingTx > 0))
443     {
444         FD_SET(sTxFd, aWriteFdSet);
445 
446         if (aMaxFd != NULL && *aMaxFd < sTxFd)
447         {
448             *aMaxFd = sTxFd;
449         }
450     }
451 }
452 
platformTrelProcess(otInstance * aInstance,const fd_set * aReadFdSet,const fd_set * aWriteFdSet)453 void platformTrelProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet)
454 {
455     if (FD_ISSET(sTxFd, aWriteFdSet) && (sNumPendingTx > 0))
456     {
457         sendPendingTxMessages();
458     }
459 
460     if (FD_ISSET(sRxFd, aReadFdSet))
461     {
462         Message message;
463         ssize_t rval;
464 
465         message.mDataLength = 0;
466 
467         rval = recvfrom(sRxFd, (char *)&message, sizeof(message), 0, NULL, NULL);
468 
469         if (rval < 0)
470         {
471             perror("recvfrom(sRxFd)");
472             exit(EXIT_FAILURE);
473         }
474 
475         processMessage(aInstance, &message, (uint16_t)(rval));
476     }
477 }
478 
479 //---------------------------------------------------------------------------------------------------------------------
480 
481 // This is added for RCP build to be built ok
otPlatTrelHandleReceived(otInstance * aInstance,uint8_t * aBuffer,uint16_t aLength)482 OT_TOOL_WEAK void otPlatTrelHandleReceived(otInstance *aInstance, uint8_t *aBuffer, uint16_t aLength)
483 {
484     OT_UNUSED_VARIABLE(aInstance);
485     OT_UNUSED_VARIABLE(aBuffer);
486     OT_UNUSED_VARIABLE(aLength);
487 
488     assert(false);
489 }
490 
otPlatTrelHandleDiscoveredPeerInfo(otInstance * aInstance,const otPlatTrelPeerInfo * aInfo)491 OT_TOOL_WEAK void otPlatTrelHandleDiscoveredPeerInfo(otInstance *aInstance, const otPlatTrelPeerInfo *aInfo)
492 {
493     OT_UNUSED_VARIABLE(aInstance);
494     OT_UNUSED_VARIABLE(aInfo);
495 
496     assert(false);
497 }
498 
499 #endif // OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
500