xref: /aosp_15_r20/external/openthread/examples/platforms/simulation/trel.c (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
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 "simul_utils.h"
35 #include "utils/code_utils.h"
36 
37 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
38 
39 // Change DEBUG_LOG to all extra logging
40 #define DEBUG_LOG 0
41 
42 #define TREL_SIM_PORT 9200
43 
44 #define TREL_MAX_PACKET_SIZE 1800
45 
46 #define TREL_MAX_PENDING_TX 64
47 
48 #define TREL_MAX_SERVICE_TXT_DATA_LEN 128
49 
50 typedef enum MessageType
51 {
52     TREL_DATA_MESSAGE,
53     TREL_DNSSD_BROWSE_MESSAGE,
54     TREL_DNSSD_ADD_SERVICE_MESSAGE,
55     TREL_DNSSD_REMOVE_SERVICE_MESSAGE,
56 } MessageType;
57 
58 typedef struct Message
59 {
60     MessageType mType;
61     otSockAddr  mSockAddr;                   // Destination (when TREL_DATA_MESSAGE), or peer addr (when DNS-SD service)
62     uint16_t    mDataLength;                 // mData length
63     uint8_t     mData[TREL_MAX_PACKET_SIZE]; // TREL UDP packet (when TREL_DATA_MESSAGE), or service TXT data.
64 } Message;
65 
66 static uint8_t sNumPendingTx = 0;
67 static Message sPendingTx[TREL_MAX_PENDING_TX];
68 
69 static utilsSocket sSocket;
70 static uint16_t    sPortOffset = 0;
71 static bool        sEnabled    = false;
72 
73 static bool               sServiceRegistered = false;
74 static uint16_t           sServicePort;
75 static uint8_t            sServiceTxtLength;
76 static char               sServiceTxtData[TREL_MAX_SERVICE_TXT_DATA_LEN];
77 static otPlatTrelCounters sCounters;
78 
79 #if DEBUG_LOG
dumpBuffer(const void * aBuffer,uint16_t aLength)80 static void dumpBuffer(const void *aBuffer, uint16_t aLength)
81 {
82     const uint8_t *buffer = (const uint8_t *)aBuffer;
83     fprintf(stderr, "[ (len:%d) ", aLength);
84 
85     while (aLength--)
86     {
87         fprintf(stderr, "%02x ", *buffer++);
88     }
89 
90     fprintf(stderr, "]");
91 }
92 
messageTypeToString(MessageType aType)93 static const char *messageTypeToString(MessageType aType)
94 {
95     const char *str = "unknown";
96 
97     switch (aType)
98     {
99     case TREL_DATA_MESSAGE:
100         str = "data";
101         break;
102     case TREL_DNSSD_BROWSE_MESSAGE:
103         str = "browse";
104         break;
105     case TREL_DNSSD_ADD_SERVICE_MESSAGE:
106         str = "add-service";
107         break;
108     case TREL_DNSSD_REMOVE_SERVICE_MESSAGE:
109         str = "remove-service";
110         break;
111     }
112 
113     return str;
114 }
115 #endif
116 
getMessageSize(const Message * aMessage)117 static uint16_t getMessageSize(const Message *aMessage)
118 {
119     return (uint16_t)(&aMessage->mData[aMessage->mDataLength] - (const uint8_t *)aMessage);
120 }
121 
sendPendingTxMessages(void)122 static void sendPendingTxMessages(void)
123 {
124     for (uint8_t i = 0; i < sNumPendingTx; i++)
125     {
126 #if DEBUG_LOG
127         fprintf(stderr, "\r\n[trel-sim] Sending message (num:%d, type:%s, port:%u)\r\n", i,
128                 messageTypeToString(sPendingTx[i].mType), sPendingTx[i].mSockAddr.mPort);
129 #endif
130         utilsSendOverSocket(&sSocket, &sPendingTx[i], getMessageSize(&sPendingTx[i]));
131     }
132 
133     sNumPendingTx = 0;
134 }
135 
sendBrowseMessage(void)136 static void sendBrowseMessage(void)
137 {
138     Message *message;
139 
140     assert(sNumPendingTx < TREL_MAX_PENDING_TX);
141     message = &sPendingTx[sNumPendingTx++];
142 
143     message->mType       = TREL_DNSSD_BROWSE_MESSAGE;
144     message->mDataLength = 0;
145 
146 #if DEBUG_LOG
147     fprintf(stderr, "\r\n[trel-sim] sendBrowseMessage()\r\n");
148 #endif
149 }
150 
sendServiceMessage(MessageType aType)151 static void sendServiceMessage(MessageType aType)
152 {
153     Message *message;
154 
155     assert((aType == TREL_DNSSD_ADD_SERVICE_MESSAGE) || (aType == TREL_DNSSD_REMOVE_SERVICE_MESSAGE));
156 
157     assert(sNumPendingTx < TREL_MAX_PENDING_TX);
158     message = &sPendingTx[sNumPendingTx++];
159 
160     message->mType = aType;
161     memset(&message->mSockAddr, 0, sizeof(otSockAddr));
162     message->mSockAddr.mPort = sServicePort;
163     message->mDataLength     = sServiceTxtLength;
164     memcpy(message->mData, sServiceTxtData, sServiceTxtLength);
165 
166 #if DEBUG_LOG
167     fprintf(stderr, "\r\n[trel-sim] sendServiceMessage(%s): service-port:%u, txt-len:%u\r\n",
168             aType == TREL_DNSSD_ADD_SERVICE_MESSAGE ? "add" : "remove", sServicePort, sServiceTxtLength);
169 #endif
170 }
171 
processMessage(otInstance * aInstance,Message * aMessage,uint16_t aLength)172 static void processMessage(otInstance *aInstance, Message *aMessage, uint16_t aLength)
173 {
174     otPlatTrelPeerInfo peerInfo;
175 
176 #if DEBUG_LOG
177     fprintf(stderr, "\r\n[trel-sim] processMessage(len:%u, type:%s, port:%u)\r\n", aLength,
178             messageTypeToString(aMessage->mType), aMessage->mSockAddr.mPort);
179 #endif
180 
181     otEXPECT(aLength > 0);
182     otEXPECT(getMessageSize(aMessage) == aLength);
183 
184     switch (aMessage->mType)
185     {
186     case TREL_DATA_MESSAGE:
187         otEXPECT(aMessage->mSockAddr.mPort == sSocket.mPort);
188         otPlatTrelHandleReceived(aInstance, aMessage->mData, aMessage->mDataLength);
189         break;
190 
191     case TREL_DNSSD_BROWSE_MESSAGE:
192         sendServiceMessage(TREL_DNSSD_ADD_SERVICE_MESSAGE);
193         break;
194 
195     case TREL_DNSSD_ADD_SERVICE_MESSAGE:
196     case TREL_DNSSD_REMOVE_SERVICE_MESSAGE:
197         memset(&peerInfo, 0, sizeof(peerInfo));
198         peerInfo.mRemoved   = (aMessage->mType == TREL_DNSSD_REMOVE_SERVICE_MESSAGE);
199         peerInfo.mTxtData   = aMessage->mData;
200         peerInfo.mTxtLength = (uint8_t)(aMessage->mDataLength);
201         peerInfo.mSockAddr  = aMessage->mSockAddr;
202         otPlatTrelHandleDiscoveredPeerInfo(aInstance, &peerInfo);
203         break;
204     }
205 
206 exit:
207     return;
208 }
209 
210 //---------------------------------------------------------------------------------------------------------------------
211 // otPlatTrel
212 
otPlatTrelEnable(otInstance * aInstance,uint16_t * aUdpPort)213 void otPlatTrelEnable(otInstance *aInstance, uint16_t *aUdpPort)
214 {
215     OT_UNUSED_VARIABLE(aInstance);
216 
217     *aUdpPort = sSocket.mPort;
218 
219 #if DEBUG_LOG
220     fprintf(stderr, "\r\n[trel-sim] otPlatTrelEnable() *aUdpPort=%u\r\n", *aUdpPort);
221 #endif
222 
223     if (!sEnabled)
224     {
225         sEnabled = true;
226         sendBrowseMessage();
227     }
228 }
229 
otPlatTrelDisable(otInstance * aInstance)230 void otPlatTrelDisable(otInstance *aInstance)
231 {
232     OT_UNUSED_VARIABLE(aInstance);
233 
234 #if DEBUG_LOG
235     fprintf(stderr, "\r\n[trel-sim] otPlatTrelDisable()\r\n");
236 #endif
237 
238     if (sEnabled)
239     {
240         sEnabled = false;
241 
242         if (sServiceRegistered)
243         {
244             sendServiceMessage(TREL_DNSSD_REMOVE_SERVICE_MESSAGE);
245             sServiceRegistered = false;
246         }
247     }
248 }
249 
otPlatTrelRegisterService(otInstance * aInstance,uint16_t aPort,const uint8_t * aTxtData,uint8_t aTxtLength)250 void otPlatTrelRegisterService(otInstance *aInstance, uint16_t aPort, const uint8_t *aTxtData, uint8_t aTxtLength)
251 {
252     OT_UNUSED_VARIABLE(aInstance);
253 
254     assert(aTxtLength <= TREL_MAX_SERVICE_TXT_DATA_LEN);
255 
256     if (sServiceRegistered)
257     {
258         sendServiceMessage(TREL_DNSSD_REMOVE_SERVICE_MESSAGE);
259     }
260 
261     sServiceRegistered = true;
262     sServicePort       = aPort;
263     sServiceTxtLength  = aTxtLength;
264     memcpy(sServiceTxtData, aTxtData, aTxtLength);
265 
266     sendServiceMessage(TREL_DNSSD_ADD_SERVICE_MESSAGE);
267 
268 #if DEBUG_LOG
269     fprintf(stderr, "\r\n[trel-sim] otPlatTrelRegisterService(aPort:%d, aTxtData:", aPort);
270     dumpBuffer(aTxtData, aTxtLength);
271     fprintf(stderr, ")\r\n");
272 #endif
273 }
274 
otPlatTrelSend(otInstance * aInstance,const uint8_t * aUdpPayload,uint16_t aUdpPayloadLen,const otSockAddr * aDestSockAddr)275 void otPlatTrelSend(otInstance       *aInstance,
276                     const uint8_t    *aUdpPayload,
277                     uint16_t          aUdpPayloadLen,
278                     const otSockAddr *aDestSockAddr)
279 {
280     OT_UNUSED_VARIABLE(aInstance);
281 
282     Message *message;
283 
284     assert(sNumPendingTx < TREL_MAX_PENDING_TX);
285     assert(aUdpPayloadLen <= TREL_MAX_PACKET_SIZE);
286 
287     message = &sPendingTx[sNumPendingTx++];
288 
289     message->mType       = TREL_DATA_MESSAGE;
290     message->mSockAddr   = *aDestSockAddr;
291     message->mDataLength = aUdpPayloadLen;
292     memcpy(message->mData, aUdpPayload, aUdpPayloadLen);
293 
294 #if DEBUG_LOG
295     fprintf(stderr, "\r\n[trel-sim] otPlatTrelSend(len:%u, port:%u)\r\n", aUdpPayloadLen, aDestSockAddr->mPort);
296 #endif
297     ++sCounters.mTxPackets;
298     sCounters.mTxBytes += aUdpPayloadLen;
299 }
300 
301 //---------------------------------------------------------------------------------------------------------------------
302 // platformTrel system
303 
platformTrelInit(uint32_t aSpeedUpFactor)304 void platformTrelInit(uint32_t aSpeedUpFactor)
305 {
306     char *str;
307 
308     str = getenv("PORT_OFFSET");
309 
310     if (str != NULL)
311     {
312         char *endptr;
313 
314         sPortOffset = (uint16_t)strtol(str, &endptr, 0);
315 
316         if (*endptr != '\0')
317         {
318             fprintf(stderr, "\r\nInvalid PORT_OFFSET: %s\r\n", str);
319             exit(EXIT_FAILURE);
320         }
321 
322         sPortOffset *= (MAX_NETWORK_SIZE + 1);
323     }
324 
325     utilsInitSocket(&sSocket, TREL_SIM_PORT + sPortOffset);
326 
327     OT_UNUSED_VARIABLE(aSpeedUpFactor);
328 }
329 
platformTrelDeinit(void)330 void platformTrelDeinit(void) { utilsDeinitSocket(&sSocket); }
331 
platformTrelUpdateFdSet(fd_set * aReadFdSet,fd_set * aWriteFdSet,struct timeval * aTimeout,int * aMaxFd)332 void platformTrelUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, struct timeval *aTimeout, int *aMaxFd)
333 {
334     OT_UNUSED_VARIABLE(aTimeout);
335 
336     // Always ready to receive
337     utilsAddSocketRxFd(&sSocket, aReadFdSet, aMaxFd);
338 
339     if (sNumPendingTx > 0)
340     {
341         utilsAddSocketTxFd(&sSocket, aWriteFdSet, aMaxFd);
342     }
343 }
344 
platformTrelProcess(otInstance * aInstance,const fd_set * aReadFdSet,const fd_set * aWriteFdSet)345 void platformTrelProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet)
346 {
347     if ((sNumPendingTx > 0) && utilsCanSocketSend(&sSocket, aWriteFdSet))
348     {
349         sendPendingTxMessages();
350     }
351 
352     if (utilsCanSocketReceive(&sSocket, aReadFdSet))
353     {
354         Message  message;
355         uint16_t len;
356 
357         message.mDataLength = 0;
358 
359         len = utilsReceiveFromSocket(&sSocket, &message, sizeof(message), NULL);
360 
361         if (len > 0)
362         {
363             processMessage(aInstance, &message, len);
364         }
365     }
366 }
367 
otPlatTrelGetCounters(otInstance * aInstance)368 const otPlatTrelCounters *otPlatTrelGetCounters(otInstance *aInstance)
369 {
370     OT_UNUSED_VARIABLE(aInstance);
371     return &sCounters;
372 }
373 
otPlatTrelResetCounters(otInstance * aInstance)374 void otPlatTrelResetCounters(otInstance *aInstance)
375 {
376     OT_UNUSED_VARIABLE(aInstance);
377     memset(&sCounters, 0, sizeof(sCounters));
378 }
379 
380 //---------------------------------------------------------------------------------------------------------------------
381 
382 // This is added for RCP build to be built ok
otPlatTrelHandleReceived(otInstance * aInstance,uint8_t * aBuffer,uint16_t aLength)383 OT_TOOL_WEAK void otPlatTrelHandleReceived(otInstance *aInstance, uint8_t *aBuffer, uint16_t aLength)
384 {
385     OT_UNUSED_VARIABLE(aInstance);
386     OT_UNUSED_VARIABLE(aBuffer);
387     OT_UNUSED_VARIABLE(aLength);
388 
389     assert(false);
390 }
391 
otPlatTrelHandleDiscoveredPeerInfo(otInstance * aInstance,const otPlatTrelPeerInfo * aInfo)392 OT_TOOL_WEAK void otPlatTrelHandleDiscoveredPeerInfo(otInstance *aInstance, const otPlatTrelPeerInfo *aInfo)
393 {
394     OT_UNUSED_VARIABLE(aInstance);
395     OT_UNUSED_VARIABLE(aInfo);
396 
397     assert(false);
398 }
399 
400 #endif // OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
401