@@ -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+ */
296313INET_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+ */
369413INET_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+ */
433504INET_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
799883exit:
800- return (lRetval );
884+ return (res );
801885}
802886
803887INET_ERROR IPEndPointBasis::GetSocket(IPAddressType aAddressType, int aType, int aProtocol)
0 commit comments