1 /*
2 * Copyright (c) 2016, 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 /**
30 * @file
31 * This file implements UDP/IPv6 sockets.
32 */
33
34 #include "udp6.hpp"
35
36 #include "instance/instance.hpp"
37
38 namespace ot {
39 namespace Ip6 {
40
41 //---------------------------------------------------------------------------------------------------------------------
42 // Udp::SocketHandle
43
Matches(const MessageInfo & aMessageInfo) const44 bool Udp::SocketHandle::Matches(const MessageInfo &aMessageInfo) const
45 {
46 bool matches = false;
47
48 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
49 VerifyOrExit(IsBackbone() == aMessageInfo.IsHostInterface());
50 #endif
51
52 VerifyOrExit(GetSockName().mPort == aMessageInfo.GetSockPort());
53
54 VerifyOrExit(aMessageInfo.GetSockAddr().IsMulticast() || GetSockName().GetAddress().IsUnspecified() ||
55 GetSockName().GetAddress() == aMessageInfo.GetSockAddr());
56
57 // Verify source if connected socket
58 if (GetPeerName().mPort != 0)
59 {
60 VerifyOrExit(GetPeerName().mPort == aMessageInfo.GetPeerPort());
61
62 VerifyOrExit(GetPeerName().GetAddress().IsUnspecified() ||
63 GetPeerName().GetAddress() == aMessageInfo.GetPeerAddr());
64 }
65
66 matches = true;
67
68 exit:
69 return matches;
70 }
71
72 //---------------------------------------------------------------------------------------------------------------------
73 // Udp::Socket
74
Socket(Instance & aInstance,ReceiveHandler aHandler,void * aContext)75 Udp::Socket::Socket(Instance &aInstance, ReceiveHandler aHandler, void *aContext)
76 : InstanceLocator(aInstance)
77 {
78 Clear();
79 mHandler = aHandler;
80 mContext = aContext;
81 }
82
NewMessage(void)83 Message *Udp::Socket::NewMessage(void) { return NewMessage(0); }
84
NewMessage(uint16_t aReserved)85 Message *Udp::Socket::NewMessage(uint16_t aReserved) { return NewMessage(aReserved, Message::Settings::GetDefault()); }
86
NewMessage(uint16_t aReserved,const Message::Settings & aSettings)87 Message *Udp::Socket::NewMessage(uint16_t aReserved, const Message::Settings &aSettings)
88 {
89 return Get<Udp>().NewMessage(aReserved, aSettings);
90 }
91
Open(NetifIdentifier aNetifId)92 Error Udp::Socket::Open(NetifIdentifier aNetifId) { return Get<Udp>().Open(*this, aNetifId, mHandler, mContext); }
93
IsOpen(void) const94 bool Udp::Socket::IsOpen(void) const { return Get<Udp>().IsOpen(*this); }
95
Bind(const SockAddr & aSockAddr)96 Error Udp::Socket::Bind(const SockAddr &aSockAddr) { return Get<Udp>().Bind(*this, aSockAddr); }
97
Bind(uint16_t aPort)98 Error Udp::Socket::Bind(uint16_t aPort) { return Bind(SockAddr(aPort)); }
99
Connect(const SockAddr & aSockAddr)100 Error Udp::Socket::Connect(const SockAddr &aSockAddr) { return Get<Udp>().Connect(*this, aSockAddr); }
101
Connect(uint16_t aPort)102 Error Udp::Socket::Connect(uint16_t aPort) { return Connect(SockAddr(aPort)); }
103
Close(void)104 Error Udp::Socket::Close(void) { return Get<Udp>().Close(*this); }
105
SendTo(Message & aMessage,const MessageInfo & aMessageInfo)106 Error Udp::Socket::SendTo(Message &aMessage, const MessageInfo &aMessageInfo)
107 {
108 return Get<Udp>().SendTo(*this, aMessage, aMessageInfo);
109 }
110
111 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
JoinNetifMulticastGroup(NetifIdentifier aNetifIdentifier,const Address & aAddress)112 Error Udp::Socket::JoinNetifMulticastGroup(NetifIdentifier aNetifIdentifier, const Address &aAddress)
113 {
114 OT_UNUSED_VARIABLE(aNetifIdentifier);
115 OT_UNUSED_VARIABLE(aAddress);
116
117 Error error = kErrorNotImplemented;
118
119 VerifyOrExit(aAddress.IsMulticast(), error = kErrorInvalidArgs);
120
121 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
122 error = Plat::JoinMulticastGroup(*this, aNetifIdentifier, aAddress);
123 #endif
124
125 exit:
126 return error;
127 }
128
LeaveNetifMulticastGroup(NetifIdentifier aNetifIdentifier,const Address & aAddress)129 Error Udp::Socket::LeaveNetifMulticastGroup(NetifIdentifier aNetifIdentifier, const Address &aAddress)
130 {
131 OT_UNUSED_VARIABLE(aNetifIdentifier);
132 OT_UNUSED_VARIABLE(aAddress);
133
134 Error error = kErrorNotImplemented;
135
136 VerifyOrExit(aAddress.IsMulticast(), error = kErrorInvalidArgs);
137
138 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
139 error = Plat::LeaveMulticastGroup(*this, aNetifIdentifier, aAddress);
140 #endif
141
142 exit:
143 return error;
144 }
145 #endif
146
147 //---------------------------------------------------------------------------------------------------------------------
148 // Udp::Plat
149
150 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
151
Open(SocketHandle & aSocket)152 Error Udp::Plat::Open(SocketHandle &aSocket)
153 {
154 return aSocket.ShouldUsePlatformUdp() ? otPlatUdpSocket(&aSocket) : kErrorNone;
155 }
156
Close(SocketHandle & aSocket)157 Error Udp::Plat::Close(SocketHandle &aSocket)
158 {
159 return aSocket.ShouldUsePlatformUdp() ? otPlatUdpClose(&aSocket) : kErrorNone;
160 }
161
Bind(SocketHandle & aSocket)162 Error Udp::Plat::Bind(SocketHandle &aSocket)
163 {
164 return aSocket.ShouldUsePlatformUdp() ? otPlatUdpBind(&aSocket) : kErrorNone;
165 }
166
BindToNetif(SocketHandle & aSocket)167 Error Udp::Plat::BindToNetif(SocketHandle &aSocket)
168 {
169 return aSocket.ShouldUsePlatformUdp() ? otPlatUdpBindToNetif(&aSocket, MapEnum(aSocket.GetNetifId())) : kErrorNone;
170 }
171
Connect(SocketHandle & aSocket)172 Error Udp::Plat::Connect(SocketHandle &aSocket)
173 {
174 return aSocket.ShouldUsePlatformUdp() ? otPlatUdpConnect(&aSocket) : kErrorNone;
175 }
176
Send(SocketHandle & aSocket,Message & aMessage,const MessageInfo & aMessageInfo)177 Error Udp::Plat::Send(SocketHandle &aSocket, Message &aMessage, const MessageInfo &aMessageInfo)
178 {
179 OT_ASSERT(aSocket.ShouldUsePlatformUdp());
180
181 return otPlatUdpSend(&aSocket, &aMessage, &aMessageInfo);
182 }
183
JoinMulticastGroup(SocketHandle & aSocket,NetifIdentifier aNetifId,const Address & aAddress)184 Error Udp::Plat::JoinMulticastGroup(SocketHandle &aSocket, NetifIdentifier aNetifId, const Address &aAddress)
185 {
186 return aSocket.ShouldUsePlatformUdp() ? otPlatUdpJoinMulticastGroup(&aSocket, MapEnum(aNetifId), &aAddress)
187 : kErrorNone;
188 }
189
LeaveMulticastGroup(SocketHandle & aSocket,NetifIdentifier aNetifId,const Address & aAddress)190 Error Udp::Plat::LeaveMulticastGroup(SocketHandle &aSocket, NetifIdentifier aNetifId, const Address &aAddress)
191 {
192 return aSocket.ShouldUsePlatformUdp() ? otPlatUdpLeaveMulticastGroup(&aSocket, MapEnum(aNetifId), &aAddress)
193 : kErrorNone;
194 }
195
196 #endif // OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
197
198 //---------------------------------------------------------------------------------------------------------------------
199 // Udp
200
Udp(Instance & aInstance)201 Udp::Udp(Instance &aInstance)
202 : InstanceLocator(aInstance)
203 , mEphemeralPort(kDynamicPortMin)
204 {
205 }
206
AddReceiver(Receiver & aReceiver)207 Error Udp::AddReceiver(Receiver &aReceiver) { return mReceivers.Add(aReceiver); }
208
RemoveReceiver(Receiver & aReceiver)209 Error Udp::RemoveReceiver(Receiver &aReceiver)
210 {
211 Error error;
212
213 SuccessOrExit(error = mReceivers.Remove(aReceiver));
214 aReceiver.SetNext(nullptr);
215
216 exit:
217 return error;
218 }
219
Open(SocketHandle & aSocket,NetifIdentifier aNetifId,ReceiveHandler aHandler,void * aContext)220 Error Udp::Open(SocketHandle &aSocket, NetifIdentifier aNetifId, ReceiveHandler aHandler, void *aContext)
221 {
222 Error error = kErrorNone;
223
224 OT_ASSERT(!IsOpen(aSocket));
225
226 aSocket.Clear();
227 aSocket.SetNetifId(aNetifId);
228 aSocket.mHandler = aHandler;
229 aSocket.mContext = aContext;
230
231 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
232 error = Plat::Open(aSocket);
233 #endif
234 SuccessOrExit(error);
235
236 AddSocket(aSocket);
237
238 exit:
239 return error;
240 }
241
Bind(SocketHandle & aSocket,const SockAddr & aSockAddr)242 Error Udp::Bind(SocketHandle &aSocket, const SockAddr &aSockAddr)
243 {
244 Error error = kErrorNone;
245
246 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
247 SuccessOrExit(error = Plat::BindToNetif(aSocket));
248 #endif
249
250 VerifyOrExit(aSockAddr.GetAddress().IsUnspecified() || Get<ThreadNetif>().HasUnicastAddress(aSockAddr.GetAddress()),
251 error = kErrorInvalidArgs);
252
253 aSocket.mSockName = aSockAddr;
254
255 if (!aSocket.IsBound())
256 {
257 do
258 {
259 aSocket.mSockName.mPort = GetEphemeralPort();
260 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
261 error = Plat::Bind(aSocket);
262 #endif
263 } while (error != kErrorNone);
264 }
265 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
266 else
267 {
268 error = Plat::Bind(aSocket);
269 }
270 #endif
271
272 exit:
273 return error;
274 }
275
Connect(SocketHandle & aSocket,const SockAddr & aSockAddr)276 Error Udp::Connect(SocketHandle &aSocket, const SockAddr &aSockAddr)
277 {
278 Error error = kErrorNone;
279
280 aSocket.mPeerName = aSockAddr;
281
282 if (!aSocket.IsBound())
283 {
284 SuccessOrExit(error = Bind(aSocket, aSocket.GetSockName()));
285 }
286
287 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
288 error = Plat::Connect(aSocket);
289 #endif
290
291 exit:
292 return error;
293 }
294
Close(SocketHandle & aSocket)295 Error Udp::Close(SocketHandle &aSocket)
296 {
297 Error error = kErrorNone;
298
299 VerifyOrExit(IsOpen(aSocket));
300
301 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
302 SuccessOrExit(error = Plat::Close(aSocket));
303 #endif
304
305 RemoveSocket(aSocket);
306 aSocket.GetSockName().Clear();
307 aSocket.GetPeerName().Clear();
308
309 exit:
310 return error;
311 }
312
SendTo(SocketHandle & aSocket,Message & aMessage,const MessageInfo & aMessageInfo)313 Error Udp::SendTo(SocketHandle &aSocket, Message &aMessage, const MessageInfo &aMessageInfo)
314 {
315 Error error = kErrorNone;
316 MessageInfo messageInfoLocal;
317
318 VerifyOrExit((aMessageInfo.GetSockPort() == 0) || (aSocket.GetSockName().mPort == aMessageInfo.GetSockPort()),
319 error = kErrorInvalidArgs);
320
321 messageInfoLocal = aMessageInfo;
322
323 if (messageInfoLocal.GetPeerAddr().IsUnspecified())
324 {
325 VerifyOrExit(!aSocket.GetPeerName().GetAddress().IsUnspecified(), error = kErrorInvalidArgs);
326
327 messageInfoLocal.SetPeerAddr(aSocket.GetPeerName().GetAddress());
328 }
329
330 if (messageInfoLocal.mPeerPort == 0)
331 {
332 VerifyOrExit(aSocket.GetPeerName().mPort != 0, error = kErrorInvalidArgs);
333 messageInfoLocal.mPeerPort = aSocket.GetPeerName().mPort;
334 }
335
336 if (messageInfoLocal.GetSockAddr().IsUnspecified())
337 {
338 messageInfoLocal.SetSockAddr(aSocket.GetSockName().GetAddress());
339 }
340
341 if (!aSocket.IsBound())
342 {
343 SuccessOrExit(error = Bind(aSocket, aSocket.GetSockName()));
344 }
345
346 messageInfoLocal.SetSockPort(aSocket.GetSockName().mPort);
347
348 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
349 if (aSocket.ShouldUsePlatformUdp())
350 {
351 SuccessOrExit(error = Plat::Send(aSocket, aMessage, messageInfoLocal));
352 }
353 else
354 #endif
355 {
356 SuccessOrExit(error = SendDatagram(aMessage, messageInfoLocal));
357 }
358
359 exit:
360 return error;
361 }
362
IsPortReserved(uint16_t aPort)363 bool Udp::IsPortReserved(uint16_t aPort)
364 {
365 return aPort == Tmf::kUdpPort || (kSrpServerPortMin <= aPort && aPort <= kSrpServerPortMax);
366 }
367
AddSocket(SocketHandle & aSocket)368 void Udp::AddSocket(SocketHandle &aSocket) { IgnoreError(mSockets.Add(aSocket)); }
369
RemoveSocket(SocketHandle & aSocket)370 void Udp::RemoveSocket(SocketHandle &aSocket)
371 {
372 SocketHandle *prev;
373
374 SuccessOrExit(mSockets.Find(aSocket, prev));
375
376 mSockets.PopAfter(prev);
377 aSocket.SetNext(nullptr);
378
379 exit:
380 return;
381 }
382
GetEphemeralPort(void)383 uint16_t Udp::GetEphemeralPort(void)
384 {
385 do
386 {
387 if (mEphemeralPort < kDynamicPortMax)
388 {
389 mEphemeralPort++;
390 }
391 else
392 {
393 mEphemeralPort = kDynamicPortMin;
394 }
395 } while (IsPortReserved(mEphemeralPort));
396
397 return mEphemeralPort;
398 }
399
NewMessage(void)400 Message *Udp::NewMessage(void) { return NewMessage(0); }
401
NewMessage(uint16_t aReserved)402 Message *Udp::NewMessage(uint16_t aReserved) { return NewMessage(aReserved, Message::Settings::GetDefault()); }
403
NewMessage(uint16_t aReserved,const Message::Settings & aSettings)404 Message *Udp::NewMessage(uint16_t aReserved, const Message::Settings &aSettings)
405 {
406 return Get<Ip6>().NewMessage(sizeof(Header) + aReserved, aSettings);
407 }
408
SendDatagram(Message & aMessage,MessageInfo & aMessageInfo)409 Error Udp::SendDatagram(Message &aMessage, MessageInfo &aMessageInfo)
410 {
411 Error error = kErrorNone;
412
413 #if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE
414 if (aMessageInfo.IsHostInterface())
415 {
416 VerifyOrExit(mUdpForwarder.IsSet(), error = kErrorNoRoute);
417 mUdpForwarder.Invoke(&aMessage, aMessageInfo.mPeerPort, &aMessageInfo.GetPeerAddr(), aMessageInfo.mSockPort);
418 // message is consumed by the callback
419 }
420 else
421 #endif
422 {
423 Header udpHeader;
424
425 udpHeader.SetSourcePort(aMessageInfo.mSockPort);
426 udpHeader.SetDestinationPort(aMessageInfo.mPeerPort);
427 udpHeader.SetLength(sizeof(udpHeader) + aMessage.GetLength());
428 udpHeader.SetChecksum(0);
429
430 SuccessOrExit(error = aMessage.Prepend(udpHeader));
431 aMessage.SetOffset(0);
432
433 error = Get<Ip6>().SendDatagram(aMessage, aMessageInfo, kProtoUdp);
434 }
435
436 exit:
437 return error;
438 }
439
HandleMessage(Message & aMessage,MessageInfo & aMessageInfo)440 Error Udp::HandleMessage(Message &aMessage, MessageInfo &aMessageInfo)
441 {
442 Error error = kErrorNone;
443 Header udpHeader;
444
445 SuccessOrExit(error = aMessage.Read(aMessage.GetOffset(), udpHeader));
446
447 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
448 SuccessOrExit(error = Checksum::VerifyMessageChecksum(aMessage, aMessageInfo, kProtoUdp));
449 #endif
450
451 aMessage.MoveOffset(sizeof(udpHeader));
452 aMessageInfo.mPeerPort = udpHeader.GetSourcePort();
453 aMessageInfo.mSockPort = udpHeader.GetDestinationPort();
454
455 for (Receiver &receiver : mReceivers)
456 {
457 VerifyOrExit(!receiver.HandleMessage(aMessage, aMessageInfo));
458 }
459
460 HandlePayload(aMessage, aMessageInfo);
461
462 exit:
463 return error;
464 }
465
HandlePayload(Message & aMessage,MessageInfo & aMessageInfo)466 void Udp::HandlePayload(Message &aMessage, MessageInfo &aMessageInfo)
467 {
468 SocketHandle *socket;
469
470 socket = mSockets.FindMatching(aMessageInfo);
471 VerifyOrExit(socket != nullptr);
472
473 aMessage.RemoveHeader(aMessage.GetOffset());
474 OT_ASSERT(aMessage.GetOffset() == 0);
475 socket->HandleUdpReceive(aMessage, aMessageInfo);
476
477 exit:
478 return;
479 }
480
IsPortInUse(uint16_t aPort) const481 bool Udp::IsPortInUse(uint16_t aPort) const
482 {
483 bool found = false;
484
485 for (const SocketHandle &socket : mSockets)
486 {
487 if (socket.GetSockName().GetPort() == aPort)
488 {
489 found = true;
490 break;
491 }
492 }
493
494 return found;
495 }
496
497 } // namespace Ip6
498 } // namespace ot
499