diff options
author | bms <bms@FreeBSD.org> | 2007-07-09 10:36:47 +0000 |
---|---|---|
committer | bms <bms@FreeBSD.org> | 2007-07-09 10:36:47 +0000 |
commit | 73f66e3d099a10e58aa871eaa8f7fd964a3bc288 (patch) | |
tree | 940a10664e03182d81af18435e890808935e19d4 | |
parent | 4cd173a329dbe3f4d052194878a5a7c266bd9173 (diff) | |
download | FreeBSD-src-73f66e3d099a10e58aa871eaa8f7fd964a3bc288.zip FreeBSD-src-73f66e3d099a10e58aa871eaa8f7fd964a3bc288.tar.gz |
Fix a regression in IPv4 multicast join path (IP_ADD_MEMBERSHIP).
With the in_mcast.c code, if an interface for an IPv4 multicast join was
not specified, and a route did not exist for the specified group in the
unicast forwarding tables, the join would be rejected with the error
EADDRNOTAVAIL.
This change restores the old behaviour whereby if no interface is specified,
and no route exists for the group destination, the IPv4 address list is
walked to find a non-loopback, multicast-capable interface to satisfy
the join request.
This should resolve problems with starting multicast services during
system boot or when a default forwarding entry does not exist.
Approved by: re (rwatson)
-rw-r--r-- | sys/netinet/in_mcast.c | 37 |
1 files changed, 26 insertions, 11 deletions
diff --git a/sys/netinet/in_mcast.c b/sys/netinet/in_mcast.c index 0f0dc2d..4995800 100644 --- a/sys/netinet/in_mcast.c +++ b/sys/netinet/in_mcast.c @@ -996,8 +996,16 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) /* * Obtain ifp. If no interface address was provided, - * use the interface of the route to the given multicast - * address (usually this is the default route). + * use the interface of the route in the unicast FIB for + * the given multicast destination; usually, this is the + * default route. + * If this lookup fails, attempt to use the first non-loopback + * interface with multicast capability in the system as a + * last resort. The legacy IPv4 ASM API requires that we do + * this in order to allow groups to be joined when the routing + * table has not yet been populated during boot. + * If all of these conditions fail, return EADDRNOTAVAIL, and + * reject the IPv4 multicast join. */ if (mreqs.imr_interface.s_addr != INADDR_ANY) { INADDR_TO_IFP(mreqs.imr_interface, ifp); @@ -1007,16 +1015,23 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) ro.ro_rt = NULL; *(struct sockaddr_in *)&ro.ro_dst = gsa->sin; rtalloc_ign(&ro, RTF_CLONING); - if (ro.ro_rt == NULL) { -#ifdef DIAGNOSTIC - printf("%s: no route to %s\n", __func__, - inet_ntoa(gsa->sin.sin_addr)); -#endif - return (EADDRNOTAVAIL); + if (ro.ro_rt != NULL) { + ifp = ro.ro_rt->rt_ifp; + KASSERT(ifp != NULL, ("%s: null ifp", + __func__)); + RTFREE(ro.ro_rt); + } else { + struct in_ifaddr *ia; + struct ifnet *mfp = NULL; + TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { + mfp = ia->ia_ifp; + if (!(mfp->if_flags & IFF_LOOPBACK) && + (mfp->if_flags & IFF_MULTICAST)) { + ifp = mfp; + break; + } + } } - ifp = ro.ro_rt->rt_ifp; - KASSERT(ifp != NULL, ("%s: null ifp", __func__)); - RTFREE(ro.ro_rt); } #ifdef DIAGNOSTIC if (bootverbose) { |