mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-27 16:39:08 +00:00
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
This commit is contained in:
parent
e806165bee
commit
0dfc145abe
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=344481
@ -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 ,
|
||||
|
@ -2049,41 +2049,50 @@ 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
gsa->sin.sin_addr = mreqn.imr_multiaddr;
|
||||
if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
|
||||
return (EINVAL);
|
||||
|
||||
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);
|
||||
CTR3(KTR_IGMPV3, "%s: imr_interface = 0x%08x, ifp = %p",
|
||||
|
Loading…
Reference in New Issue
Block a user