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