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

Commit f83b6ce

Browse files
author
Jay Logue
authored
Merge pull request #381 from openweave/feature/udp-source-addr-control
Support for UDP source address control
2 parents e20cf9f + 7b5c065 commit f83b6ce

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)