From: Alexander Bluhm Subject: Re: ip6 multicast router lock To: tech@openbsd.org Date: Wed, 5 Aug 2026 23:52:03 +0200 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;