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