I forgot to add ip_mreqn support to IP_MULTICAST_IF and so the
IP_ADD_MEMBERSHIP change is not fixing all the issues I have.
Linux supports calling IP_MULTICAST_IF with a struct in_addr, a struct
ip_mreq, or a struct ip_mreqn. FreeBSD only does the first and last.
I followed the Linux way because doing that was not that hard. In the end
only the imr_ifindex field and the imr_address field need to be checked
and if the imr_ifindex is 0 then just use the old code. If the imr_ifindex
is set then use this for interface index and break early.
Any opinions about this?
--
:wq Claudio
Index: netinet/ip_output.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_output.c,v
retrieving revision 1.360
diff -u -p -r1.360 ip_output.c
--- netinet/ip_output.c 11 Jan 2021 13:28:53 -0000 1.360
+++ netinet/ip_output.c 15 Jan 2021 12:20:26 -0000
@@ -1423,11 +1423,40 @@ ip_setmoptions(int optname, struct ip_mo
/*
* Select the interface for outgoing multicast packets.
*/
- if (m == NULL || m->m_len != sizeof(struct in_addr)) {
+ if (m == NULL) {
+ error = EINVAL;
+ break;
+ }
+ if (m->m_len == sizeof(struct in_addr)) {
+ addr = *(mtod(m, struct in_addr *));
+ } else if (m->m_len == sizeof(struct ip_mreq) ||
+ m->m_len == sizeof(struct ip_mreqn)) {
+ memset(&mreqn, 0, sizeof(mreqn));
+ memcpy(&mreqn, mtod(m, void *), m->m_len);
+
+ /*
+ * If an interface index is given use this
+ * index to set the imo_ifidx but check first
+ * that the interface actually exists.
+ * In the other case just set the addr to
+ * the imr_address and fall through to the
+ * regular code.
+ */
+ if (mreqn.imr_ifindex != 0) {
+ ifp = if_get(mreqn.imr_ifindex);
+ if (ifp == NULL) {
+ error = EADDRNOTAVAIL;
+ break;
+ }
+ imo->imo_ifidx = ifp->if_index;
+ if_put(ifp);
+ break;
+ } else
+ addr = mreqn.imr_address;
+ } else {
error = EINVAL;
break;
}
- addr = *(mtod(m, struct in_addr *));
/*
* INADDR_ANY is used to remove a previous selection.
* When no interface is selected, a default one is