Page MenuHomeFreeBSD

D55031.diff
No OneTemporary

D55031.diff

diff --git a/sys/netinet/in_mcast.c b/sys/netinet/in_mcast.c
--- a/sys/netinet/in_mcast.c
+++ b/sys/netinet/in_mcast.c
@@ -158,8 +158,6 @@
static struct ip_moptions *
inp_findmoptions(struct inpcb *);
static int inp_get_source_filters(struct inpcb *, struct sockopt *);
-static int inp_join_group(struct inpcb *, struct sockopt *);
-static int inp_leave_group(struct inpcb *, struct sockopt *);
static int inp_block_unblock_source(struct inpcb *, struct sockopt *);
static int inp_set_multicast_if(struct inpcb *, struct sockopt *);
static int inp_set_source_filters(struct inpcb *, struct sockopt *);
@@ -1884,7 +1882,7 @@
/*
* Join an IPv4 multicast group, possibly with a source.
*/
-static int
+int
inp_join_group(struct inpcb *inp, struct sockopt *sopt)
{
struct group_source_req gsr;
@@ -2208,7 +2206,7 @@
/*
* Leave an IPv4 multicast group on an inpcb, possibly with a source.
*/
-static int
+int
inp_leave_group(struct inpcb *inp, struct sockopt *sopt)
{
struct epoch_tracker et;
diff --git a/sys/netinet/in_var.h b/sys/netinet/in_var.h
--- a/sys/netinet/in_var.h
+++ b/sys/netinet/in_var.h
@@ -477,6 +477,11 @@
void in_detachhead(struct rib_head *rh);
#endif
+struct sockopt;
+
+int inp_join_group(struct inpcb *, struct sockopt *);
+int inp_leave_group(struct inpcb *, struct sockopt *);
+
#endif /* _KERNEL */
/* INET6 stuff */
diff --git a/sys/netinet6/in6_mcast.c b/sys/netinet6/in6_mcast.c
--- a/sys/netinet6/in6_mcast.c
+++ b/sys/netinet6/in6_mcast.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
- * Copyright (c) 2009 Bruce Simpson.
+ * Copyright (c) 2009-2026 Bruce Simpson.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,7 @@
* Normative references: RFC 2292, RFC 3492, RFC 3542, RFC 3678, RFC 3810.
*/
+#include "opt_inet.h"
#include "opt_inet6.h"
#include <sys/param.h>
@@ -162,6 +163,9 @@
static int in6p_block_unblock_source(struct inpcb *, struct sockopt *);
static int in6p_set_multicast_if(struct inpcb *, struct sockopt *);
static int in6p_set_source_filters(struct inpcb *, struct sockopt *);
+#ifdef INET
+static int in6_v6_mreq_to_v4(struct ipv6_mreq *, struct ip_mreq *);
+#endif
static int sysctl_ip6_mcast_filters(SYSCTL_HANDLER_ARGS);
SYSCTL_DECL(_net_inet6_ip6); /* XXX Not in any common header. */
@@ -1881,6 +1885,51 @@
return (nh ? nh->nh_ifp : NULL);
}
+#ifdef INET
+/*
+ * Perform sockopt mreq argument conversion for IPv4-mapped groups.
+ *
+ * NOTE: Only required to support an extension to the behaviour in
+ * RFC 3493 Sec 3.7, which is used by OpenJDK and other software
+ * which assumes AF_INET joins are possible on AF_INET6 sockets.
+ * This support is limited to simple ASM mode joins/leaves only.
+ *
+ * FUTURE: Use IPv4 source-address selection.
+ */
+static int
+in6_v6_mreq_to_v4(struct ipv6_mreq *mreq, struct ip_mreq *mreq_v4)
+{
+ int error;
+ struct epoch_tracker et;
+ struct ifnet *ifp;
+ struct in_ifaddr *ia;
+
+ NET_EPOCH_ENTER(et);
+
+ ifp = ifnet_byindex(mreq->ipv6mr_interface);
+ if (ifp == NULL) {
+ error = EADDRNOTAVAIL;
+ goto out;
+ }
+
+ /*
+ * XXX: Allow the primary IP to be 0.0.0.0 for bootstrap;
+ * otherwise, check in_nullhost(ia->ia_addr.sin_addr.s_addr).
+ */
+ IFP_TO_IA(ifp, ia);
+ if (ia == NULL) {
+ error = EADDRNOTAVAIL;
+ goto out;
+ }
+ mreq_v4->imr_interface.s_addr = IA_SIN(ia)->sin_addr.s_addr;
+ error = 0;
+
+out:
+ NET_EPOCH_EXIT(et);
+ return (error);
+}
+#endif /* INET */
+
/*
* Join an IPv6 multicast group, possibly with a source.
*
@@ -1929,6 +1978,33 @@
sizeof(struct ipv6_mreq));
if (error)
return (error);
+#ifdef INET
+ if (IN6_IS_ADDR_V4MAPPED(&mreq.ipv6mr_multiaddr)) {
+ struct ip_mreq mreq_v4;
+ struct sockopt sopt_v4 = {
+ .sopt_dir = SOPT_SET,
+ .sopt_level = sopt->sopt_level,
+ .sopt_name = IP_ADD_MEMBERSHIP,
+ .sopt_val = &mreq_v4,
+ .sopt_valsize = sizeof(mreq_v4),
+ .sopt_rights = sopt->sopt_rights,
+ .sopt_td = sopt->sopt_td
+ };
+
+ mreq_v4.imr_multiaddr.s_addr =
+ mreq.ipv6mr_multiaddr.s6_addr32[3];
+ if (mreq.ipv6mr_interface == 0) {
+ mreq_v4.imr_interface.s_addr = INADDR_ANY;
+ } else {
+ error = in6_v6_mreq_to_v4(&mreq, &mreq_v4);
+ }
+ if (error) {
+ return error;
+ }
+
+ return (inp_join_group(inp, &sopt_v4));
+ }
+#endif /* INET */
gsa->sin6.sin6_family = AF_INET6;
gsa->sin6.sin6_len = sizeof(struct sockaddr_in6);
@@ -2242,6 +2318,33 @@
sizeof(struct ipv6_mreq));
if (error)
return (error);
+#ifdef INET
+ if (IN6_IS_ADDR_V4MAPPED(&mreq.ipv6mr_multiaddr)) {
+ struct ip_mreq mreq_v4;
+ struct sockopt sopt_v4 = {
+ .sopt_dir = SOPT_SET,
+ .sopt_level = sopt->sopt_level,
+ .sopt_name = IP_DROP_MEMBERSHIP,
+ .sopt_val = &mreq_v4,
+ .sopt_valsize = sizeof(mreq_v4),
+ .sopt_rights = sopt->sopt_rights,
+ .sopt_td = sopt->sopt_td
+ };
+
+ mreq_v4.imr_multiaddr.s_addr =
+ mreq.ipv6mr_multiaddr.s6_addr32[3];
+ if (mreq.ipv6mr_interface == 0) {
+ mreq_v4.imr_interface.s_addr = INADDR_ANY;
+ } else {
+ error = in6_v6_mreq_to_v4(&mreq, &mreq_v4);
+ }
+ if (error) {
+ return error;
+ }
+
+ return (inp_leave_group(inp, &sopt_v4));
+ }
+#endif /* INET */
gsa->sin6.sin6_family = AF_INET6;
gsa->sin6.sin6_len = sizeof(struct sockaddr_in6);
gsa->sin6.sin6_addr = mreq.ipv6mr_multiaddr;

File Metadata

Mime Type
text/plain
Expires
Thu, Mar 19, 2:54 AM (13 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29940876
Default Alt Text
D55031.diff (6 KB)

Event Timeline