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