Skip to content

Commit 0dfc145

Browse files
committed
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
1 parent e806165 commit 0dfc145

File tree

2 files changed

+72
-40
lines changed

2 files changed

+72
-40
lines changed

share/man/man4/ip.4

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
.\" @(#)ip.4 8.2 (Berkeley) 11/30/93
2929
.\" $FreeBSD$
3030
.\"
31-
.Dd August 19, 2018
31+
.Dd February 22, 2019
3232
.Dt IP 4
3333
.Os
3434
.Sh NAME
@@ -571,32 +571,55 @@ To join a multicast group, use the
571571
.Dv IP_ADD_MEMBERSHIP
572572
option:
573573
.Bd -literal
574-
struct ip_mreq mreq;
575-
setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
574+
struct ip_mreqn mreqn;
575+
setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreqn, sizeof(mreqn));
576576
.Ed
577577
.Pp
578578
where
579-
.Fa mreq
579+
.Fa mreqn
580580
is the following structure:
581581
.Bd -literal
582-
struct ip_mreq {
582+
struct ip_mreqn {
583583
struct in_addr imr_multiaddr; /* IP multicast address of group */
584584
struct in_addr imr_interface; /* local IP address of interface */
585+
int imr_ifindex; /* interface index */
585586
}
586587
.Ed
587588
.Pp
588-
.Va imr_interface
589-
should be set to the
590-
.Tn IP
591-
address of a particular multicast-capable interface if
589+
.Va imr_ifindex
590+
should be set to the index of a particular multicast-capable interface if
592591
the host is multihomed.
593-
It may be set to
594-
.Dv INADDR_ANY
595-
to choose the default interface, although this is not recommended;
596-
this is considered to be the first interface corresponding
597-
to the default route.
598-
Otherwise, the first multicast-capable interface
599-
configured in the system will be used.
592+
If
593+
.Va imr_ifindex
594+
is non-zero, value of
595+
.Va imr_interface
596+
is ignored.
597+
Otherwise, if
598+
.Va imr_ifindex
599+
is 0, kernel will use IP address from
600+
.Va imr_interface
601+
to lookup the interface.
602+
Value of
603+
.Va imr_interface
604+
may be set to
605+
.Va INADDR_ANY
606+
to choose the default interface, although this is not recommended; this is
607+
considered to be the first interface corresponding to the default route.
608+
Otherwise, the first multicast-capable interface configured in the system
609+
will be used.
610+
.Pp
611+
Legacy
612+
.Vt "struct ip_mreq" ,
613+
that lacks
614+
.Va imr_ifindex
615+
field is also supported by
616+
.Dv IP_ADD_MEMBERSHIP
617+
setsockopt.
618+
In this case kernel would behave as if
619+
.Va imr_ifindex
620+
was set to zero:
621+
.Va imr_interface
622+
will be used to lookup interface.
600623
.Pp
601624
Prior to
602625
.Fx 7.0 ,

sys/netinet/in_mcast.c

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2049,41 +2049,50 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt)
20492049
ssa->ss.ss_family = AF_UNSPEC;
20502050

20512051
switch (sopt->sopt_name) {
2052-
case IP_ADD_MEMBERSHIP:
2053-
case IP_ADD_SOURCE_MEMBERSHIP: {
2054-
struct ip_mreq_source mreqs;
2052+
case IP_ADD_MEMBERSHIP: {
2053+
struct ip_mreqn mreqn;
20552054

2056-
if (sopt->sopt_name == IP_ADD_MEMBERSHIP) {
2057-
error = sooptcopyin(sopt, &mreqs,
2058-
sizeof(struct ip_mreq),
2059-
sizeof(struct ip_mreq));
2060-
/*
2061-
* Do argument switcharoo from ip_mreq into
2062-
* ip_mreq_source to avoid using two instances.
2063-
*/
2064-
mreqs.imr_interface = mreqs.imr_sourceaddr;
2065-
mreqs.imr_sourceaddr.s_addr = INADDR_ANY;
2066-
} else if (sopt->sopt_name == IP_ADD_SOURCE_MEMBERSHIP) {
2067-
error = sooptcopyin(sopt, &mreqs,
2068-
sizeof(struct ip_mreq_source),
2069-
sizeof(struct ip_mreq_source));
2070-
}
2055+
if (sopt->sopt_valsize == sizeof(struct ip_mreqn))
2056+
error = sooptcopyin(sopt, &mreqn,
2057+
sizeof(struct ip_mreqn), sizeof(struct ip_mreqn));
2058+
else
2059+
error = sooptcopyin(sopt, &mreqn,
2060+
sizeof(struct ip_mreq), sizeof(struct ip_mreq));
20712061
if (error)
20722062
return (error);
20732063

20742064
gsa->sin.sin_family = AF_INET;
20752065
gsa->sin.sin_len = sizeof(struct sockaddr_in);
2076-
gsa->sin.sin_addr = mreqs.imr_multiaddr;
2066+
gsa->sin.sin_addr = mreqn.imr_multiaddr;
2067+
if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
2068+
return (EINVAL);
20772069

2078-
if (sopt->sopt_name == IP_ADD_SOURCE_MEMBERSHIP) {
2079-
ssa->sin.sin_family = AF_INET;
2080-
ssa->sin.sin_len = sizeof(struct sockaddr_in);
2081-
ssa->sin.sin_addr = mreqs.imr_sourceaddr;
2082-
}
2070+
if (sopt->sopt_valsize == sizeof(struct ip_mreqn) &&
2071+
mreqn.imr_ifindex != 0)
2072+
ifp = ifnet_byindex(mreqn.imr_ifindex);
2073+
else
2074+
ifp = inp_lookup_mcast_ifp(inp, &gsa->sin,
2075+
mreqn.imr_address);
2076+
break;
2077+
}
2078+
case IP_ADD_SOURCE_MEMBERSHIP: {
2079+
struct ip_mreq_source mreqs;
2080+
2081+
error = sooptcopyin(sopt, &mreqs, sizeof(struct ip_mreq_source),
2082+
sizeof(struct ip_mreq_source));
2083+
if (error)
2084+
return (error);
20832085

2086+
gsa->sin.sin_family = ssa->sin.sin_family = AF_INET;
2087+
gsa->sin.sin_len = ssa->sin.sin_len =
2088+
sizeof(struct sockaddr_in);
2089+
2090+
gsa->sin.sin_addr = mreqs.imr_multiaddr;
20842091
if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
20852092
return (EINVAL);
20862093

2094+
ssa->sin.sin_addr = mreqs.imr_sourceaddr;
2095+
20872096
ifp = inp_lookup_mcast_ifp(inp, &gsa->sin,
20882097
mreqs.imr_interface);
20892098
CTR3(KTR_IGMPV3, "%s: imr_interface = 0x%08x, ifp = %p",

0 commit comments

Comments
 (0)