Skip to content
This repository was archived by the owner on Dec 20, 2023. It is now read-only.

Commit 7b5c065

Browse files
author
Jay Logue
committed
Support for UDP source address control
-- Modified UDPEndPoint and IPEndPointBasis to allow the source address for an outbound packet to be specified by the sender. Both classes now feature a new SendMsg() method which takes an IPPacketInfo structure containing the destination information (address and port) and, optionally, a source address. (The existing SendTo() methods on UDPEndPoint have been retained for API compatibility). When specified, the source address overrides the normal IP source address selection process performed by the network stack. On sockets based systems, this feature works by passing a IP_PKTINFO/IPV6_PKTINFO "control message" to the kernel. On LwIP, normal source address selection is overridden by temporarily rebinding the local address of the UDP PCB. -- Adjusted RawEndPoint to work with the above changes to IPEndPointBasis and added a SendMsg() method to keep the interface similar to UDPEndPoint (although source address control is not needed for raw end points). -- Moved method documentation into .cpp files to reduce clutter in class definitions.
1 parent d42cdfa commit 7b5c065

File tree

6 files changed

+634
-483
lines changed

6 files changed

+634
-483
lines changed

src/inet/IPEndPointBasis.cpp

Lines changed: 130 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,23 @@ static INET_ERROR SocketsIPv6JoinLeaveMulticastGroup(int aSocket, InterfaceId aI
293293
}
294294
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
295295

296+
/**
297+
* @brief Set whether IP multicast traffic should be looped back.
298+
*
299+
* @param[in] aIPVersion
300+
*
301+
* @param[in] aLoop
302+
*
303+
* @retval INET_NO_ERROR
304+
* success: multicast loopback behavior set
305+
* @retval other
306+
* another system or platform error
307+
*
308+
* @details
309+
* Set whether or not IP multicast traffic should be looped back
310+
* to this endpoint.
311+
*
312+
*/
296313
INET_ERROR IPEndPointBasis::SetMulticastLoopback(IPVersion aIPVersion, bool aLoopback)
297314
{
298315
INET_ERROR lRetval = INET_ERROR_NOT_IMPLEMENTED;
@@ -366,6 +383,33 @@ Please upgrade your version of LwIP for SetMulticastLoopback support."
366383
return (lRetval);
367384
}
368385
386+
/**
387+
* @brief Join an IP multicast group.
388+
*
389+
* @param[in] aInterfaceId the indicator of the network interface to
390+
* add to the multicast group
391+
*
392+
* @param[in] aAddress the multicast group to add the
393+
* interface to
394+
*
395+
* @retval INET_NO_ERROR
396+
* success: multicast group removed
397+
*
398+
* @retval INET_ERROR_UNKNOWN_INTERFACE
399+
* unknown network interface, \c aInterfaceId
400+
*
401+
* @retval INET_ERROR_WRONG_ADDRESS_TYPE
402+
* \c aAddress is not \c kIPAddressType_IPv4 or
403+
* \c kIPAddressType_IPv6 or is not multicast
404+
*
405+
* @retval other
406+
* another system or platform error
407+
*
408+
* @details
409+
* Join the endpoint to the supplied multicast group on the
410+
* specified interface.
411+
*
412+
*/
369413
INET_ERROR IPEndPointBasis::JoinMulticastGroup(InterfaceId aInterfaceId, const IPAddress &aAddress)
370414
{
371415
const IPAddressType lAddrType = aAddress.Type();
@@ -430,6 +474,33 @@ Please enable LWIP_IPV6_MLD && LWIP_IPV6_ND && LWIP_IPV6 for IPv6 JoinMulticastG
430474
return (lRetval);
431475
}
432476
477+
/**
478+
* @brief Leave an IP multicast group.
479+
*
480+
* @param[in] aInterfaceId the indicator of the network interface to
481+
* remove from the multicast group
482+
*
483+
* @param[in] aAddress the multicast group to remove the
484+
* interface from
485+
*
486+
* @retval INET_NO_ERROR
487+
* success: multicast group removed
488+
*
489+
* @retval INET_ERROR_UNKNOWN_INTERFACE
490+
* unknown network interface, \c aInterfaceId
491+
*
492+
* @retval INET_ERROR_WRONG_ADDRESS_TYPE
493+
* \c aAddress is not \c kIPAddressType_IPv4 or
494+
* \c kIPAddressType_IPv6 or is not multicast
495+
*
496+
* @retval other
497+
* another system or platform error
498+
*
499+
* @details
500+
* Remove the endpoint from the supplied multicast group on the
501+
* specified interface.
502+
*
503+
*/
433504
INET_ERROR IPEndPointBasis::LeaveMulticastGroup(InterfaceId aInterfaceId, const IPAddress &aAddress)
434505
{
435506
const IPAddressType lAddrType = aAddress.Type();
@@ -689,17 +760,20 @@ INET_ERROR IPEndPointBasis::BindInterface(IPAddressType aAddressType, InterfaceI
689760
return (lRetval);
690761
}
691762
692-
INET_ERROR IPEndPointBasis::SendTo(const IPAddress &aAddress, uint16_t aPort, InterfaceId aInterfaceId, PacketBuffer *aBuffer, uint16_t aSendFlags)
763+
INET_ERROR IPEndPointBasis::SendMsg(const IPPacketInfo *aPktInfo, Weave::System::PacketBuffer *aBuffer, uint16_t aSendFlags)
693764
{
694-
INET_ERROR lRetval = INET_NO_ERROR;
695-
PeerSockAddr lPeerSockAddr;
765+
INET_ERROR res = INET_NO_ERROR;
766+
PeerSockAddr peerSockAddr;
696767
struct iovec msgIOV;
697768
uint8_t controlData[256];
698769
struct msghdr msgHeader;
770+
InterfaceId intfId = aPktInfo->Interface;
699771
700-
// For now the entire message must fit within a single buffer.
772+
// Ensure the destination address type is compatible with the endpoint address type.
773+
VerifyOrExit(mAddrType == aPktInfo->DestAddress.Type(), res = INET_ERROR_BAD_ARGS);
701774
702-
VerifyOrExit(aBuffer->Next() == NULL, lRetval = INET_ERROR_MESSAGE_TOO_LONG);
775+
// For now the entire message must fit within a single buffer.
776+
VerifyOrExit(aBuffer->Next() == NULL, res = INET_ERROR_MESSAGE_TOO_LONG);
703777
704778
memset(&msgHeader, 0, sizeof (msgHeader));
705779
@@ -708,96 +782,106 @@ INET_ERROR IPEndPointBasis::SendTo(const IPAddress &aAddress, uint16_t aPort, In
708782
msgHeader.msg_iov = &msgIOV;
709783
msgHeader.msg_iovlen = 1;
710784
711-
memset(&lPeerSockAddr, 0, sizeof (lPeerSockAddr));
712-
713-
msgHeader.msg_name = &lPeerSockAddr;
714-
785+
// Construct a sockaddr_in/sockaddr_in6 structure containing the destination information.
786+
memset(&peerSockAddr, 0, sizeof (peerSockAddr));
787+
msgHeader.msg_name = &peerSockAddr;
715788
if (mAddrType == kIPAddressType_IPv6)
716789
{
717-
lPeerSockAddr.in6.sin6_family = AF_INET6;
718-
lPeerSockAddr.in6.sin6_port = htons(aPort);
719-
lPeerSockAddr.in6.sin6_flowinfo = 0;
720-
lPeerSockAddr.in6.sin6_addr = aAddress.ToIPv6();
721-
lPeerSockAddr.in6.sin6_scope_id = aInterfaceId;
722-
msgHeader.msg_namelen = sizeof (sockaddr_in6);
790+
peerSockAddr.in6.sin6_family = AF_INET6;
791+
peerSockAddr.in6.sin6_port = htons(aPktInfo->DestPort);
792+
peerSockAddr.in6.sin6_flowinfo = 0;
793+
peerSockAddr.in6.sin6_addr = aPktInfo->DestAddress.ToIPv6();
794+
peerSockAddr.in6.sin6_scope_id = aPktInfo->Interface;
795+
msgHeader.msg_namelen = sizeof(sockaddr_in6);
723796
}
724797
#if INET_CONFIG_ENABLE_IPV4
725798
else
726799
{
727-
lPeerSockAddr.in.sin_family = AF_INET;
728-
lPeerSockAddr.in.sin_port = htons(aPort);
729-
lPeerSockAddr.in.sin_addr = aAddress.ToIPv4();
730-
msgHeader.msg_namelen = sizeof (sockaddr_in);
800+
peerSockAddr.in.sin_family = AF_INET;
801+
peerSockAddr.in.sin_port = htons(aPktInfo->DestPort);
802+
peerSockAddr.in.sin_addr = aPktInfo->DestAddress.ToIPv4();
803+
msgHeader.msg_namelen = sizeof(sockaddr_in);
731804
}
732805
#endif // INET_CONFIG_ENABLE_IPV4
733806
734807
// If the endpoint has been bound to a particular interface,
735808
// and the caller didn't supply a specific interface to send
736809
// on, use the bound interface. This appears to be necessary
737810
// for messages to multicast addresses, which under Linux
738-
// don't seem to get sent out the correct inferface, despite
811+
// don't seem to get sent out the correct interface, despite
739812
// the socket being bound.
740-
741-
if (aInterfaceId == INET_NULL_INTERFACEID)
742-
aInterfaceId = mBoundIntfId;
743-
744-
if (aInterfaceId != INET_NULL_INTERFACEID)
813+
if (intfId == INET_NULL_INTERFACEID)
814+
intfId = mBoundIntfId;
815+
816+
// If the packet should be sent over a specific interface, or with a specific source
817+
// address, construct an IP_PKTINFO/IPV6_PKTINFO "control message" to that effect
818+
// add add it to the message header. If the local OS doesn't support IP_PKTINFO/IPV6_PKTINFO
819+
// fail with an error.
820+
if (intfId != INET_NULL_INTERFACEID || aPktInfo->SrcAddress.Type() != kIPAddressType_Any)
745821
{
746822
#if defined(IP_PKTINFO) || defined(IPV6_PKTINFO)
747-
memset(controlData, 0, sizeof (controlData));
823+
memset(controlData, 0, sizeof(controlData));
748824
msgHeader.msg_control = controlData;
749-
msgHeader.msg_controllen = sizeof (controlData);
825+
msgHeader.msg_controllen = sizeof(controlData);
750826
751827
struct cmsghdr *controlHdr = CMSG_FIRSTHDR(&msgHeader);
752828
753829
#if INET_CONFIG_ENABLE_IPV4
754-
#if defined(IP_PKTINFO)
830+
755831
if (mAddrType == kIPAddressType_IPv4)
756832
{
833+
#if defined(IP_PKTINFO)
757834
controlHdr->cmsg_level = IPPROTO_IP;
758835
controlHdr->cmsg_type = IP_PKTINFO;
759-
controlHdr->cmsg_len = CMSG_LEN(sizeof (in_pktinfo));
836+
controlHdr->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
760837
761838
struct in_pktinfo *pktInfo = (struct in_pktinfo *)CMSG_DATA(controlHdr);
762-
pktInfo->ipi_ifindex = aInterfaceId;
839+
pktInfo->ipi_ifindex = intfId;
840+
pktInfo->ipi_spec_dst = aPktInfo->SrcAddress.ToIPv4();
763841
764-
msgHeader.msg_controllen = CMSG_SPACE(sizeof (in_pktinfo));
842+
msgHeader.msg_controllen = CMSG_SPACE(sizeof(in_pktinfo));
843+
#else // !defined(IP_PKTINFO)
844+
ExitNow(res = INET_ERROR_NOT_SUPPORTED);
845+
#endif // !defined(IP_PKTINFO)
765846
}
766-
#endif // defined(IP_PKTINFO)
847+
767848
#endif // INET_CONFIG_ENABLE_IPV4
768849
769-
#if defined(IPV6_PKTINFO)
770850
if (mAddrType == kIPAddressType_IPv6)
771851
{
772-
controlHdr->cmsg_level = IPPROTO_IP;
852+
#if defined(IPV6_PKTINFO)
853+
controlHdr->cmsg_level = IPPROTO_IPV6;
773854
controlHdr->cmsg_type = IPV6_PKTINFO;
774-
controlHdr->cmsg_len = CMSG_LEN(sizeof (in6_pktinfo));
855+
controlHdr->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
775856
776857
struct in6_pktinfo *pktInfo = (struct in6_pktinfo *)CMSG_DATA(controlHdr);
777-
pktInfo->ipi6_ifindex = aInterfaceId;
858+
pktInfo->ipi6_ifindex = intfId;
859+
pktInfo->ipi6_addr = aPktInfo->SrcAddress.ToIPv6();
778860
779-
msgHeader.msg_controllen = CMSG_SPACE(sizeof (in6_pktinfo));
861+
msgHeader.msg_controllen = CMSG_SPACE(sizeof(in6_pktinfo));
862+
#else // !defined(IPV6_PKTINFO)
863+
ExitNow(res = INET_ERROR_NOT_SUPPORTED);
864+
#endif // !defined(IPV6_PKTINFO)
780865
}
781-
#endif // defined(IPV6_PKTINFO)
866+
782867
#else // !(defined(IP_PKTINFO) && defined(IPV6_PKTINFO))
783-
lRetval = INET_ERROR_NOT_IMPLEMENTED
868+
869+
ExitNow(res = INET_ERROR_NOT_SUPPORTED);
870+
784871
#endif // !(defined(IP_PKTINFO) && defined(IPV6_PKTINFO))
785872
}
786873
787-
if (lRetval == INET_NO_ERROR)
874+
// Send IP packet.
788875
{
789-
// Send IP packet.
790-
791876
const ssize_t lenSent = sendmsg(mSocket, &msgHeader, 0);
792-
793877
if (lenSent == -1)
794-
lRetval = Weave::System::MapErrorPOSIX(errno);
878+
res = Weave::System::MapErrorPOSIX(errno);
795879
else if (lenSent != aBuffer->DataLength())
796-
lRetval = INET_ERROR_OUTBOUND_MESSAGE_TRUNCATED;
880+
res = INET_ERROR_OUTBOUND_MESSAGE_TRUNCATED;
797881
}
798882
799883
exit:
800-
return (lRetval);
884+
return (res);
801885
}
802886
803887
INET_ERROR IPEndPointBasis::GetSocket(IPAddressType aAddressType, int aType, int aProtocol)

0 commit comments

Comments
 (0)