summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorbms <bms@FreeBSD.org>2007-07-09 10:36:47 +0000
committerbms <bms@FreeBSD.org>2007-07-09 10:36:47 +0000
commit73f66e3d099a10e58aa871eaa8f7fd964a3bc288 (patch)
tree940a10664e03182d81af18435e890808935e19d4 /sys
parent4cd173a329dbe3f4d052194878a5a7c266bd9173 (diff)
downloadFreeBSD-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)
Diffstat (limited to 'sys')
-rw-r--r--sys/netinet/in_mcast.c37
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) {
OpenPOWER on IntegriCloud