Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 24 May 2019 06:27:12 +0000 (UTC)
From:      Gleb Smirnoff <glebius@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r348230 - in stable/12: share/man/man4 sys/netinet
Message-ID:  <201905240627.x4O6RCHe052946@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: glebius
Date: Fri May 24 06:27:11 2019
New Revision: 348230
URL: https://svnweb.freebsd.org/changeset/base/348230

Log:
  Merge r344481:
    Support struct ip_mreqn as argument for IP_ADD_MEMBERSHIP. Legacy support
    for struct ip_mreq remains in place.
  
    The struct ip_mreqn is Linux extension to classic BSD multicast API. It
    has extra field allowing to specify the interface index explicitly. In
    Linux it used as argument for IP_MULTICAST_IF and IP_ADD_MEMBERSHIP.
    FreeBSD kernel also declares this structure and supports it as argument
    to IP_MULTICAST_IF since r170613. So, we have structure declared but
    not fully supported, this confused third party application configure
    scripts.
  
    Code handling IP_ADD_MEMBERSHIP was mixed together with code for
    IP_ADD_SOURCE_MEMBERSHIP.  Bringing legacy and new structure support
    into the mess would made the "argument switcharoo" intolerable, so
    code was separated into its own switch case clause.

Modified:
  stable/12/share/man/man4/ip.4
  stable/12/sys/netinet/in_mcast.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/share/man/man4/ip.4
==============================================================================
--- stable/12/share/man/man4/ip.4	Fri May 24 06:07:33 2019	(r348229)
+++ stable/12/share/man/man4/ip.4	Fri May 24 06:27:11 2019	(r348230)
@@ -28,7 +28,7 @@
 .\"     @(#)ip.4	8.2 (Berkeley) 11/30/93
 .\" $FreeBSD$
 .\"
-.Dd August 19, 2018
+.Dd February 22, 2019
 .Dt IP 4
 .Os
 .Sh NAME
@@ -571,32 +571,55 @@ To join a multicast group, use the
 .Dv IP_ADD_MEMBERSHIP
 option:
 .Bd -literal
-struct ip_mreq mreq;
-setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
+struct ip_mreqn mreqn;
+setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreqn, sizeof(mreqn));
 .Ed
 .Pp
 where
-.Fa mreq
+.Fa mreqn
 is the following structure:
 .Bd -literal
-struct ip_mreq {
+struct ip_mreqn {
     struct in_addr imr_multiaddr; /* IP multicast address of group */
     struct in_addr imr_interface; /* local IP address of interface */
+    int            imr_ifindex;   /* interface index */
 }
 .Ed
 .Pp
-.Va imr_interface
-should be set to the
-.Tn IP
-address of a particular multicast-capable interface if
+.Va imr_ifindex
+should be set to the index of a particular multicast-capable interface if
 the host is multihomed.
-It may be set to
-.Dv INADDR_ANY
-to choose the default interface, although this is not recommended;
-this is considered to be the first interface corresponding
-to the default route.
-Otherwise, the first multicast-capable interface
-configured in the system will be used.
+If
+.Va imr_ifindex
+is non-zero, value of
+.Va imr_interface
+is ignored.
+Otherwise, if
+.Va imr_ifindex
+is 0, kernel will use IP address from
+.Va imr_interface
+to lookup the interface.
+Value of
+.Va imr_interface
+may be set to
+.Va INADDR_ANY
+to choose the default interface, although this is not recommended; this is
+considered to be the first interface corresponding to the default route.
+Otherwise, the first multicast-capable interface configured in the system
+will be used.
+.Pp
+Legacy
+.Vt "struct ip_mreq" ,
+that lacks
+.Va imr_ifindex
+field is also supported by
+.Dv IP_ADD_MEMBERSHIP
+setsockopt.
+In this case kernel would behave as if
+.Va imr_ifindex
+was set to zero:
+.Va imr_interface
+will be used to lookup interface.
 .Pp
 Prior to
 .Fx 7.0 ,

Modified: stable/12/sys/netinet/in_mcast.c
==============================================================================
--- stable/12/sys/netinet/in_mcast.c	Fri May 24 06:07:33 2019	(r348229)
+++ stable/12/sys/netinet/in_mcast.c	Fri May 24 06:27:11 2019	(r348230)
@@ -2046,40 +2046,49 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt
 	ssa->ss.ss_family = AF_UNSPEC;
 
 	switch (sopt->sopt_name) {
-	case IP_ADD_MEMBERSHIP:
-	case IP_ADD_SOURCE_MEMBERSHIP: {
-		struct ip_mreq_source	 mreqs;
+	case IP_ADD_MEMBERSHIP: {
+		struct ip_mreqn mreqn;
 
-		if (sopt->sopt_name == IP_ADD_MEMBERSHIP) {
-			error = sooptcopyin(sopt, &mreqs,
-			    sizeof(struct ip_mreq),
-			    sizeof(struct ip_mreq));
-			/*
-			 * Do argument switcharoo from ip_mreq into
-			 * ip_mreq_source to avoid using two instances.
-			 */
-			mreqs.imr_interface = mreqs.imr_sourceaddr;
-			mreqs.imr_sourceaddr.s_addr = INADDR_ANY;
-		} else if (sopt->sopt_name == IP_ADD_SOURCE_MEMBERSHIP) {
-			error = sooptcopyin(sopt, &mreqs,
-			    sizeof(struct ip_mreq_source),
-			    sizeof(struct ip_mreq_source));
-		}
+		if (sopt->sopt_valsize == sizeof(struct ip_mreqn))
+			error = sooptcopyin(sopt, &mreqn,
+			    sizeof(struct ip_mreqn), sizeof(struct ip_mreqn));
+		else
+			error = sooptcopyin(sopt, &mreqn,
+			    sizeof(struct ip_mreq), sizeof(struct ip_mreq));
 		if (error)
 			return (error);
 
 		gsa->sin.sin_family = AF_INET;
 		gsa->sin.sin_len = sizeof(struct sockaddr_in);
-		gsa->sin.sin_addr = mreqs.imr_multiaddr;
+		gsa->sin.sin_addr = mreqn.imr_multiaddr;
+		if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
+			return (EINVAL);
 
-		if (sopt->sopt_name == IP_ADD_SOURCE_MEMBERSHIP) {
-			ssa->sin.sin_family = AF_INET;
-			ssa->sin.sin_len = sizeof(struct sockaddr_in);
-			ssa->sin.sin_addr = mreqs.imr_sourceaddr;
-		}
+		if (sopt->sopt_valsize == sizeof(struct ip_mreqn) &&
+		    mreqn.imr_ifindex != 0)
+			ifp = ifnet_byindex(mreqn.imr_ifindex);
+		else
+			ifp = inp_lookup_mcast_ifp(inp, &gsa->sin,
+			    mreqn.imr_address);
+		break;
+	}
+	case IP_ADD_SOURCE_MEMBERSHIP: {
+		struct ip_mreq_source	 mreqs;
 
+		error = sooptcopyin(sopt, &mreqs, sizeof(struct ip_mreq_source),
+			    sizeof(struct ip_mreq_source));
+		if (error)
+			return (error);
+
+		gsa->sin.sin_family = ssa->sin.sin_family = AF_INET;
+		gsa->sin.sin_len = ssa->sin.sin_len =
+		    sizeof(struct sockaddr_in);
+
+		gsa->sin.sin_addr = mreqs.imr_multiaddr;
 		if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
 			return (EINVAL);
+
+		ssa->sin.sin_addr = mreqs.imr_sourceaddr;
 
 		ifp = inp_lookup_mcast_ifp(inp, &gsa->sin,
 		    mreqs.imr_interface);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201905240627.x4O6RCHe052946>