Download raw body.
ip6 multicast router lock
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?
bluhm
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 16 Jul 2026 21:20:04 -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 16 Jul 2026 18:34:14 -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 16 Jul 2026 21:20:25 -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 16 Jul 2026 18:32:45 -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.306 ip6_output.c
--- netinet6/ip6_output.c 25 Jun 2026 13:16:44 -0000 1.306
+++ netinet6/ip6_output.c 16 Jul 2026 18:38:15 -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) {
if (ip6_mforward(ip6, ifp, m, flags) != 0) {
m_freem(m);
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 16 Jul 2026 18:36:11 -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 16 Jul 2026 18:39:52 -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 16 Jul 2026 18:30:02 -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;
ip6 multicast router lock