svn commit: r344481 - in head: share/man/man4 sys/netinet

Gleb Smirnoff glebius at FreeBSD.org
Sat Feb 23 06:03:19 UTC 2019


Author: glebius
Date: Sat Feb 23 06:03:18 2019
New Revision: 344481
URL: https://svnweb.freebsd.org/changeset/base/344481

Log:
  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.
  
  MFC after:	3 months
  Differential Revision:	https://reviews.freebsd.org/D19276

Modified:
  head/share/man/man4/ip.4
  head/sys/netinet/in_mcast.c

Modified: head/share/man/man4/ip.4
==============================================================================
--- head/share/man/man4/ip.4	Sat Feb 23 04:24:44 2019	(r344480)
+++ head/share/man/man4/ip.4	Sat Feb 23 06:03:18 2019	(r344481)
@@ -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: head/sys/netinet/in_mcast.c
==============================================================================
--- head/sys/netinet/in_mcast.c	Sat Feb 23 04:24:44 2019	(r344480)
+++ head/sys/netinet/in_mcast.c	Sat Feb 23 06:03:18 2019	(r344481)
@@ -2049,40 +2049,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);


More information about the svn-src-all mailing list