Re: ip6 multicast router lock
Alexander Bluhm <[email protected]> Wed, 5 Aug 2026 23:52:03 +0200
| Newsgroups | gmane.os.openbsd.tech |
|---|---|
| Message-ID | <[email protected]> |
On Thu, Jul 16, 2026 at 11:28:05PM +0200, Alexander Bluhm wrote:
> Hi,
>
> This is the IPv6 counter part of my multicast router locking diff.
> The IPv4 part tries to make both families similar.
>
> Also fix checking the return code of mfc_add().
>
> Unlocking is not completed yet, netlock and kernel lock stay.
>
> ok?
anyone?
Index: netinet/ip_mroute.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_mroute.c,v
diff -u -p -r1.154 ip_mroute.c
--- netinet/ip_mroute.c 16 Jul 2026 12:21:40 -0000 1.154
+++ netinet/ip_mroute.c 5 Aug 2026 13:42:56 -0000
@@ -116,7 +116,6 @@ int ip_mrtproto = IGMP_DVMRP; /* [I] f
struct cpumem *mrtcounters;
-struct rtentry *mfc_find(struct ifnet *, struct in_addr *, unsigned int);
int get_sg_cnt(unsigned int, struct sioc_sg_req *);
int get_vif_cnt(unsigned int, struct sioc_vif_req *);
int mrt_rtwalk_mfcsysctl(struct rtentry *, void *, unsigned int);
@@ -126,7 +125,6 @@ int get_version(struct mbuf *);
int add_vif(struct socket *, struct mbuf *);
int del_vif(struct socket *, struct mbuf *);
void update_mfc_params(struct mfcctl2 *, int, unsigned int);
-void mfc_expire_route(struct rtentry *, u_int);
int mfc_add(struct mfcctl2 *, struct in_addr *, struct in_addr *,
int, unsigned int, int);
int add_mfc(struct socket *, struct mbuf *);
@@ -136,7 +134,9 @@ int get_api_support(struct mbuf *);
int get_api_config(struct socket *, struct mbuf *);
int socket_send(struct socket *, struct mbuf *, struct sockaddr_in *);
int ip_mdq(struct mbuf *, struct ifnet *, struct rtentry *, int);
+void mfc_expire_route(struct rtentry *, u_int);
struct ifnet *if_lookupbyvif(vifi_t, unsigned int);
+struct rtentry *mfc_find(struct ifnet *, struct in_addr *, unsigned int);
struct rtentry *rt_mcast_add(struct ifnet *, struct sockaddr *,
struct sockaddr *);
void mrt_mcast_del(struct rtentry *, unsigned int);
@@ -222,8 +222,19 @@ ip_mrouter_set(struct socket *so, int op
int
ip_mrouter_get(struct socket *so, int optname, struct mbuf *m)
{
+ struct inpcb *inp = sotoinpcb(so);
+ unsigned int rtableid = inp->inp_rtableid;
int error;
+ soassertlocked(so);
+
+ rw_enter_read(&mrt_routerlock);
+
+ if (so != mrt_mrouter[rtableid]) {
+ error = EPROTONOSUPPORT;
+ goto out;
+ }
+
switch (optname) {
case MRT_VERSION:
error = get_version(m);
@@ -238,6 +249,8 @@ ip_mrouter_get(struct socket *so, int op
error = ENOPROTOOPT;
break;
}
+ out:
+ rw_exit_read(&mrt_routerlock);
return (error);
}
@@ -263,17 +276,22 @@ mrt_init(void)
int
mrt_ioctl(struct socket *so, u_long cmd, caddr_t data)
{
- struct inpcb *inp = sotoinpcb(so);
+ struct inpcb *inp;
+ unsigned int rtableid;
int error;
- if (inp == NULL)
- return (ENOTCONN);
+ solock_shared(so);
+ inp = sotoinpcb(so);
+ if (inp == NULL) {
+ error = ENOTCONN;
+ goto sounlock;
+ }
+ rtableid = inp->inp_rtableid;
- NET_LOCK_SHARED();
rw_enter_read(&mrt_routerlock);
- if (so != mrt_mrouter[inp->inp_rtableid]) {
+ if (so != mrt_mrouter[rtableid]) {
error = EPROTONOSUPPORT;
goto out;
}
@@ -281,24 +299,22 @@ mrt_ioctl(struct socket *so, u_long cmd,
switch (cmd) {
case SIOCGETVIFCNT:
KERNEL_LOCK();
- error = get_vif_cnt(inp->inp_rtableid,
- (struct sioc_vif_req *)data);
+ error = get_vif_cnt(rtableid, (struct sioc_vif_req *)data);
KERNEL_UNLOCK();
break;
case SIOCGETSGCNT:
KERNEL_LOCK();
- error = get_sg_cnt(inp->inp_rtableid,
- (struct sioc_sg_req *)data);
+ error = get_sg_cnt(rtableid, (struct sioc_sg_req *)data);
KERNEL_UNLOCK();
break;
default:
error = ENOTTY;
break;
}
-
out:
rw_exit_read(&mrt_routerlock);
- NET_UNLOCK_SHARED();
+ sounlock:
+ sounlock_shared(so);
return (error);
}
@@ -584,6 +600,8 @@ ip_mrouter_init(struct socket *so, struc
unsigned int rtableid = inp->inp_rtableid;
int *v;
+ soassertlocked(so);
+
if (so->so_type != SOCK_RAW ||
so->so_proto->pr_protocol != IPPROTO_IGMP)
return (EOPNOTSUPP);
@@ -602,6 +620,7 @@ ip_mrouter_init(struct socket *so, struc
return (EADDRINUSE);
}
mrt_mrouter[rtableid] = soref(so);
+ mrt_api_config[rtableid] = 0;
rw_exit_write(&mrt_routerlock);
@@ -630,11 +649,11 @@ ip_mrouter_done(struct socket *so)
unsigned int rtableid = inp->inp_rtableid;
int error;
- NET_ASSERT_LOCKED();
+ soassertlocked(so);
rw_enter_write(&mrt_routerlock);
- if (so != mrt_mrouter[inp->inp_rtableid]) {
+ if (so != mrt_mrouter[rtableid]) {
rw_exit_write(&mrt_routerlock);
return (EPROTONOSUPPORT);
}
@@ -666,8 +685,8 @@ ip_mrouter_done(struct socket *so)
vif_delete(ifp);
}
- mrt_api_config[rtableid] = 0;
mrt_mrouter[rtableid] = NULL;
+ mrt_api_config[rtableid] = 0;
sorele(so);
rw_exit_write(&mrt_routerlock);
@@ -682,6 +701,7 @@ get_version(struct mbuf *m)
*v = 0x0305; /* XXX !!!! */
m->m_len = sizeof(int);
+
return (0);
}
@@ -696,6 +716,8 @@ set_api_config(struct socket *so, struct
uint32_t *apival;
unsigned int rtableid = inp->inp_rtableid;
+ NET_ASSERT_LOCKED();
+
if (m == NULL || m->m_len < sizeof(u_int32_t))
return (EINVAL);
@@ -750,7 +772,6 @@ get_api_support(struct mbuf *m)
return (EINVAL);
apival = mtod(m, uint32_t *);
-
*apival = mrt_api_support;
return (0);
@@ -766,18 +787,13 @@ get_api_config(struct socket *so, struct
uint32_t *apival;
unsigned int rtableid = inp->inp_rtableid;
+ rw_assert_rdlock(&mrt_routerlock);
+
if (m == NULL || m->m_len < sizeof(u_int32_t))
return (EINVAL);
apival = mtod(m, uint32_t *);
-
- rw_enter_read(&mrt_routerlock);
- if (so != mrt_mrouter[inp->inp_rtableid]) {
- rw_exit_read(&mrt_routerlock);
- return (EPROTONOSUPPORT);
- }
*apival = mrt_api_config[rtableid];
- rw_exit_read(&mrt_routerlock);
return (0);
}
@@ -794,13 +810,13 @@ add_vif(struct socket *so, struct mbuf *
int error;
unsigned int rtableid = inp->inp_rtableid;
- NET_ASSERT_LOCKED();
+ soassertlocked(so);
if (m == NULL || m->m_len < sizeof(struct vifctl))
return (EINVAL);
rw_enter_read(&mrt_routerlock);
- if (so != mrt_mrouter[inp->inp_rtableid]) {
+ if (so != mrt_mrouter[rtableid]) {
rw_exit_read(&mrt_routerlock);
return (EPROTONOSUPPORT);
}
@@ -868,13 +884,13 @@ del_vif(struct socket *so, struct mbuf *
vifi_t *vifip;
unsigned int rtableid = inp->inp_rtableid;
- NET_ASSERT_LOCKED();
+ soassertlocked(so);
if (m == NULL || m->m_len < sizeof(vifi_t))
return (EINVAL);
rw_enter_read(&mrt_routerlock);
- if (so != mrt_mrouter[inp->inp_rtableid]) {
+ if (so != mrt_mrouter[rtableid]) {
rw_exit_read(&mrt_routerlock);
return (EPROTONOSUPPORT);
}
@@ -885,16 +901,17 @@ del_vif(struct socket *so, struct mbuf *
return (EADDRNOTAVAIL);
vif_delete(ifp);
+
return (0);
}
void
vif_delete(struct ifnet *ifp)
{
- struct vif *v;
+ struct vif *v = ifp->if_mcast;
struct ifreq ifr;
- if ((v = ifp->if_mcast) == NULL)
+ if (v == NULL)
return;
ifp->if_mcast = NULL;
@@ -1115,10 +1132,10 @@ add_mfc(struct socket *so, struct mbuf *
uint32_t api_config;
unsigned int rtableid = inp->inp_rtableid;
- NET_ASSERT_LOCKED();
+ soassertlocked(so);
rw_enter_read(&mrt_routerlock);
- if (so != mrt_mrouter[inp->inp_rtableid]) {
+ if (so != mrt_mrouter[rtableid]) {
rw_exit_read(&mrt_routerlock);
return (EPROTONOSUPPORT);
}
@@ -1144,11 +1161,8 @@ add_mfc(struct socket *so, struct mbuf *
sizeof(mfcctl2) - sizeof(struct mfcctl));
}
- if (mfc_add(&mfcctl2, &mfcctl2.mfcc_origin, &mfcctl2.mfcc_mcastgrp,
- mfcctl2.mfcc_parent, rtableid, M_WAITOK) == -1)
- return (EINVAL);
-
- return (0);
+ return (mfc_add(&mfcctl2, &mfcctl2.mfcc_origin, &mfcctl2.mfcc_mcastgrp,
+ mfcctl2.mfcc_parent, rtableid, M_WAITOK));
}
int
@@ -1161,7 +1175,7 @@ del_mfc(struct socket *so, struct mbuf *
struct mfcctl *mp;
unsigned int rtableid = inp->inp_rtableid;
- NET_ASSERT_LOCKED();
+ soassertlocked(so);
/*
* XXX: for deleting MFC entries the information in entries
@@ -1172,7 +1186,7 @@ del_mfc(struct socket *so, struct mbuf *
return (EINVAL);
rw_enter_read(&mrt_routerlock);
- if (so != mrt_mrouter[inp->inp_rtableid]) {
+ if (so != mrt_mrouter[rtableid]) {
rw_exit_read(&mrt_routerlock);
return (EPROTONOSUPPORT);
}
@@ -1187,7 +1201,8 @@ del_mfc(struct socket *so, struct mbuf *
DPRINTF("origin %#08X group %#08X rtableid %d",
mfcctl2.mfcc_origin.s_addr, mfcctl2.mfcc_mcastgrp.s_addr, rtableid);
- while ((rt = mfc_find(NULL, &mfcctl2.mfcc_mcastgrp, rtableid)) != NULL) {
+ while ((rt = mfc_find(NULL, &mfcctl2.mfcc_mcastgrp,
+ rtableid)) != NULL) {
mrt_mcast_del(rt, rtableid);
rtfree(rt);
}
@@ -1237,6 +1252,8 @@ ip_mforward(struct mbuf *m, struct ifnet
struct mbuf *mm;
unsigned int rtableid = ifp->if_rdomain;
+ NET_ASSERT_LOCKED();
+
if (ip->ip_hl < (IP_HDR_LEN + TUNNEL_LEN) >> 2 ||
((u_char *)(ip + 1))[1] != IPOPT_LSRR) {
/*
@@ -1310,8 +1327,6 @@ ip_mforward(struct mbuf *m, struct ifnet
im->im_mbz = 0;
im->im_vif = v->v_id;
- mrtstat_inc(mrts_upcalls);
-
sin.sin_addr = ip->ip_src;
rw_enter_read(&mrt_routerlock);
if (socket_send(mrt_mrouter[rtableid], mm, &sin) < 0) {
@@ -1323,6 +1338,8 @@ ip_mforward(struct mbuf *m, struct ifnet
}
rw_exit_read(&mrt_routerlock);
+ mrtstat_inc(mrts_upcalls);
+
mfc_add(NULL, &ip->ip_src, &ip->ip_dst, v->v_id,
rtableid, M_NOWAIT);
}
@@ -1338,22 +1355,23 @@ int
ip_mdq(struct mbuf *m, struct ifnet *ifp0, struct rtentry *rt, int flags)
{
struct ip *ip = mtod(m, struct ip *);
- struct mfc *mfc = (struct mfc *)rt->rt_llinfo;
struct vif *v = ifp0->if_mcast;
+ struct mfc *mfc = (struct mfc *)rt->rt_llinfo;
struct ifnet *ifp;
struct mbuf *mc;
struct ip_moptions imo;
+ int plen = m->m_pkthdr.len;
- /* Sanity check: we have all promised pointers. */
if (v == NULL || mfc == NULL) {
rtfree(rt);
return (EHOSTUNREACH);
}
/*
- * Don't forward if it didn't arrive from the parent vif for its origin.
+ * Don't forward if it didn't arrive from the parent vif
+ * for its origin.
*/
- if (mfc->mfc_parent != v->v_id) {
+ if (v->v_id != mfc->mfc_parent) {
/* came in the wrong interface */
mrtstat_inc(mrts_wrong_if);
mfc->mfc_wrong_if++;
@@ -1364,10 +1382,10 @@ ip_mdq(struct mbuf *m, struct ifnet *ifp
/* If I sourced this packet, it counts as output, else it was input. */
if (in_hosteq(ip->ip_src, v->v_lcl_addr)) {
v->v_pkt_out++;
- v->v_bytes_out += m->m_pkthdr.len;
+ v->v_bytes_out += plen;
} else {
v->v_pkt_in++;
- v->v_bytes_in += m->m_pkthdr.len;
+ v->v_bytes_in += plen;
}
/*
@@ -1387,7 +1405,7 @@ ip_mdq(struct mbuf *m, struct ifnet *ifp
continue;
mfc->mfc_pkt_cnt++;
- mfc->mfc_byte_cnt += m->m_pkthdr.len;
+ mfc->mfc_byte_cnt += plen;
/* Don't let this route expire. */
mfc->mfc_expire = 0;
@@ -1410,7 +1428,7 @@ ip_mdq(struct mbuf *m, struct ifnet *ifp
}
v->v_pkt_out++;
- v->v_bytes_out += m->m_pkthdr.len;
+ v->v_bytes_out += plen;
/*
* Make a new reference to the packet; make sure
@@ -1446,6 +1464,8 @@ if_lookupbyvif(vifi_t vifi, unsigned int
struct vif *v;
struct ifnet *ifp;
+ NET_ASSERT_LOCKED();
+
TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
if (ifp->if_rdomain != rtableid)
continue;
@@ -1466,6 +1486,8 @@ rt_mcast_add(struct ifnet *ifp, struct s
struct ifaddr *ifa;
int rv;
unsigned int rtableid = ifp->if_rdomain;
+
+ NET_ASSERT_LOCKED();
TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
if (ifa->ifa_addr->sa_family == AF_INET)
Index: netinet6/ip6_input.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_input.c,v
diff -u -p -r1.300 ip6_input.c
--- netinet6/ip6_input.c 16 Sep 2025 09:19:16 -0000 1.300
+++ netinet6/ip6_input.c 5 Aug 2026 13:42:56 -0000
@@ -475,7 +475,7 @@ ip6_input_if(struct mbuf **mp, int *offp
#ifdef MROUTING
if (atomic_load_int(&ip6_mforwarding) &&
- ip6_mrouter[ifp->if_rdomain]) {
+ ip6_mrouter_active(ifp->if_rdomain)) {
int error;
nxt = ip6_hbhchcheck(&m, offp, &ours, flags);
@@ -1432,10 +1432,6 @@ const u_char inet6ctlerrmap[PRC_NCMDS] =
0, 0, 0, 0,
ENOPROTOOPT
};
-
-#ifdef MROUTING
-extern int ip6_mrtproto;
-#endif
#ifndef SMALL_KERNEL
const struct sysctl_bounded_args ipv6ctl_vars[] = {
Index: netinet6/ip6_mroute.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_mroute.c,v
diff -u -p -r1.158 ip6_mroute.c
--- netinet6/ip6_mroute.c 24 Jun 2026 12:33:49 -0000 1.158
+++ netinet6/ip6_mroute.c 5 Aug 2026 13:42:56 -0000
@@ -107,6 +107,8 @@
/*
* Locks used to protect data:
* I immutable after creation
+ * N net lock
+ * R multicast router lock
*/
/* #define MCAST_DEBUG */
@@ -127,14 +129,13 @@ int mcast6_debug = 1;
int ip6_mdq(struct mbuf *, struct ifnet *, struct rtentry *, int);
void phyint_send6(struct ifnet *, struct ip6_hdr *, struct mbuf *, int, int);
-/*
- * Globals. All but ip6_mrouter, ip6_mrtproto and mrt6stat could be static,
- * except for netstat or debugging purposes.
- */
-struct socket *ip6_mrouter[RT_TABLEID_MAX + 1];
-struct rttimer_queue ip6_mrouterq;
-int ip6_mrouter_ver = 0;
-int ip6_mrtproto; /* [I] for netstat only */
+struct rwlock mrt6_routerlock = RWLOCK_INITIALIZER("mrouter6");
+
+struct rttimer_queue mrt6_timer;
+struct socket *mrt6_mrouter[RT_TABLEID_MAX + 1]; /* [R] */
+int mrt6_mrouter_ver[RT_TABLEID_MAX + 1]; /* [R] */
+int ip6_mrtproto; /* [I] for netstat only */
+
struct cpumem *mrt6counters;
int get_sg6_cnt(struct sioc_sg_req6 *, unsigned int);
@@ -144,6 +145,7 @@ int add_m6if(struct socket *, struct mif
int del_m6if(struct socket *, mifi_t *);
int add_m6fc(struct socket *, struct mf6cctl *);
int del_m6fc(struct socket *, struct mf6cctl *);
+int socket6_send(struct socket *, struct mbuf *, struct sockaddr_in6 *);
void mf6c_expire_route(struct rtentry *, u_int);
struct ifnet *mrt6_iflookupbymif(mifi_t, unsigned int);
struct rtentry *mf6c_find(struct ifnet *, struct in6_addr *, unsigned int);
@@ -156,11 +158,6 @@ void mrt6_mcast_del(struct rtentry *, un
int
ip6_mrouter_set(int cmd, struct socket *so, struct mbuf *m)
{
- struct inpcb *inp = sotoinpcb(so);
-
- if (cmd != MRT6_INIT && so != ip6_mrouter[inp->inp_rtableid])
- return (EPERM);
-
switch (cmd) {
case MRT6_INIT:
if (m == NULL || m->m_len < sizeof(int))
@@ -195,15 +192,34 @@ ip6_mrouter_set(int cmd, struct socket *
int
ip6_mrouter_get(int cmd, struct socket *so, struct mbuf *m)
{
- struct inpcb *inp = sotoinpcb(so);
+ struct inpcb *inp = sotoinpcb(so);
+ unsigned int rtableid = inp->inp_rtableid;
+ int error;
+
+ soassertlocked(so);
- if (so != ip6_mrouter[inp->inp_rtableid])
- return (EPERM);
+ rw_enter_read(&mrt6_routerlock);
+
+ if (so != mrt6_mrouter[rtableid]) {
+ error = EPROTONOSUPPORT;
+ goto out;
+ }
switch (cmd) {
default:
- return EOPNOTSUPP;
+ error = EOPNOTSUPP;
+ break;
}
+ out:
+ rw_exit_read(&mrt6_routerlock);
+
+ return (error);
+}
+
+int
+ip6_mrouter_active(u_int rtableid)
+{
+ return (READ_ONCE(mrt6_mrouter[rtableid]) != NULL);
}
void
@@ -211,7 +227,7 @@ mrt6_init(void)
{
mrt6counters = counters_alloc(mrt6s_ncounters);
- rt_timer_queue_init(&ip6_mrouterq, MCAST_EXPIRE_TIMEOUT,
+ rt_timer_queue_init(&mrt6_timer, MCAST_EXPIRE_TIMEOUT,
&mf6c_expire_route);
}
@@ -221,33 +237,46 @@ mrt6_init(void)
int
mrt6_ioctl(struct socket *so, u_long cmd, caddr_t data)
{
- struct inpcb *inp = sotoinpcb(so);
+ struct inpcb *inp;
+ unsigned int rtableid;
int error;
- if (inp == NULL)
- return (ENOTCONN);
+ solock_shared(so);
- KERNEL_LOCK();
+ inp = sotoinpcb(so);
+ if (inp == NULL) {
+ error = ENOTCONN;
+ goto sounlock;
+ }
+ rtableid = inp->inp_rtableid;
+
+ rw_enter_read(&mrt6_routerlock);
+
+ if (so != mrt6_mrouter[rtableid]) {
+ error = EPROTONOSUPPORT;
+ goto out;
+ }
switch (cmd) {
case SIOCGETSGCNT_IN6:
- NET_LOCK_SHARED();
- error = get_sg6_cnt((struct sioc_sg_req6 *)data,
- inp->inp_rtableid);
- NET_UNLOCK_SHARED();
+ KERNEL_LOCK();
+ error = get_sg6_cnt((struct sioc_sg_req6 *)data, rtableid);
+ KERNEL_UNLOCK();
break;
case SIOCGETMIFCNT_IN6:
- NET_LOCK_SHARED();
- error = get_mif6_cnt((struct sioc_mif_req6 *)data,
- inp->inp_rtableid);
- NET_UNLOCK_SHARED();
+ KERNEL_LOCK();
+ error = get_mif6_cnt((struct sioc_mif_req6 *)data, rtableid);
+ KERNEL_UNLOCK();
break;
default:
error = ENOTTY;
break;
}
+ out:
+ rw_exit_read(&mrt6_routerlock);
+ sounlock:
+ sounlock_shared(so);
- KERNEL_UNLOCK();
return error;
}
@@ -526,6 +555,8 @@ ip6_mrouter_init(struct socket *so, int
struct inpcb *inp = sotoinpcb(so);
unsigned int rtableid = inp->inp_rtableid;
+ soassertlocked(so);
+
if (so->so_type != SOCK_RAW ||
so->so_proto->pr_protocol != IPPROTO_ICMPV6)
return (EOPNOTSUPP);
@@ -533,11 +564,16 @@ ip6_mrouter_init(struct socket *so, int
if (v != 1)
return (ENOPROTOOPT);
- if (ip6_mrouter[rtableid] != NULL)
+ rw_enter_write(&mrt6_routerlock);
+
+ if (mrt6_mrouter[rtableid] != NULL) {
+ rw_exit_write(&mrt6_routerlock);
return (EADDRINUSE);
+ }
+ mrt6_mrouter[rtableid] = soref(so);
+ mrt6_mrouter_ver[rtableid] = cmd;
- ip6_mrouter[rtableid] = so;
- ip6_mrouter_ver = cmd;
+ rw_exit_write(&mrt6_routerlock);
return (0);
}
@@ -564,7 +600,14 @@ ip6_mrouter_done(struct socket *so)
unsigned int rtableid = inp->inp_rtableid;
int error;
- NET_ASSERT_LOCKED();
+ soassertlocked(so);
+
+ rw_enter_write(&mrt6_routerlock);
+
+ if (so != mrt6_mrouter[rtableid]) {
+ rw_exit_write(&mrt6_routerlock);
+ return (EPROTONOSUPPORT);
+ }
/* Delete all remaining installed multicast routes. */
do {
@@ -587,8 +630,11 @@ ip6_mrouter_done(struct socket *so)
ip6_mrouter_detach(ifp);
}
- ip6_mrouter[inp->inp_rtableid] = NULL;
- ip6_mrouter_ver = 0;
+ mrt6_mrouter[rtableid] = NULL;
+ mrt6_mrouter_ver[rtableid] = 0;
+ sorele(so);
+
+ rw_exit_write(&mrt6_routerlock);
return 0;
}
@@ -605,6 +651,7 @@ ip6_mrouter_detach(struct ifnet *ifp)
ifp->if_mcast6 = NULL;
memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
ifr.ifr_addr.sin6_family = AF_INET6;
ifr.ifr_addr.sin6_addr = in6addr_any;
KERNEL_LOCK();
@@ -627,23 +674,29 @@ add_m6if(struct socket *so, struct mif6c
int error;
unsigned int rtableid = inp->inp_rtableid;
- NET_ASSERT_LOCKED();
+ soassertlocked(so);
- if (mifcp->mif6c_mifi >= MAXMIFS)
- return EINVAL;
+ rw_enter_read(&mrt6_routerlock);
+ if (so != mrt6_mrouter[rtableid]) {
+ rw_exit_read(&mrt6_routerlock);
+ return (EPROTONOSUPPORT);
+ }
+ rw_exit_read(&mrt6_routerlock);
+ if (mifcp->mif6c_mifi >= MAXMIFS)
+ return (EINVAL);
if (mrt6_iflookupbymif(mifcp->mif6c_mifi, rtableid) != NULL)
- return EADDRINUSE; /* XXX: is it appropriate? */
+ return (EADDRINUSE);
{
ifp = if_get(mifcp->mif6c_pifi);
if (ifp == NULL)
- return ENXIO;
+ return (ENXIO);
/* Make sure the interface supports multicast */
if ((ifp->if_flags & IFF_MULTICAST) == 0) {
if_put(ifp);
- return EOPNOTSUPP;
+ return (EOPNOTSUPP);
}
/*
@@ -651,15 +704,15 @@ add_m6if(struct socket *so, struct mif6c
* from the interface.
*/
memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
ifr.ifr_addr.sin6_family = AF_INET6;
ifr.ifr_addr.sin6_addr = in6addr_any;
KERNEL_LOCK();
error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
KERNEL_UNLOCK();
-
if (error) {
if_put(ifp);
- return error;
+ return (error);
}
}
@@ -675,7 +728,7 @@ add_m6if(struct socket *so, struct mif6c
if_put(ifp);
- return 0;
+ return (0);
}
/*
@@ -686,17 +739,25 @@ del_m6if(struct socket *so, mifi_t *mifi
{
struct inpcb *inp = sotoinpcb(so);
struct ifnet *ifp;
+ unsigned int rtableid = inp->inp_rtableid;
- NET_ASSERT_LOCKED();
+ soassertlocked(so);
+
+ rw_enter_read(&mrt6_routerlock);
+ if (so != mrt6_mrouter[rtableid]) {
+ rw_exit_read(&mrt6_routerlock);
+ return (EPROTONOSUPPORT);
+ }
+ rw_exit_read(&mrt6_routerlock);
if (*mifip >= MAXMIFS)
- return EINVAL;
- if ((ifp = mrt6_iflookupbymif(*mifip, inp->inp_rtableid)) == NULL)
- return EINVAL;
+ return (EINVAL);
+ if ((ifp = mrt6_iflookupbymif(*mifip, rtableid)) == NULL)
+ return (EADDRNOTAVAIL);
ip6_mrouter_detach(ifp);
- return 0;
+ return (0);
}
int
@@ -726,7 +787,7 @@ mf6c_add_route(struct ifnet *ifp, struct
}
rt->rt_llinfo = (caddr_t)mf6c;
- rt_timer_add(rt, &ip6_mrouterq, rtableid);
+ rt_timer_add(rt, &mrt6_timer, rtableid);
mf6c->mf6c_parent = mf6cc->mf6cc_parent;
rtfree(rt);
@@ -870,7 +931,14 @@ add_m6fc(struct socket *so, struct mf6cc
struct inpcb *inp = sotoinpcb(so);
unsigned int rtableid = inp->inp_rtableid;
- NET_ASSERT_LOCKED();
+ soassertlocked(so);
+
+ rw_enter_read(&mrt6_routerlock);
+ if (so != mrt6_mrouter[rtableid]) {
+ rw_exit_read(&mrt6_routerlock);
+ return (EPROTONOSUPPORT);
+ }
+ rw_exit_read(&mrt6_routerlock);
return mf6c_add(mfccp, &mfccp->mf6cc_origin.sin6_addr,
&mfccp->mf6cc_mcastgrp.sin6_addr, mfccp->mf6cc_parent,
@@ -884,7 +952,14 @@ del_m6fc(struct socket *so, struct mf6cc
struct rtentry *rt;
unsigned int rtableid = inp->inp_rtableid;
- NET_ASSERT_LOCKED();
+ soassertlocked(so);
+
+ rw_enter_read(&mrt6_routerlock);
+ if (so != mrt6_mrouter[rtableid]) {
+ rw_exit_read(&mrt6_routerlock);
+ return (EPROTONOSUPPORT);
+ }
+ rw_exit_read(&mrt6_routerlock);
while ((rt = mf6c_find(NULL, &mfccp->mf6cc_mcastgrp.sin6_addr,
rtableid)) != NULL) {
@@ -892,7 +967,7 @@ del_m6fc(struct socket *so, struct mf6cc
rtfree(rt);
}
- return 0;
+ return (0);
}
int
@@ -930,7 +1005,6 @@ ip6_mforward(struct ip6_hdr *ip6, struct
struct rtentry *rt;
struct mif6 *mifp;
struct mbuf *mm;
- struct sockaddr_in6 sin6;
unsigned int rtableid = ifp->if_rdomain;
NET_ASSERT_LOCKED();
@@ -978,6 +1052,7 @@ ip6_mforward(struct ip6_hdr *ip6, struct
mrt6stat_inc(mrt6s_no_route);
{
+ struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 };
struct mrt6msg *im;
if ((mifp = ifp->if_mcast6) == NULL)
@@ -989,18 +1064,15 @@ ip6_mforward(struct ip6_hdr *ip6, struct
*/
mm = m_copym(m, 0, sizeof(struct ip6_hdr), M_NOWAIT);
if (mm == NULL)
- return ENOBUFS;
+ return (ENOBUFS);
/*
* Send message to routing daemon
*/
- (void)memset(&sin6, 0, sizeof(sin6));
- sin6.sin6_len = sizeof(sin6);
- sin6.sin6_family = AF_INET6;
- sin6.sin6_addr = ip6->ip6_src;
- im = NULL;
- switch (ip6_mrouter_ver) {
+ rw_enter_read(&mrt6_routerlock);
+
+ switch (mrt6_mrouter_ver[rtableid]) {
case MRT6_INIT:
im = mtod(mm, struct mrt6msg *);
im->im6_msgtype = MRT6MSG_NOCACHE;
@@ -1008,17 +1080,21 @@ ip6_mforward(struct ip6_hdr *ip6, struct
im->im6_mif = mifp->m6_mifi;
break;
default:
+ rw_exit_read(&mrt6_routerlock);
m_freem(mm);
- return EINVAL;
+ return (EINVAL);
}
- if (socket6_send(ip6_mrouter[rtableid], mm,
+ sin6.sin6_addr = ip6->ip6_src;
+ if (socket6_send(mrt6_mrouter[rtableid], mm,
&sin6) < 0) {
- log(LOG_WARNING, "ip6_mforward: ip6_mrouter "
+ rw_exit_read(&mrt6_routerlock);
+ log(LOG_WARNING, "ip6_mforward: mrt6_mrouter "
"socket queue full\n");
mrt6stat_inc(mrt6s_upq_sockfull);
- return ENOBUFS;
+ return (ENOBUFS);
}
+ rw_exit_read(&mrt6_routerlock);
mrt6stat_inc(mrt6s_upcalls);
@@ -1026,7 +1102,7 @@ ip6_mforward(struct ip6_hdr *ip6, struct
mifp->m6_mifi, rtableid, M_NOWAIT);
}
- return 0;
+ return (0);
}
}
@@ -1051,7 +1127,7 @@ mf6c_expire_route(struct rtentry *rt, u_
if (mf6c->mf6c_expire == 0) {
mf6c->mf6c_expire = 1;
- rt_timer_add(rt, &ip6_mrouterq, rtableid);
+ rt_timer_add(rt, &mrt6_timer, rtableid);
return;
}
@@ -1072,7 +1148,7 @@ ip6_mdq(struct mbuf *m, struct ifnet *if
if (mifp == NULL || mf6c == NULL) {
rtfree(rt);
- return EHOSTUNREACH;
+ return (EHOSTUNREACH);
}
/*
@@ -1114,7 +1190,7 @@ ip6_mdq(struct mbuf *m, struct ifnet *if
continue;
mf6c->mf6c_pkt_cnt++;
- mf6c->mf6c_byte_cnt += m->m_pkthdr.len;
+ mf6c->mf6c_byte_cnt += plen;
/* Don't let this route expire. */
mf6c->mf6c_expire = 0;
@@ -1246,10 +1322,10 @@ mrt6_iflookupbymif(mifi_t mifi, unsigned
if (m6->m6_mifi != mifi)
continue;
- return ifp;
+ return (ifp);
}
- return NULL;
+ return (NULL);
}
struct rtentry *
@@ -1259,8 +1335,8 @@ mf6c_find(struct ifnet *ifp, struct in6_
struct sockaddr_in6 msin6;
memset(&msin6, 0, sizeof(msin6));
- msin6.sin6_family = AF_INET6;
msin6.sin6_len = sizeof(msin6);
+ msin6.sin6_family = AF_INET6;
msin6.sin6_addr = *group;
rt = rtalloc(sin6tosa(&msin6), 0, rtableid);
@@ -1288,6 +1364,8 @@ mrt6_mcast_add(struct ifnet *ifp, struct
struct ifaddr *ifa;
int rv;
unsigned int rtableid = ifp->if_rdomain;
+
+ NET_ASSERT_LOCKED();
TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
if (ifa->ifa_addr->sa_family == AF_INET6)
Index: netinet6/ip6_mroute.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_mroute.h,v
diff -u -p -r1.26 ip6_mroute.h
--- netinet6/ip6_mroute.h 24 Jun 2026 12:33:49 -0000 1.26
+++ netinet6/ip6_mroute.h 5 Aug 2026 13:42:56 -0000
@@ -222,6 +222,8 @@ mrt6stat_inc(enum mrt6stat_counters c)
/* How frequent should we look for expired entries (in seconds). */
#define MCAST_EXPIRE_TIMEOUT 30
+extern int ip6_mrtproto;
+
/*
* The kernel's multicast-interface structure.
*/
Index: netinet6/ip6_output.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_output.c,v
diff -u -p -r1.308 ip6_output.c
--- netinet6/ip6_output.c 5 Aug 2026 09:43:19 -0000 1.308
+++ netinet6/ip6_output.c 5 Aug 2026 13:42:56 -0000
@@ -490,7 +490,7 @@ reroute:
* if necessary.
*/
if (atomic_load_int(&ip6_mforwarding) &&
- ip6_mrouter[ifp->if_rdomain] &&
+ ip6_mrouter_active(ifp->if_rdomain) &&
(flags & IPV6_FORWARDING) == 0) {
int rv;
Index: netinet6/ip6_var.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_var.h,v
diff -u -p -r1.130 ip6_var.h
--- netinet6/ip6_var.h 23 Jun 2026 15:45:00 -0000 1.130
+++ netinet6/ip6_var.h 5 Aug 2026 13:42:56 -0000
@@ -299,6 +299,7 @@ int ip6_unknown_opt(struct mbuf **, u_in
int ip6_get_prevhdr(struct mbuf *, int);
int ip6_nexthdr(struct mbuf *, int, int, int *);
int ip6_lasthdr(struct mbuf *, int, int, int *);
+int ip6_mrouter_active(u_int);
int ip6_mforward(struct ip6_hdr *, struct ifnet *, struct mbuf *, int);
int ip6_process_hopopts(struct mbuf **, u_int8_t *, int, u_int32_t *,
u_int32_t *);
Index: netinet6/mld6.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/mld6.c,v
diff -u -p -r1.75 mld6.c
--- netinet6/mld6.c 29 Mar 2026 18:08:07 -0000 1.75
+++ netinet6/mld6.c 5 Aug 2026 13:42:56 -0000
@@ -535,7 +535,7 @@ mld6_sendpkt(const struct mld6_pktinfo *
* router, so that the process-level routing daemon can hear it.
*/
#ifdef MROUTING
- im6o.im6o_loop = (ip6_mrouter[pkt->mpi_rdomain] != NULL);
+ im6o.im6o_loop = ip6_mrouter_active(pkt->mpi_rdomain);
#endif
if_put(ifp);
Index: netinet6/raw_ip6.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/raw_ip6.c,v
diff -u -p -r1.194 raw_ip6.c
--- netinet6/raw_ip6.c 8 Jul 2025 00:47:41 -0000 1.194
+++ netinet6/raw_ip6.c 5 Aug 2026 13:42:56 -0000
@@ -627,8 +627,7 @@ rip6_detach(struct socket *so)
if (inp == NULL)
panic("%s", __func__);
#ifdef MROUTING
- if (so == ip6_mrouter[inp->inp_rtableid])
- ip6_mrouter_done(so);
+ ip6_mrouter_done(so);
#endif
free(inp->inp_icmp6filt, M_PCB, sizeof(struct icmp6_filter));
inp->inp_icmp6filt = NULL;