Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / inet / UDPEndPoint.cpp
1 /*
2  *
3  *    Copyright (c) 2020-2021 Project CHIP Authors
4  *    Copyright (c) 2018 Google LLC.
5  *    Copyright (c) 2013-2018 Nest Labs, Inc.
6  *
7  *    Licensed under the Apache License, Version 2.0 (the "License");
8  *    you may not use this file except in compliance with the License.
9  *    You may obtain a copy of the License at
10  *
11  *        http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *    Unless required by applicable law or agreed to in writing, software
14  *    distributed under the License is distributed on an "AS IS" BASIS,
15  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *    See the License for the specific language governing permissions and
17  *    limitations under the License.
18  */
19
20 /**
21  *    @file
22  *      This file implements the <tt>Inet::UDPEndPoint</tt>
23  *      class, where the CHIP Inet Layer encapsulates methods for
24  *      interacting with UDP transport endpoints (SOCK_DGRAM sockets
25  *      on Linux and BSD-derived systems) or LwIP UDP protocol
26  *      control blocks, as the system is configured accordingly.
27  *
28  */
29
30 #define __APPLE_USE_RFC_3542
31 #include "UDPEndPoint.h"
32
33 #include "InetFaultInjection.h"
34 #include <inet/InetLayer.h>
35
36 #include <support/CodeUtils.h>
37 #include <support/logging/CHIPLogging.h>
38 #include <system/SystemFaultInjection.h>
39
40 #if CHIP_SYSTEM_CONFIG_USE_LWIP
41 #include <lwip/ip.h>
42 #include <lwip/tcpip.h>
43 #include <lwip/udp.h>
44 #if CHIP_HAVE_CONFIG_H
45 #include <lwip/lwip_buildconfig.h>
46 #endif // CHIP_HAVE_CONFIG_H
47 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
48
49 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
50 #include <sys/select.h>
51 #if HAVE_SYS_SOCKET_H
52 #include <sys/socket.h>
53 #endif // HAVE_SYS_SOCKET_H
54 #include <errno.h>
55 #include <net/if.h>
56 #include <netinet/in.h>
57 #include <unistd.h>
58 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
59
60 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKET_EXTENSIONS
61 #include "ZephyrSocket.h"
62 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKET_EXTENSIONS
63
64 #include "arpa-inet-compatibility.h"
65
66 #include <string.h>
67 #include <utility>
68
69 // SOCK_CLOEXEC not defined on all platforms, e.g. iOS/macOS:
70 #ifdef SOCK_CLOEXEC
71 #define SOCK_FLAGS SOCK_CLOEXEC
72 #else
73 #define SOCK_FLAGS 0
74 #endif
75
76 namespace chip {
77 namespace Inet {
78
79 chip::System::ObjectPool<UDPEndPoint, INET_CONFIG_NUM_UDP_ENDPOINTS> UDPEndPoint::sPool;
80
81 #if CHIP_SYSTEM_CONFIG_USE_LWIP
82 /*
83  * Note that for LwIP InterfaceId is already defined to be 'struct
84  * netif'; consequently, some of the checking performed here could
85  * conceivably be optimized out and the HAVE_LWIP_UDP_BIND_NETIF case
86  * could simply be:
87  *
88  *   udp_bind_netif(aUDP, intfId);
89  *
90  */
91 static INET_ERROR LwIPBindInterface(struct udp_pcb * aUDP, InterfaceId intfId)
92 {
93     INET_ERROR res = INET_NO_ERROR;
94
95 #if HAVE_LWIP_UDP_BIND_NETIF
96     if (!IsInterfaceIdPresent(intfId))
97         udp_bind_netif(aUDP, NULL);
98     else
99     {
100         struct netif * netifp = IPEndPointBasis::FindNetifFromInterfaceId(intfId);
101
102         if (netifp == NULL)
103             res = INET_ERROR_UNKNOWN_INTERFACE;
104         else
105             udp_bind_netif(aUDP, netifp);
106     }
107 #else
108     if (!IsInterfaceIdPresent(intfId))
109         aUDP->intf_filter = NULL;
110     else
111     {
112         struct netif * netifp = IPEndPointBasis::FindNetifFromInterfaceId(intfId);
113
114         if (netifp == NULL)
115             res = INET_ERROR_UNKNOWN_INTERFACE;
116         else
117             aUDP->intf_filter = netifp;
118     }
119 #endif // HAVE_LWIP_UDP_BIND_NETIF
120
121     return res;
122 }
123 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
124
125 /**
126  * @brief   Bind the endpoint to an interface IP address.
127  *
128  * @param[in]   addrType    the protocol version of the IP address
129  * @param[in]   addr        the IP address (must be an interface address)
130  * @param[in]   port        the UDP port
131  * @param[in]   intfId      an optional network interface indicator
132  *
133  * @retval  INET_NO_ERROR               success: endpoint bound to address
134  * @retval  INET_ERROR_INCORRECT_STATE  endpoint has been bound previously
135  * @retval  INET_NO_MEMORY              insufficient memory for endpoint
136  *
137  * @retval  INET_ERROR_UNKNOWN_INTERFACE
138  *      On some platforms, the optionally specified interface is not
139  *      present.
140  *
141  * @retval  INET_ERROR_WRONG_PROTOCOL_TYPE
142  *      \c addrType does not match \c IPVer.
143  *
144  * @retval  INET_ERROR_WRONG_ADDRESS_TYPE
145  *      \c addrType is \c kIPAddressType_Any, or the type of \c addr is not
146  *      equal to \c addrType.
147  *
148  * @retval  other                   another system or platform error
149  *
150  * @details
151  *  Binds the endpoint to the specified network interface IP address.
152  *
153  *  On LwIP, this method must not be called with the LwIP stack lock
154  *  already acquired.
155  */
156 INET_ERROR UDPEndPoint::Bind(IPAddressType addrType, const IPAddress & addr, uint16_t port, InterfaceId intfId)
157 {
158     INET_ERROR res = INET_NO_ERROR;
159
160 #if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
161
162     nw_parameters_configure_protocol_block_t configure_tls;
163     nw_parameters_t parameters;
164
165 #endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
166
167     if (mState != kState_Ready && mState != kState_Bound)
168     {
169         res = INET_ERROR_INCORRECT_STATE;
170         goto exit;
171     }
172
173     if ((addr != IPAddress::Any) && (addr.Type() != kIPAddressType_Any) && (addr.Type() != addrType))
174     {
175         res = INET_ERROR_WRONG_ADDRESS_TYPE;
176         goto exit;
177     }
178
179 #if CHIP_SYSTEM_CONFIG_USE_LWIP
180
181     // Lock LwIP stack
182     LOCK_TCPIP_CORE();
183
184     // Make sure we have the appropriate type of PCB.
185     res = GetPCB(addrType);
186
187     // Bind the PCB to the specified address/port.
188     if (res == INET_NO_ERROR)
189     {
190 #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
191         ip_addr_t ipAddr = addr.ToLwIPAddr();
192 #if INET_CONFIG_ENABLE_IPV4
193         lwip_ip_addr_type lType = IPAddress::ToLwIPAddrType(addrType);
194         IP_SET_TYPE_VAL(ipAddr, lType);
195 #endif // INET_CONFIG_ENABLE_IPV4
196         res = chip::System::MapErrorLwIP(udp_bind(mUDP, &ipAddr, port));
197 #else // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5
198         if (addrType == kIPAddressType_IPv6)
199         {
200             ip6_addr_t ipv6Addr = addr.ToIPv6();
201             res                 = chip::System::MapErrorLwIP(udp_bind_ip6(mUDP, &ipv6Addr, port));
202         }
203 #if INET_CONFIG_ENABLE_IPV4
204         else if (addrType == kIPAddressType_IPv4)
205         {
206             ip4_addr_t ipv4Addr = addr.ToIPv4();
207             res                 = chip::System::MapErrorLwIP(udp_bind(mUDP, &ipv4Addr, port));
208         }
209 #endif // INET_CONFIG_ENABLE_IPV4
210         else
211             res = INET_ERROR_WRONG_ADDRESS_TYPE;
212 #endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
213     }
214
215     if (res == INET_NO_ERROR)
216     {
217         res = LwIPBindInterface(mUDP, intfId);
218     }
219
220     // Unlock LwIP stack
221     UNLOCK_TCPIP_CORE();
222
223     SuccessOrExit(res);
224
225 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
226
227 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
228
229     // Make sure we have the appropriate type of socket.
230     res = GetSocket(addrType);
231     SuccessOrExit(res);
232
233     res = IPEndPointBasis::Bind(addrType, addr, port, intfId);
234     SuccessOrExit(res);
235
236     mBoundPort   = port;
237     mBoundIntfId = intfId;
238
239     // If an ephemeral port was requested, retrieve the actual bound port.
240     if (port == 0)
241     {
242         union
243         {
244             struct sockaddr any;
245             struct sockaddr_in in;
246             struct sockaddr_in6 in6;
247         } boundAddr;
248         socklen_t boundAddrLen = sizeof(boundAddr);
249
250         if (getsockname(mSocket, &boundAddr.any, &boundAddrLen) == 0)
251         {
252             if (boundAddr.any.sa_family == AF_INET)
253             {
254                 mBoundPort = ntohs(boundAddr.in.sin_port);
255             }
256             else if (boundAddr.any.sa_family == AF_INET6)
257             {
258                 mBoundPort = ntohs(boundAddr.in6.sin6_port);
259             }
260         }
261     }
262
263 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
264
265 #if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
266
267     if (intfId != INET_NULL_INTERFACEID)
268     {
269         res = INET_ERROR_NOT_IMPLEMENTED;
270         goto exit;
271     }
272
273     configure_tls = NW_PARAMETERS_DISABLE_PROTOCOL;
274     parameters    = nw_parameters_create_secure_udp(configure_tls, NW_PARAMETERS_DEFAULT_CONFIGURATION);
275
276     res = IPEndPointBasis::Bind(addrType, addr, port, parameters);
277     SuccessOrExit(res);
278
279     mParameters = parameters;
280
281 #endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
282
283     if (res == INET_NO_ERROR)
284     {
285         mState = kState_Bound;
286     }
287
288 exit:
289     return res;
290 }
291
292 /**
293  * @brief   Prepare the endpoint to receive UDP messages.
294  *
295  * @retval  INET_NO_ERROR   success: endpoint ready to receive messages.
296  * @retval  INET_ERROR_INCORRECT_STATE  endpoint is already listening.
297  *
298  * @details
299  *  If \c State is already \c kState_Listening, then no operation is
300  *  performed, otherwise the \c mState is set to \c kState_Listening and
301  *  the endpoint is prepared to received UDP messages, according to the
302  *  semantics of the platform.
303  *
304  *  On LwIP, this method must not be called with the LwIP stack lock
305  *  already acquired
306  */
307 INET_ERROR UDPEndPoint::Listen()
308 {
309     INET_ERROR res = INET_NO_ERROR;
310
311 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
312     chip::System::Layer & lSystemLayer = SystemLayer();
313 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
314
315     if (mState == kState_Listening)
316     {
317         res = INET_NO_ERROR;
318         goto exit;
319     }
320
321     if (mState != kState_Bound)
322     {
323         res = INET_ERROR_INCORRECT_STATE;
324         goto exit;
325     }
326
327 #if CHIP_SYSTEM_CONFIG_USE_LWIP
328
329     // Lock LwIP stack
330     LOCK_TCPIP_CORE();
331
332 #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
333     udp_recv(mUDP, LwIPReceiveUDPMessage, this);
334 #else  // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5
335     if (PCB_ISIPV6(mUDP))
336         udp_recv_ip6(mUDP, LwIPReceiveUDPMessage, this);
337     else
338         udp_recv(mUDP, LwIPReceiveUDPMessage, this);
339 #endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
340
341     // Unlock LwIP stack
342     UNLOCK_TCPIP_CORE();
343
344 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
345
346 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
347
348     // Wake the thread calling select so that it starts selecting on the new socket.
349     lSystemLayer.WakeSelect();
350
351 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
352
353 #if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
354
355     res = StartListener();
356     SuccessOrExit(res);
357
358 #endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
359
360     if (res == INET_NO_ERROR)
361     {
362         mState = kState_Listening;
363     }
364
365 exit:
366     return res;
367 }
368
369 /**
370  * @brief   Close the endpoint.
371  *
372  * @details
373  *  If <tt>mState != kState_Closed</tt>, then closes the endpoint, removing
374  *  it from the set of endpoints eligible for communication events.
375  *
376  *  On LwIP systems, this method must not be called with the LwIP stack
377  *  lock already acquired.
378  */
379 void UDPEndPoint::Close()
380 {
381     if (mState != kState_Closed)
382     {
383 #if CHIP_SYSTEM_CONFIG_USE_LWIP
384
385         // Lock LwIP stack
386         LOCK_TCPIP_CORE();
387
388         // Since UDP PCB is released synchronously here, but UDP endpoint itself might have to wait
389         // for destruction asynchronously, there could be more allocated UDP endpoints than UDP PCBs.
390         if (mUDP != NULL)
391         {
392             udp_remove(mUDP);
393             mUDP              = NULL;
394             mLwIPEndPointType = kLwIPEndPointType_Unknown;
395         }
396
397         // Unlock LwIP stack
398         UNLOCK_TCPIP_CORE();
399
400 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
401
402 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
403
404         if (mSocket != INET_INVALID_SOCKET_FD)
405         {
406             chip::System::Layer & lSystemLayer = SystemLayer();
407
408             // Wake the thread calling select so that it recognizes the socket is closed.
409             lSystemLayer.WakeSelect();
410
411             close(mSocket);
412             mSocket = INET_INVALID_SOCKET_FD;
413         }
414
415         // Clear any results from select() that indicate pending I/O for the socket.
416         mPendingIO.Clear();
417
418 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
419
420 #if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
421         IPEndPointBasis::ReleaseAll();
422 #endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
423
424         mState = kState_Closed;
425     }
426 }
427
428 /**
429  * @brief   Close the endpoint and recycle its memory.
430  *
431  * @details
432  *  Invokes the \c Close method, then invokes the
433  *  <tt>InetLayerBasis::Release</tt> method to return the object to its
434  *  memory pool.
435  *
436  *  On LwIP systems, this method must not be called with the LwIP stack
437  *  lock already acquired.
438  */
439 void UDPEndPoint::Free()
440 {
441     Close();
442
443 #if CHIP_SYSTEM_CONFIG_USE_LWIP
444     DeferredFree(kReleaseDeferralErrorTactic_Die);
445 #else  // !CHIP_SYSTEM_CONFIG_USE_LWIP
446     Release();
447 #endif // !CHIP_SYSTEM_CONFIG_USE_LWIP
448 }
449
450 /**
451  *  A synonym for <tt>SendTo(addr, port, INET_NULL_INTERFACEID, msg, sendFlags)</tt>.
452  */
453 INET_ERROR UDPEndPoint::SendTo(const IPAddress & addr, uint16_t port, chip::System::PacketBufferHandle && msg, uint16_t sendFlags)
454 {
455     return SendTo(addr, port, INET_NULL_INTERFACEID, std::move(msg), sendFlags);
456 }
457
458 /**
459  * @brief   Send a UDP message to the specified destination address.
460  *
461  * @param[in]   addr        the destination IP address
462  * @param[in]   port        the destination UDP port
463  * @param[in]   intfId      an optional network interface indicator
464  * @param[in]   msg         the packet buffer containing the UDP message
465  * @param[in]   sendFlags   optional transmit option flags
466  *
467  * @retval  INET_NO_ERROR       success: \c msg is queued for transmit.
468  *
469  * @retval  INET_ERROR_NOT_SUPPORTED
470  *      the system does not support the requested operation.
471  *
472  * @retval  INET_ERROR_WRONG_ADDRESS_TYPE
473  *      the destination address and the bound interface address do not
474  *      have matching protocol versions or address type.
475  *
476  * @retval  INET_ERROR_MESSAGE_TOO_LONG
477  *      \c msg does not contain the whole UDP message.
478  *
479  * @retval  INET_ERROR_OUTBOUND_MESSAGE_TRUNCATED
480  *      On some platforms, only a truncated portion of \c msg was queued
481  *      for transmit.
482  *
483  * @retval  other
484  *      another system or platform error
485  *
486  * @details
487  *      If possible, then this method sends the UDP message \c msg to the
488  *      destination \c addr (with \c intfId used as the scope
489  *      identifier for IPv6 link-local destinations) and \c port with the
490  *      transmit option flags encoded in \c sendFlags.
491  */
492 INET_ERROR UDPEndPoint::SendTo(const IPAddress & addr, uint16_t port, InterfaceId intfId, chip::System::PacketBufferHandle && msg,
493                                uint16_t sendFlags)
494 {
495     IPPacketInfo pktInfo;
496     pktInfo.Clear();
497     pktInfo.DestAddress = addr;
498     pktInfo.DestPort    = port;
499     pktInfo.Interface   = intfId;
500     return SendMsg(&pktInfo, std::move(msg), sendFlags);
501 }
502
503 /**
504  * @brief   Send a UDP message to a specified destination.
505  *
506  * @param[in]   pktInfo     source and destination information for the UDP message
507  * @param[in]   msg         a packet buffer containing the UDP message
508  * @param[in]   sendFlags   optional transmit option flags
509  *
510  * @retval  INET_NO_ERROR
511  *      success: \c msg is queued for transmit.
512  *
513  * @retval  INET_ERROR_NOT_SUPPORTED
514  *      the system does not support the requested operation.
515  *
516  * @retval  INET_ERROR_WRONG_ADDRESS_TYPE
517  *      the destination address and the bound interface address do not
518  *      have matching protocol versions or address type.
519  *
520  * @retval  INET_ERROR_MESSAGE_TOO_LONG
521  *      \c msg does not contain the whole UDP message.
522  *
523  * @retval  INET_ERROR_OUTBOUND_MESSAGE_TRUNCATED
524  *      On some platforms, only a truncated portion of \c msg was queued
525  *      for transmit.
526  *
527  * @retval  other
528  *      another system or platform error
529  *
530  * @details
531  *      Send the UDP message in \c msg to the destination address and port given in
532  *      \c pktInfo.  If \c pktInfo contains an interface id, the message will be sent
533  *      over the specified interface.  If \c pktInfo contains a source address, the
534  *      given address will be used as the source of the UDP message.
535  */
536 INET_ERROR UDPEndPoint::SendMsg(const IPPacketInfo * pktInfo, System::PacketBufferHandle msg, uint16_t sendFlags)
537 {
538     INET_ERROR res             = INET_NO_ERROR;
539     const IPAddress & destAddr = pktInfo->DestAddress;
540
541     INET_FAULT_INJECT(FaultInjection::kFault_Send, return INET_ERROR_UNKNOWN_INTERFACE;);
542     INET_FAULT_INJECT(FaultInjection::kFault_SendNonCritical, return INET_ERROR_NO_MEMORY;);
543
544 #if CHIP_SYSTEM_CONFIG_USE_LWIP
545
546     if (!msg.HasSoleOwnership())
547     {
548         // when retaining a buffer, the caller expects the msg to be unmodified.
549         // LwIP stack will normally prepend the packet headers as the packet traverses
550         // the UDP/IP/netif layers, which normally modifies the packet. We need to clone
551         // msg into a fresh object in this case, and queues that for transmission, leaving
552         // the original msg available after return.
553         msg = msg.CloneData();
554         VerifyOrExit(!msg.IsNull(), res = INET_ERROR_NO_MEMORY);
555     }
556
557     // Lock LwIP stack
558     LOCK_TCPIP_CORE();
559
560     // Make sure we have the appropriate type of PCB based on the destination address.
561     res = GetPCB(destAddr.Type());
562     SuccessOrExit(res);
563
564     // Send the message to the specified address/port.
565     // If an outbound interface has been specified, call a specific version of the UDP sendto()
566     // function that accepts the target interface.
567     // If a source address has been specified, temporarily override the local_ip of the PCB.
568     // This results in LwIP using the given address being as the source address for the generated
569     // packet, as if the PCB had been bound to that address.
570     {
571         err_t lwipErr              = ERR_VAL;
572         const IPAddress & srcAddr  = pktInfo->SrcAddress;
573         const uint16_t & destPort  = pktInfo->DestPort;
574         const InterfaceId & intfId = pktInfo->Interface;
575
576 #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
577
578         ip_addr_t lwipSrcAddr  = srcAddr.ToLwIPAddr();
579         ip_addr_t lwipDestAddr = destAddr.ToLwIPAddr();
580
581         ip_addr_t boundAddr;
582         ip_addr_copy(boundAddr, mUDP->local_ip);
583
584         if (!ip_addr_isany(&lwipSrcAddr))
585         {
586             ip_addr_copy(mUDP->local_ip, lwipSrcAddr);
587         }
588
589         if (intfId != INET_NULL_INTERFACEID)
590             lwipErr = udp_sendto_if(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort, intfId);
591         else
592             lwipErr = udp_sendto(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort);
593
594         ip_addr_copy(mUDP->local_ip, boundAddr);
595
596 #else // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5
597
598         ipX_addr_t boundAddr;
599         ipX_addr_copy(boundAddr, mUDP->local_ip);
600
601         if (PCB_ISIPV6(mUDP))
602         {
603             ip6_addr_t lwipSrcAddr  = srcAddr.ToIPv6();
604             ip6_addr_t lwipDestAddr = destAddr.ToIPv6();
605
606             if (!ip6_addr_isany(&lwipSrcAddr))
607             {
608                 ipX_addr_copy(mUDP->local_ip, *ip6_2_ipX(&lwipSrcAddr));
609             }
610
611             if (intfId != INET_NULL_INTERFACEID)
612                 lwipErr =
613                     udp_sendto_if_ip6(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort, intfId);
614             else
615                 lwipErr = udp_sendto_ip6(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort);
616         }
617
618 #if INET_CONFIG_ENABLE_IPV4
619
620         else
621         {
622             ip4_addr_t lwipSrcAddr  = srcAddr.ToIPv4();
623             ip4_addr_t lwipDestAddr = destAddr.ToIPv4();
624             ipX_addr_t boundAddr;
625
626             if (!ip_addr_isany(&lwipSrcAddr))
627             {
628                 ipX_addr_copy(mUDP->local_ip, *ip_2_ipX(&lwipSrcAddr));
629             }
630
631             if (intfId != INET_NULL_INTERFACEID)
632                 lwipErr =
633                     udp_sendto_if(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort, intfId);
634             else
635                 lwipErr = udp_sendto(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort);
636         }
637
638         ipX_addr_copy(mUDP->local_ip, boundAddr);
639
640 #endif // INET_CONFIG_ENABLE_IPV4
641 #endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
642
643         if (lwipErr != ERR_OK)
644             res = chip::System::MapErrorLwIP(lwipErr);
645     }
646
647     // Unlock LwIP stack
648     UNLOCK_TCPIP_CORE();
649 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
650
651 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
652
653     // Make sure we have the appropriate type of socket based on the
654     // destination address.
655
656     res = GetSocket(destAddr.Type());
657     SuccessOrExit(res);
658
659     res = IPEndPointBasis::SendMsg(pktInfo, std::move(msg), sendFlags);
660 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
661
662 #if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
663     res = IPEndPointBasis::SendMsg(pktInfo, std::move(msg), sendFlags);
664 #endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
665
666 exit:
667     CHIP_SYSTEM_FAULT_INJECT_ASYNC_EVENT();
668
669     return res;
670 }
671
672 /**
673  * @brief   Bind the endpoint to a network interface.
674  *
675  * @param[in]   addrType    the protocol version of the IP address.
676  *
677  * @param[in]   intfId      indicator of the network interface.
678  *
679  * @retval  INET_NO_ERROR               success: endpoint bound to address
680  * @retval  INET_NO_MEMORY              insufficient memory for endpoint
681  * @retval  INET_ERROR_NOT_IMPLEMENTED  system implementation not complete.
682  *
683  * @retval  INET_ERROR_UNKNOWN_INTERFACE
684  *      On some platforms, the interface is not present.
685  *
686  * @retval  other                   another system or platform error
687  *
688  * @details
689  *  Binds the endpoint to the specified network interface IP address.
690  *
691  *  On LwIP, this method must not be called with the LwIP stack lock
692  *  already acquired.
693  */
694 INET_ERROR UDPEndPoint::BindInterface(IPAddressType addrType, InterfaceId intfId)
695 {
696     INET_ERROR err = INET_NO_ERROR;
697
698     if (mState != kState_Ready && mState != kState_Bound)
699         return INET_ERROR_INCORRECT_STATE;
700
701 #if CHIP_SYSTEM_CONFIG_USE_LWIP
702
703     // A lock is required because the LwIP thread may be referring to intf_filter,
704     // while this code running in the Inet application is potentially modifying it.
705     // NOTE: this only supports LwIP interfaces whose number is no bigger than 9.
706     LOCK_TCPIP_CORE();
707
708     // Make sure we have the appropriate type of PCB.
709     err = GetPCB(addrType);
710     SuccessOrExit(err);
711
712     err = LwIPBindInterface(mUDP, intfId);
713
714     UNLOCK_TCPIP_CORE();
715
716     SuccessOrExit(err);
717
718 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
719
720 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
721     // Make sure we have the appropriate type of socket.
722     err = GetSocket(addrType);
723     SuccessOrExit(err);
724
725     err = IPEndPointBasis::BindInterface(addrType, intfId);
726     SuccessOrExit(err);
727 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
728
729 #if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
730     err = INET_ERROR_UNKNOWN_INTERFACE;
731     SuccessOrExit(err);
732 #endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
733
734     if (err == INET_NO_ERROR)
735     {
736         mState = kState_Bound;
737     }
738 exit:
739     return err;
740 }
741
742 void UDPEndPoint::Init(InetLayer * inetLayer)
743 {
744     IPEndPointBasis::Init(inetLayer);
745 }
746
747 /**
748  * Get the bound interface on this endpoint.
749  *
750  * @return InterfaceId   The bound interface id.
751  */
752 InterfaceId UDPEndPoint::GetBoundInterface()
753 {
754 #if CHIP_SYSTEM_CONFIG_USE_LWIP
755 #if HAVE_LWIP_UDP_BIND_NETIF
756     return netif_get_by_index(mUDP->netif_idx);
757 #else
758     return mUDP->intf_filter;
759 #endif
760 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
761
762 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
763     return mBoundIntfId;
764 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
765
766 #if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
767     return INET_NULL_INTERFACEID;
768 #endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
769 }
770
771 uint16_t UDPEndPoint::GetBoundPort()
772 {
773 #if CHIP_SYSTEM_CONFIG_USE_LWIP
774     return mUDP->local_port;
775 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
776
777 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
778     return mBoundPort;
779 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
780
781 #if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
782     nw_endpoint_t endpoint = nw_parameters_copy_local_endpoint(mParameters);
783     return nw_endpoint_get_port(endpoint);
784 #endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
785 }
786
787 #if CHIP_SYSTEM_CONFIG_USE_LWIP
788
789 void UDPEndPoint::HandleDataReceived(System::PacketBufferHandle && msg)
790 {
791     IPEndPointBasis::HandleDataReceived(std::move(msg));
792 }
793
794 INET_ERROR UDPEndPoint::GetPCB(IPAddressType addrType)
795 {
796     INET_ERROR err = INET_NO_ERROR;
797
798     // IMPORTANT: This method MUST be called with the LwIP stack LOCKED!
799
800     // If a PCB hasn't been allocated yet...
801     if (mUDP == NULL)
802     {
803         // Allocate a PCB of the appropriate type.
804         if (addrType == kIPAddressType_IPv6)
805         {
806 #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
807             mUDP = udp_new_ip_type(IPADDR_TYPE_V6);
808 #else  // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5
809             mUDP = udp_new_ip6();
810 #endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
811         }
812 #if INET_CONFIG_ENABLE_IPV4
813         else if (addrType == kIPAddressType_IPv4)
814         {
815 #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
816             mUDP = udp_new_ip_type(IPADDR_TYPE_V4);
817 #else  // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5
818             mUDP = udp_new();
819 #endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
820         }
821 #endif // INET_CONFIG_ENABLE_IPV4
822         else
823         {
824             ExitNow(err = INET_ERROR_WRONG_ADDRESS_TYPE);
825         }
826
827         // Fail if the system has run out of PCBs.
828         if (mUDP == NULL)
829         {
830             ChipLogError(Inet, "Unable to allocate UDP PCB");
831             ExitNow(err = INET_ERROR_NO_MEMORY);
832         }
833
834         // Allow multiple bindings to the same port.
835         ip_set_option(mUDP, SOF_REUSEADDR);
836     }
837
838     // Otherwise, verify that the existing PCB is the correct type...
839     else
840     {
841         IPAddressType pcbAddrType;
842
843         // Get the address type of the existing PCB.
844 #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
845         switch (static_cast<lwip_ip_addr_type>(IP_GET_TYPE(&mUDP->local_ip)))
846         {
847         case IPADDR_TYPE_V6:
848             pcbAddrType = kIPAddressType_IPv6;
849             break;
850 #if INET_CONFIG_ENABLE_IPV4
851         case IPADDR_TYPE_V4:
852             pcbAddrType = kIPAddressType_IPv4;
853             break;
854 #endif // INET_CONFIG_ENABLE_IPV4
855         default:
856             ExitNow(err = INET_ERROR_WRONG_ADDRESS_TYPE);
857         }
858 #else // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5
859 #if INET_CONFIG_ENABLE_IPV4
860         pcbAddrType = PCB_ISIPV6(mUDP) ? kIPAddressType_IPv6 : kIPAddressType_IPv4;
861 #else  // !INET_CONFIG_ENABLE_IPV4
862         pcbAddrType = kIPAddressType_IPv6;
863 #endif // !INET_CONFIG_ENABLE_IPV4
864 #endif // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5
865
866         // Fail if the existing PCB is not the correct type.
867         VerifyOrExit(addrType == pcbAddrType, err = INET_ERROR_WRONG_ADDRESS_TYPE);
868     }
869
870 exit:
871     return err;
872 }
873
874 #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
875 void UDPEndPoint::LwIPReceiveUDPMessage(void * arg, struct udp_pcb * pcb, struct pbuf * p, const ip_addr_t * addr, u16_t port)
876 #else  // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5
877 void UDPEndPoint::LwIPReceiveUDPMessage(void * arg, struct udp_pcb * pcb, struct pbuf * p, ip_addr_t * addr, u16_t port)
878 #endif // LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
879 {
880     UDPEndPoint * ep                   = static_cast<UDPEndPoint *>(arg);
881     chip::System::Layer & lSystemLayer = ep->SystemLayer();
882     IPPacketInfo * pktInfo             = NULL;
883     System::PacketBufferHandle buf     = System::PacketBufferHandle::Adopt(p);
884
885     pktInfo = GetPacketInfo(buf);
886     if (pktInfo != NULL)
887     {
888 #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
889         pktInfo->SrcAddress  = IPAddress::FromLwIPAddr(*addr);
890         pktInfo->DestAddress = IPAddress::FromLwIPAddr(*ip_current_dest_addr());
891 #else // LWIP_VERSION_MAJOR <= 1
892         if (PCB_ISIPV6(pcb))
893         {
894             pktInfo->SrcAddress = IPAddress::FromIPv6(*(ip6_addr_t *) addr);
895             pktInfo->DestAddress = IPAddress::FromIPv6(*ip6_current_dest_addr());
896         }
897 #if INET_CONFIG_ENABLE_IPV4
898         else
899         {
900             pktInfo->SrcAddress = IPAddress::FromIPv4(*addr);
901             pktInfo->DestAddress = IPAddress::FromIPv4(*ip_current_dest_addr());
902         }
903 #endif // INET_CONFIG_ENABLE_IPV4
904 #endif // LWIP_VERSION_MAJOR <= 1
905
906         pktInfo->Interface = ip_current_netif();
907         pktInfo->SrcPort   = port;
908         pktInfo->DestPort  = pcb->local_port;
909     }
910
911     PostPacketBufferEvent(lSystemLayer, *ep, kInetEvent_UDPDataReceived, std::move(buf));
912 }
913
914 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
915
916 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
917 INET_ERROR UDPEndPoint::GetSocket(IPAddressType aAddressType)
918 {
919     INET_ERROR lRetval  = INET_NO_ERROR;
920     const int lType     = (SOCK_DGRAM | SOCK_FLAGS);
921     const int lProtocol = 0;
922
923     lRetval = IPEndPointBasis::GetSocket(aAddressType, lType, lProtocol);
924     SuccessOrExit(lRetval);
925
926 exit:
927     return (lRetval);
928 }
929
930 SocketEvents UDPEndPoint::PrepareIO()
931 {
932     return (IPEndPointBasis::PrepareIO());
933 }
934
935 void UDPEndPoint::HandlePendingIO()
936 {
937     if (mState == kState_Listening && OnMessageReceived != nullptr && mPendingIO.IsReadable())
938     {
939         const uint16_t lPort = mBoundPort;
940
941         IPEndPointBasis::HandlePendingIO(lPort);
942     }
943
944     mPendingIO.Clear();
945 }
946
947 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
948
949 } // namespace Inet
950 } // namespace chip