3 * Copyright (c) 2020-2021 Project CHIP Authors
4 * Copyright (c) 2018 Google LLC.
5 * Copyright (c) 2013-2018 Nest Labs, Inc.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
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.
30 #define __APPLE_USE_RFC_3542
31 #include "UDPEndPoint.h"
33 #include "InetFaultInjection.h"
34 #include <inet/InetLayer.h>
36 #include <support/CodeUtils.h>
37 #include <support/logging/CHIPLogging.h>
38 #include <system/SystemFaultInjection.h>
40 #if CHIP_SYSTEM_CONFIG_USE_LWIP
42 #include <lwip/tcpip.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
49 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
50 #include <sys/select.h>
52 #include <sys/socket.h>
53 #endif // HAVE_SYS_SOCKET_H
56 #include <netinet/in.h>
58 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
60 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKET_EXTENSIONS
61 #include "ZephyrSocket.h"
62 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKET_EXTENSIONS
64 #include "arpa-inet-compatibility.h"
69 // SOCK_CLOEXEC not defined on all platforms, e.g. iOS/macOS:
71 #define SOCK_FLAGS SOCK_CLOEXEC
79 chip::System::ObjectPool<UDPEndPoint, INET_CONFIG_NUM_UDP_ENDPOINTS> UDPEndPoint::sPool;
81 #if CHIP_SYSTEM_CONFIG_USE_LWIP
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
88 * udp_bind_netif(aUDP, intfId);
91 static INET_ERROR LwIPBindInterface(struct udp_pcb * aUDP, InterfaceId intfId)
93 INET_ERROR res = INET_NO_ERROR;
95 #if HAVE_LWIP_UDP_BIND_NETIF
96 if (!IsInterfaceIdPresent(intfId))
97 udp_bind_netif(aUDP, NULL);
100 struct netif * netifp = IPEndPointBasis::FindNetifFromInterfaceId(intfId);
103 res = INET_ERROR_UNKNOWN_INTERFACE;
105 udp_bind_netif(aUDP, netifp);
108 if (!IsInterfaceIdPresent(intfId))
109 aUDP->intf_filter = NULL;
112 struct netif * netifp = IPEndPointBasis::FindNetifFromInterfaceId(intfId);
115 res = INET_ERROR_UNKNOWN_INTERFACE;
117 aUDP->intf_filter = netifp;
119 #endif // HAVE_LWIP_UDP_BIND_NETIF
123 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
126 * @brief Bind the endpoint to an interface IP address.
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
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
137 * @retval INET_ERROR_UNKNOWN_INTERFACE
138 * On some platforms, the optionally specified interface is not
141 * @retval INET_ERROR_WRONG_PROTOCOL_TYPE
142 * \c addrType does not match \c IPVer.
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.
148 * @retval other another system or platform error
151 * Binds the endpoint to the specified network interface IP address.
153 * On LwIP, this method must not be called with the LwIP stack lock
156 INET_ERROR UDPEndPoint::Bind(IPAddressType addrType, const IPAddress & addr, uint16_t port, InterfaceId intfId)
158 INET_ERROR res = INET_NO_ERROR;
160 #if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
162 nw_parameters_configure_protocol_block_t configure_tls;
163 nw_parameters_t parameters;
165 #endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
167 if (mState != kState_Ready && mState != kState_Bound)
169 res = INET_ERROR_INCORRECT_STATE;
173 if ((addr != IPAddress::Any) && (addr.Type() != kIPAddressType_Any) && (addr.Type() != addrType))
175 res = INET_ERROR_WRONG_ADDRESS_TYPE;
179 #if CHIP_SYSTEM_CONFIG_USE_LWIP
184 // Make sure we have the appropriate type of PCB.
185 res = GetPCB(addrType);
187 // Bind the PCB to the specified address/port.
188 if (res == INET_NO_ERROR)
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)
200 ip6_addr_t ipv6Addr = addr.ToIPv6();
201 res = chip::System::MapErrorLwIP(udp_bind_ip6(mUDP, &ipv6Addr, port));
203 #if INET_CONFIG_ENABLE_IPV4
204 else if (addrType == kIPAddressType_IPv4)
206 ip4_addr_t ipv4Addr = addr.ToIPv4();
207 res = chip::System::MapErrorLwIP(udp_bind(mUDP, &ipv4Addr, port));
209 #endif // INET_CONFIG_ENABLE_IPV4
211 res = INET_ERROR_WRONG_ADDRESS_TYPE;
212 #endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
215 if (res == INET_NO_ERROR)
217 res = LwIPBindInterface(mUDP, intfId);
225 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
227 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
229 // Make sure we have the appropriate type of socket.
230 res = GetSocket(addrType);
233 res = IPEndPointBasis::Bind(addrType, addr, port, intfId);
237 mBoundIntfId = intfId;
239 // If an ephemeral port was requested, retrieve the actual bound port.
245 struct sockaddr_in in;
246 struct sockaddr_in6 in6;
248 socklen_t boundAddrLen = sizeof(boundAddr);
250 if (getsockname(mSocket, &boundAddr.any, &boundAddrLen) == 0)
252 if (boundAddr.any.sa_family == AF_INET)
254 mBoundPort = ntohs(boundAddr.in.sin_port);
256 else if (boundAddr.any.sa_family == AF_INET6)
258 mBoundPort = ntohs(boundAddr.in6.sin6_port);
263 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
265 #if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
267 if (intfId != INET_NULL_INTERFACEID)
269 res = INET_ERROR_NOT_IMPLEMENTED;
273 configure_tls = NW_PARAMETERS_DISABLE_PROTOCOL;
274 parameters = nw_parameters_create_secure_udp(configure_tls, NW_PARAMETERS_DEFAULT_CONFIGURATION);
276 res = IPEndPointBasis::Bind(addrType, addr, port, parameters);
279 mParameters = parameters;
281 #endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
283 if (res == INET_NO_ERROR)
285 mState = kState_Bound;
293 * @brief Prepare the endpoint to receive UDP messages.
295 * @retval INET_NO_ERROR success: endpoint ready to receive messages.
296 * @retval INET_ERROR_INCORRECT_STATE endpoint is already listening.
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.
304 * On LwIP, this method must not be called with the LwIP stack lock
307 INET_ERROR UDPEndPoint::Listen()
309 INET_ERROR res = INET_NO_ERROR;
311 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
312 chip::System::Layer & lSystemLayer = SystemLayer();
313 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
315 if (mState == kState_Listening)
321 if (mState != kState_Bound)
323 res = INET_ERROR_INCORRECT_STATE;
327 #if CHIP_SYSTEM_CONFIG_USE_LWIP
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);
338 udp_recv(mUDP, LwIPReceiveUDPMessage, this);
339 #endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
344 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
346 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
348 // Wake the thread calling select so that it starts selecting on the new socket.
349 lSystemLayer.WakeSelect();
351 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
353 #if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
355 res = StartListener();
358 #endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
360 if (res == INET_NO_ERROR)
362 mState = kState_Listening;
370 * @brief Close the endpoint.
373 * If <tt>mState != kState_Closed</tt>, then closes the endpoint, removing
374 * it from the set of endpoints eligible for communication events.
376 * On LwIP systems, this method must not be called with the LwIP stack
377 * lock already acquired.
379 void UDPEndPoint::Close()
381 if (mState != kState_Closed)
383 #if CHIP_SYSTEM_CONFIG_USE_LWIP
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.
394 mLwIPEndPointType = kLwIPEndPointType_Unknown;
400 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
402 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
404 if (mSocket != INET_INVALID_SOCKET_FD)
406 chip::System::Layer & lSystemLayer = SystemLayer();
408 // Wake the thread calling select so that it recognizes the socket is closed.
409 lSystemLayer.WakeSelect();
412 mSocket = INET_INVALID_SOCKET_FD;
415 // Clear any results from select() that indicate pending I/O for the socket.
418 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
420 #if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
421 IPEndPointBasis::ReleaseAll();
422 #endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
424 mState = kState_Closed;
429 * @brief Close the endpoint and recycle its memory.
432 * Invokes the \c Close method, then invokes the
433 * <tt>InetLayerBasis::Release</tt> method to return the object to its
436 * On LwIP systems, this method must not be called with the LwIP stack
437 * lock already acquired.
439 void UDPEndPoint::Free()
443 #if CHIP_SYSTEM_CONFIG_USE_LWIP
444 DeferredFree(kReleaseDeferralErrorTactic_Die);
445 #else // !CHIP_SYSTEM_CONFIG_USE_LWIP
447 #endif // !CHIP_SYSTEM_CONFIG_USE_LWIP
451 * A synonym for <tt>SendTo(addr, port, INET_NULL_INTERFACEID, msg, sendFlags)</tt>.
453 INET_ERROR UDPEndPoint::SendTo(const IPAddress & addr, uint16_t port, chip::System::PacketBufferHandle && msg, uint16_t sendFlags)
455 return SendTo(addr, port, INET_NULL_INTERFACEID, std::move(msg), sendFlags);
459 * @brief Send a UDP message to the specified destination address.
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
467 * @retval INET_NO_ERROR success: \c msg is queued for transmit.
469 * @retval INET_ERROR_NOT_SUPPORTED
470 * the system does not support the requested operation.
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.
476 * @retval INET_ERROR_MESSAGE_TOO_LONG
477 * \c msg does not contain the whole UDP message.
479 * @retval INET_ERROR_OUTBOUND_MESSAGE_TRUNCATED
480 * On some platforms, only a truncated portion of \c msg was queued
484 * another system or platform error
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.
492 INET_ERROR UDPEndPoint::SendTo(const IPAddress & addr, uint16_t port, InterfaceId intfId, chip::System::PacketBufferHandle && msg,
495 IPPacketInfo pktInfo;
497 pktInfo.DestAddress = addr;
498 pktInfo.DestPort = port;
499 pktInfo.Interface = intfId;
500 return SendMsg(&pktInfo, std::move(msg), sendFlags);
504 * @brief Send a UDP message to a specified destination.
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
510 * @retval INET_NO_ERROR
511 * success: \c msg is queued for transmit.
513 * @retval INET_ERROR_NOT_SUPPORTED
514 * the system does not support the requested operation.
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.
520 * @retval INET_ERROR_MESSAGE_TOO_LONG
521 * \c msg does not contain the whole UDP message.
523 * @retval INET_ERROR_OUTBOUND_MESSAGE_TRUNCATED
524 * On some platforms, only a truncated portion of \c msg was queued
528 * another system or platform error
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.
536 INET_ERROR UDPEndPoint::SendMsg(const IPPacketInfo * pktInfo, System::PacketBufferHandle msg, uint16_t sendFlags)
538 INET_ERROR res = INET_NO_ERROR;
539 const IPAddress & destAddr = pktInfo->DestAddress;
541 INET_FAULT_INJECT(FaultInjection::kFault_Send, return INET_ERROR_UNKNOWN_INTERFACE;);
542 INET_FAULT_INJECT(FaultInjection::kFault_SendNonCritical, return INET_ERROR_NO_MEMORY;);
544 #if CHIP_SYSTEM_CONFIG_USE_LWIP
546 if (!msg.HasSoleOwnership())
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);
560 // Make sure we have the appropriate type of PCB based on the destination address.
561 res = GetPCB(destAddr.Type());
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.
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;
576 #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
578 ip_addr_t lwipSrcAddr = srcAddr.ToLwIPAddr();
579 ip_addr_t lwipDestAddr = destAddr.ToLwIPAddr();
582 ip_addr_copy(boundAddr, mUDP->local_ip);
584 if (!ip_addr_isany(&lwipSrcAddr))
586 ip_addr_copy(mUDP->local_ip, lwipSrcAddr);
589 if (intfId != INET_NULL_INTERFACEID)
590 lwipErr = udp_sendto_if(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort, intfId);
592 lwipErr = udp_sendto(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort);
594 ip_addr_copy(mUDP->local_ip, boundAddr);
596 #else // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5
598 ipX_addr_t boundAddr;
599 ipX_addr_copy(boundAddr, mUDP->local_ip);
601 if (PCB_ISIPV6(mUDP))
603 ip6_addr_t lwipSrcAddr = srcAddr.ToIPv6();
604 ip6_addr_t lwipDestAddr = destAddr.ToIPv6();
606 if (!ip6_addr_isany(&lwipSrcAddr))
608 ipX_addr_copy(mUDP->local_ip, *ip6_2_ipX(&lwipSrcAddr));
611 if (intfId != INET_NULL_INTERFACEID)
613 udp_sendto_if_ip6(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort, intfId);
615 lwipErr = udp_sendto_ip6(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort);
618 #if INET_CONFIG_ENABLE_IPV4
622 ip4_addr_t lwipSrcAddr = srcAddr.ToIPv4();
623 ip4_addr_t lwipDestAddr = destAddr.ToIPv4();
624 ipX_addr_t boundAddr;
626 if (!ip_addr_isany(&lwipSrcAddr))
628 ipX_addr_copy(mUDP->local_ip, *ip_2_ipX(&lwipSrcAddr));
631 if (intfId != INET_NULL_INTERFACEID)
633 udp_sendto_if(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort, intfId);
635 lwipErr = udp_sendto(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort);
638 ipX_addr_copy(mUDP->local_ip, boundAddr);
640 #endif // INET_CONFIG_ENABLE_IPV4
641 #endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
643 if (lwipErr != ERR_OK)
644 res = chip::System::MapErrorLwIP(lwipErr);
649 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
651 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
653 // Make sure we have the appropriate type of socket based on the
654 // destination address.
656 res = GetSocket(destAddr.Type());
659 res = IPEndPointBasis::SendMsg(pktInfo, std::move(msg), sendFlags);
660 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
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
667 CHIP_SYSTEM_FAULT_INJECT_ASYNC_EVENT();
673 * @brief Bind the endpoint to a network interface.
675 * @param[in] addrType the protocol version of the IP address.
677 * @param[in] intfId indicator of the network interface.
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.
683 * @retval INET_ERROR_UNKNOWN_INTERFACE
684 * On some platforms, the interface is not present.
686 * @retval other another system or platform error
689 * Binds the endpoint to the specified network interface IP address.
691 * On LwIP, this method must not be called with the LwIP stack lock
694 INET_ERROR UDPEndPoint::BindInterface(IPAddressType addrType, InterfaceId intfId)
696 INET_ERROR err = INET_NO_ERROR;
698 if (mState != kState_Ready && mState != kState_Bound)
699 return INET_ERROR_INCORRECT_STATE;
701 #if CHIP_SYSTEM_CONFIG_USE_LWIP
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.
708 // Make sure we have the appropriate type of PCB.
709 err = GetPCB(addrType);
712 err = LwIPBindInterface(mUDP, intfId);
718 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
720 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
721 // Make sure we have the appropriate type of socket.
722 err = GetSocket(addrType);
725 err = IPEndPointBasis::BindInterface(addrType, intfId);
727 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
729 #if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
730 err = INET_ERROR_UNKNOWN_INTERFACE;
732 #endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
734 if (err == INET_NO_ERROR)
736 mState = kState_Bound;
742 void UDPEndPoint::Init(InetLayer * inetLayer)
744 IPEndPointBasis::Init(inetLayer);
748 * Get the bound interface on this endpoint.
750 * @return InterfaceId The bound interface id.
752 InterfaceId UDPEndPoint::GetBoundInterface()
754 #if CHIP_SYSTEM_CONFIG_USE_LWIP
755 #if HAVE_LWIP_UDP_BIND_NETIF
756 return netif_get_by_index(mUDP->netif_idx);
758 return mUDP->intf_filter;
760 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
762 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
764 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
766 #if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
767 return INET_NULL_INTERFACEID;
768 #endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
771 uint16_t UDPEndPoint::GetBoundPort()
773 #if CHIP_SYSTEM_CONFIG_USE_LWIP
774 return mUDP->local_port;
775 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
777 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
779 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
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
787 #if CHIP_SYSTEM_CONFIG_USE_LWIP
789 void UDPEndPoint::HandleDataReceived(System::PacketBufferHandle && msg)
791 IPEndPointBasis::HandleDataReceived(std::move(msg));
794 INET_ERROR UDPEndPoint::GetPCB(IPAddressType addrType)
796 INET_ERROR err = INET_NO_ERROR;
798 // IMPORTANT: This method MUST be called with the LwIP stack LOCKED!
800 // If a PCB hasn't been allocated yet...
803 // Allocate a PCB of the appropriate type.
804 if (addrType == kIPAddressType_IPv6)
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
812 #if INET_CONFIG_ENABLE_IPV4
813 else if (addrType == kIPAddressType_IPv4)
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
819 #endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
821 #endif // INET_CONFIG_ENABLE_IPV4
824 ExitNow(err = INET_ERROR_WRONG_ADDRESS_TYPE);
827 // Fail if the system has run out of PCBs.
830 ChipLogError(Inet, "Unable to allocate UDP PCB");
831 ExitNow(err = INET_ERROR_NO_MEMORY);
834 // Allow multiple bindings to the same port.
835 ip_set_option(mUDP, SOF_REUSEADDR);
838 // Otherwise, verify that the existing PCB is the correct type...
841 IPAddressType pcbAddrType;
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)))
848 pcbAddrType = kIPAddressType_IPv6;
850 #if INET_CONFIG_ENABLE_IPV4
852 pcbAddrType = kIPAddressType_IPv4;
854 #endif // INET_CONFIG_ENABLE_IPV4
856 ExitNow(err = INET_ERROR_WRONG_ADDRESS_TYPE);
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
866 // Fail if the existing PCB is not the correct type.
867 VerifyOrExit(addrType == pcbAddrType, err = INET_ERROR_WRONG_ADDRESS_TYPE);
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
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);
885 pktInfo = GetPacketInfo(buf);
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
894 pktInfo->SrcAddress = IPAddress::FromIPv6(*(ip6_addr_t *) addr);
895 pktInfo->DestAddress = IPAddress::FromIPv6(*ip6_current_dest_addr());
897 #if INET_CONFIG_ENABLE_IPV4
900 pktInfo->SrcAddress = IPAddress::FromIPv4(*addr);
901 pktInfo->DestAddress = IPAddress::FromIPv4(*ip_current_dest_addr());
903 #endif // INET_CONFIG_ENABLE_IPV4
904 #endif // LWIP_VERSION_MAJOR <= 1
906 pktInfo->Interface = ip_current_netif();
907 pktInfo->SrcPort = port;
908 pktInfo->DestPort = pcb->local_port;
911 PostPacketBufferEvent(lSystemLayer, *ep, kInetEvent_UDPDataReceived, std::move(buf));
914 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
916 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
917 INET_ERROR UDPEndPoint::GetSocket(IPAddressType aAddressType)
919 INET_ERROR lRetval = INET_NO_ERROR;
920 const int lType = (SOCK_DGRAM | SOCK_FLAGS);
921 const int lProtocol = 0;
923 lRetval = IPEndPointBasis::GetSocket(aAddressType, lType, lProtocol);
924 SuccessOrExit(lRetval);
930 SocketEvents UDPEndPoint::PrepareIO()
932 return (IPEndPointBasis::PrepareIO());
935 void UDPEndPoint::HandlePendingIO()
937 if (mState == kState_Listening && OnMessageReceived != nullptr && mPendingIO.IsReadable())
939 const uint16_t lPort = mBoundPort;
941 IPEndPointBasis::HandlePendingIO(lPort);
947 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS