diff --git a/include/re_udp.h b/include/re_udp.h index e88557d29..a9bdf9f17 100644 --- a/include/re_udp.h +++ b/include/re_udp.h @@ -45,6 +45,10 @@ re_sock_t udp_sock_fd(const struct udp_sock *us, int af); int udp_multicast_join(struct udp_sock *us, const struct sa *group); int udp_multicast_leave(struct udp_sock *us, const struct sa *group); +int udp_multicast_join_local(struct udp_sock *us, const struct sa *group, + const struct sa *local); +int udp_multicast_leave_local(struct udp_sock *us, const struct sa *group, + const struct sa *local); int udp_settos(struct udp_sock *us, uint8_t tos); void udp_flush(const struct udp_sock *us); void udp_recv_packet(struct udp_sock *us, const struct sa *src, diff --git a/src/udp/mcast.c b/src/udp/mcast.c index d0e9a985b..14c118860 100644 --- a/src/udp/mcast.c +++ b/src/udp/mcast.c @@ -5,25 +5,40 @@ */ #include #include +#include #include #include static int multicast_update(struct udp_sock *us, const struct sa *group, - bool join) + const struct sa *local, bool join) { - struct ip_mreq mreq; + struct ip_mreqn mreq; struct ipv6_mreq mreq6; int err; + int if_index = 0; if (!us || !group) return EINVAL; + if (local && !sa_is_any(local)) { + char name[64]; + if (net_if_getname(name, sizeof(name), sa_af(local), local) != 0) + return EADDRNOTAVAIL; + + if ((if_index = if_nametoindex(name)) == 0) + return ENXIO; + } + + switch (sa_af(group)) { case AF_INET: mreq.imr_multiaddr = group->u.in.sin_addr; - mreq.imr_interface.s_addr = 0; + mreq.imr_ifindex = if_index; + if (if_index == 0) { + mreq.imr_address.s_addr = 0; + } err = udp_setsockopt(us, IPPROTO_IP, join @@ -34,7 +49,10 @@ static int multicast_update(struct udp_sock *us, const struct sa *group, case AF_INET6: mreq6.ipv6mr_multiaddr = group->u.in6.sin6_addr; - mreq6.ipv6mr_interface = sa_scopeid(group); + mreq6.ipv6mr_interface = if_index; + if (if_index = 0) { + mreq6.ipv6mr_interface = sa_scopeid(group); + } err = udp_setsockopt(us, IPPROTO_IPV6, join @@ -50,14 +68,25 @@ static int multicast_update(struct udp_sock *us, const struct sa *group, return err; } - int udp_multicast_join(struct udp_sock *us, const struct sa *group) { - return multicast_update(us, group, true); + return multicast_update(us, group, NULL, true); } int udp_multicast_leave(struct udp_sock *us, const struct sa *group) { - return multicast_update(us, group, false); + return multicast_update(us, group, NULL, false); +} + +int udp_multicast_join_local(struct udp_sock *us, const struct sa *group, + const struct sa *local) +{ + return multicast_update(us, group, local, true); +} + +int udp_multicast_leave_local(struct udp_sock *us, const struct sa *group, + const struct sa *local) +{ + return multicast_update(us, group, local, false); }