• 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 "platform-simulation.h"
30 
31 #include <openthread/icmp6.h>
32 #include <openthread/ip6.h>
33 #include <openthread/logging.h>
34 #include <openthread/platform/infra_if.h>
35 
36 #include "simul_utils.h"
37 #include "lib/platform/exit_code.h"
38 #include "utils/code_utils.h"
39 
40 #if OPENTHREAD_SIMULATION_IMPLEMENT_INFRA_IF && OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
41 
42 #define DEBUG_LOG 0
43 
44 #if DEBUG_LOG
45 #define LOG(...) otLogNotePlat("[infra-if] "__VA_ARGS__)
46 #else
47 #define LOG(...) \
48     do           \
49     {            \
50     } while (0)
51 #endif
52 
53 #define INFRA_IF_SIM_PORT 9800
54 #define INFRA_IF_MAX_PACKET_SIZE 1800
55 #define INFRA_IF_MAX_PENDING_TX 64
56 #define INFRA_IF_NEIGHBOR_ADVERT_SIZE 24
57 
58 typedef struct Message
59 {
60     uint32_t     mIfIndex;
61     otIp6Address mSrc;
62     otIp6Address mDst;
63     uint16_t     mDataLength;
64     uint8_t      mData[INFRA_IF_MAX_PACKET_SIZE];
65 } Message;
66 
67 static bool         sInitialized = false;
68 static otIp6Address sIp6Address;
69 static otIp6Address sLinkLocalAllNodes;
70 static otIp6Address sLinkLocalAllRouters;
71 static utilsSocket  sSocket;
72 static uint16_t     sPortOffset   = 0;
73 static uint8_t      sNumPendingTx = 0;
74 static Message      sPendingTx[INFRA_IF_MAX_PENDING_TX];
75 
76 //---------------------------------------------------------------------------------------------------------------------
77 
addressesMatch(const otIp6Address * aFirstAddr,const otIp6Address * aSecondAddr)78 static bool addressesMatch(const otIp6Address *aFirstAddr, const otIp6Address *aSecondAddr)
79 {
80     return memcmp(aFirstAddr, aSecondAddr, sizeof(otIp6Address)) == 0;
81 }
82 
getMessageSize(const Message * aMessage)83 static uint16_t getMessageSize(const Message *aMessage)
84 {
85     return (uint16_t)(&aMessage->mData[aMessage->mDataLength] - (const uint8_t *)aMessage);
86 }
87 
sendPendingTxMessages(void)88 static void sendPendingTxMessages(void)
89 {
90     for (uint8_t i = 0; i < sNumPendingTx; i++)
91     {
92         utilsSendOverSocket(&sSocket, &sPendingTx[i], getMessageSize(&sPendingTx[i]));
93     }
94 
95     sNumPendingTx = 0;
96 }
97 
sendNeighborAdvert(const Message * aNsMessage)98 static void sendNeighborAdvert(const Message *aNsMessage)
99 {
100     Message *message;
101     uint8_t  index;
102 
103     assert(sNumPendingTx < INFRA_IF_MAX_PENDING_TX);
104 
105     message = &sPendingTx[sNumPendingTx++];
106 
107     message->mIfIndex = aNsMessage->mIfIndex;
108     message->mSrc     = sIp6Address;
109     message->mDst     = aNsMessage->mSrc;
110 
111     // Neighbor Advertisement Message (RFC 4861)
112     //
113     //   0                   1                   2                   3
114     //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
115     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
116     //  |     Type      |     Code      |          Checksum             |
117     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
118     //  |R|S|O|                     Reserved                            |
119     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
120     //  |                                                               |
121     //  +                                                               +
122     //  |                                                               |
123     //  +                       Target Address                          +
124     //  |                                                               |
125     //  +                                                               +
126     //  |                                                               |
127     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
128 
129     index = 0;
130     memset(message->mData, 0, INFRA_IF_NEIGHBOR_ADVERT_SIZE);
131 
132     message->mData[index++] = OT_ICMP6_TYPE_NEIGHBOR_ADVERT;           // Type.
133     index += 3;                                                        // Code is zero. Checksum (uint16) as zero.
134     message->mData[index++] = 0xd0;                                    // Flags, set R and S bits.
135     index += 3;                                                        // Skip over the reserved bytes.
136     memcpy(&message->mData[index], &sIp6Address, sizeof(sIp6Address)); // Set the target address field.
137     index += sizeof(sIp6Address);
138 
139     assert(index == INFRA_IF_NEIGHBOR_ADVERT_SIZE);
140 
141     message->mDataLength = INFRA_IF_NEIGHBOR_ADVERT_SIZE;
142 }
143 
processMessage(otInstance * aInstance,Message * aMessage,uint16_t aLength)144 static void processMessage(otInstance *aInstance, Message *aMessage, uint16_t aLength)
145 {
146     OT_UNUSED_VARIABLE(aInstance);
147 
148     otEXPECT(aLength > 0);
149     otEXPECT(getMessageSize(aMessage) == aLength);
150     otEXPECT(aMessage->mDataLength > 0);
151 
152     // Validate the dest address.
153     otEXPECT(addressesMatch(&aMessage->mDst, &sIp6Address) || addressesMatch(&aMessage->mDst, &sLinkLocalAllNodes) ||
154              addressesMatch(&aMessage->mDst, &sLinkLocalAllRouters));
155 
156     if (aMessage->mData[0] == OT_ICMP6_TYPE_NEIGHBOR_SOLICIT)
157     {
158         LOG("Received NS, responding with NA");
159         sendNeighborAdvert(aMessage);
160     }
161     else
162     {
163         LOG("Received msg, len:%u", aMessage->mDataLength);
164         otPlatInfraIfRecvIcmp6Nd(aInstance, aMessage->mIfIndex, &aMessage->mSrc, aMessage->mData,
165                                  aMessage->mDataLength);
166     }
167 
168 exit:
169     return;
170 }
171 
172 //---------------------------------------------------------------------------------------------------------------------
173 // otPlatInfraIf
174 
otPlatInfraIfHasAddress(uint32_t aInfraIfIndex,const otIp6Address * aAddress)175 bool otPlatInfraIfHasAddress(uint32_t aInfraIfIndex, const otIp6Address *aAddress)
176 {
177     OT_UNUSED_VARIABLE(aInfraIfIndex);
178 
179     return addressesMatch(aAddress, &sIp6Address);
180 }
181 
otPlatInfraIfSendIcmp6Nd(uint32_t aInfraIfIndex,const otIp6Address * aDestAddress,const uint8_t * aBuffer,uint16_t aBufferLength)182 otError otPlatInfraIfSendIcmp6Nd(uint32_t            aInfraIfIndex,
183                                  const otIp6Address *aDestAddress,
184                                  const uint8_t      *aBuffer,
185                                  uint16_t            aBufferLength)
186 {
187     otError  error = OT_ERROR_FAILED;
188     Message *message;
189 
190     otEXPECT(sInitialized);
191     otEXPECT(sNumPendingTx < INFRA_IF_MAX_PENDING_TX);
192 
193     message = &sPendingTx[sNumPendingTx++];
194 
195     message->mIfIndex = aInfraIfIndex;
196     message->mSrc     = sIp6Address;
197     message->mDst     = *aDestAddress;
198 
199     assert(aBufferLength <= INFRA_IF_MAX_PACKET_SIZE);
200     message->mDataLength = aBufferLength;
201     memcpy(message->mData, aBuffer, aBufferLength);
202     error = OT_ERROR_NONE;
203 
204     LOG("otPlatInfraIfSendIcmp6Nd() msg-len:%u", aBufferLength);
205 
206 exit:
207     return error;
208 }
209 
otPlatInfraIfDiscoverNat64Prefix(uint32_t aInfraIfIndex)210 otError otPlatInfraIfDiscoverNat64Prefix(uint32_t aInfraIfIndex)
211 {
212     OT_UNUSED_VARIABLE(aInfraIfIndex);
213 
214     return OT_ERROR_NONE;
215 }
216 
217 //---------------------------------------------------------------------------------------------------------------------
218 // platformInfraIf
219 
platformInfraIfInit(void)220 void platformInfraIfInit(void)
221 {
222     char *str;
223 
224     otEXPECT(!sInitialized);
225 
226     sInitialized = true;
227 
228     memset(&sIp6Address, 0, sizeof(sIp6Address));
229     sIp6Address.mFields.m8[0]  = 0xfe;
230     sIp6Address.mFields.m8[1]  = 0x80;
231     sIp6Address.mFields.m8[15] = (uint8_t)(gNodeId & 0xff);
232 
233     // "ff02::01"
234     memset(&sLinkLocalAllNodes, 0, sizeof(sLinkLocalAllNodes));
235     sLinkLocalAllNodes.mFields.m8[0]  = 0xff;
236     sLinkLocalAllNodes.mFields.m8[1]  = 0x02;
237     sLinkLocalAllNodes.mFields.m8[15] = 0x01;
238 
239     // "ff02::02"
240     memset(&sLinkLocalAllRouters, 0, sizeof(sLinkLocalAllRouters));
241     sLinkLocalAllRouters.mFields.m8[0]  = 0xff;
242     sLinkLocalAllRouters.mFields.m8[1]  = 0x02;
243     sLinkLocalAllRouters.mFields.m8[15] = 0x02;
244 
245     str = getenv("PORT_OFFSET");
246 
247     if (str != NULL)
248     {
249         char *endptr;
250 
251         sPortOffset = (uint16_t)strtol(str, &endptr, 0);
252 
253         if (*endptr != '\0')
254         {
255             fprintf(stderr, "\r\nInvalid PORT_OFFSET: %s\r\n", str);
256             DieNow(OT_EXIT_FAILURE);
257         }
258 
259         sPortOffset *= (MAX_NETWORK_SIZE + 1);
260     }
261 
262     utilsInitSocket(&sSocket, INFRA_IF_SIM_PORT + sPortOffset);
263 
264 exit:
265     return;
266 }
267 
platformInfraIfDeinit(void)268 void platformInfraIfDeinit(void)
269 {
270     otEXPECT(sInitialized);
271     sInitialized = false;
272     utilsDeinitSocket(&sSocket);
273 
274 exit:
275     return;
276 }
277 
platformInfraIfUpdateFdSet(fd_set * aReadFdSet,fd_set * aWriteFdSet,int * aMaxFd)278 void platformInfraIfUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, int *aMaxFd)
279 {
280     otEXPECT(sInitialized);
281 
282     utilsAddSocketRxFd(&sSocket, aReadFdSet, aMaxFd);
283 
284     if (sNumPendingTx > 0)
285     {
286         utilsAddSocketTxFd(&sSocket, aWriteFdSet, aMaxFd);
287     }
288 
289 exit:
290     return;
291 }
292 
platformInfraIfProcess(otInstance * aInstance,const fd_set * aReadFdSet,const fd_set * aWriteFdSet)293 void platformInfraIfProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet)
294 {
295     OT_UNUSED_VARIABLE(aInstance);
296 
297     otEXPECT(sInitialized);
298 
299     if ((sNumPendingTx > 0) && utilsCanSocketSend(&sSocket, aWriteFdSet))
300     {
301         sendPendingTxMessages();
302     }
303 
304     if (utilsCanSocketReceive(&sSocket, aReadFdSet))
305     {
306         Message  message;
307         uint16_t len;
308 
309         message.mDataLength = 0;
310 
311         len = utilsReceiveFromSocket(&sSocket, &message, sizeof(message), NULL);
312         processMessage(aInstance, &message, len);
313     }
314 
315 exit:
316     return;
317 }
318 
319 //---------------------------------------------------------------------------------------------------------------------
320 // Provide weak implementation (used for RCP builds).
321 // `OPENTHREAD_RADIO` is not available in simulation platform
322 
otPlatInfraIfRecvIcmp6Nd(otInstance * aInstance,uint32_t aInfraIfIndex,const otIp6Address * aSrcAddress,const uint8_t * aBuffer,uint16_t aBufferLength)323 OT_TOOL_WEAK void otPlatInfraIfRecvIcmp6Nd(otInstance         *aInstance,
324                                            uint32_t            aInfraIfIndex,
325                                            const otIp6Address *aSrcAddress,
326                                            const uint8_t      *aBuffer,
327                                            uint16_t            aBufferLength)
328 {
329     OT_UNUSED_VARIABLE(aInstance);
330     OT_UNUSED_VARIABLE(aInfraIfIndex);
331     OT_UNUSED_VARIABLE(aSrcAddress);
332     OT_UNUSED_VARIABLE(aBuffer);
333     OT_UNUSED_VARIABLE(aBufferLength);
334 
335     fprintf(stderr, "\n\r Weak otPlatInfraIfRecvIcmp6Nd is being used\n\r");
336     DieNow(OT_EXIT_FAILURE);
337 }
338 
339 #endif // OPENTHREAD_SIMULATION_IMPLEMENT_INFRA_IF && OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
340