From: Alexander Bluhm Subject: Re: unlock igmp and mld6 fast timer To: tech@openbsd.org Cc: Vitaliy Makkoveev Date: Fri, 5 Dec 2025 21:31:44 +0100 I wonder if the diff also fixes this use after free https://syzkaller.appspot.com/bug?extid=3dcb7e0d63b11f6f341c I have seen traces where multicast modifications were done with shared net lock. Diff below puts an exclusive lock around them. anyone? bluhm On Tue, Dec 02, 2025 at 11:01:36PM +0100, Alexander Bluhm wrote: > Hi, > > After moving around code for a while, I think a rwlock to protect > if_maddrlist is the next step. The malloc(M_WAITOK) in rti_fill() > prevents us from using a mutex here. > > So protect the TAILQ if_maddrlist with rwlock if_maddrlock. Also > struct in_multi and in6_multi use this lock for their state and > timer. Sleeps in malloc and IP output are possible. > > This allows to run IGMP and MLD6 fast timeout with shared net lock. > > ok? > > bluhm > > Index: net/if.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/net/if.c,v > diff -u -p -r1.753 if.c > --- net/if.c 21 Nov 2025 04:44:26 -0000 1.753 > +++ net/if.c 2 Dec 2025 20:36:56 -0000 > @@ -646,6 +646,7 @@ if_attach_common(struct ifnet *ifp) > TAILQ_INIT(&ifp->if_addrlist); > TAILQ_INIT(&ifp->if_maddrlist); > TAILQ_INIT(&ifp->if_groups); > + rw_init(&ifp->if_maddrlock, "maddr"); > > if (!ISSET(ifp->if_xflags, IFXF_MPSAFE)) { > KASSERTMSG(ifp->if_qstart == NULL, > Index: net/if_var.h > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_var.h,v > diff -u -p -r1.142 if_var.h > --- net/if_var.h 17 Nov 2025 09:19:45 -0000 1.142 > +++ net/if_var.h 2 Dec 2025 20:34:11 -0000 > @@ -81,6 +81,7 @@ > * K kernel lock > * N net lock > * T if_tmplist_lock > + * m interface multicast rwlock if_maddrlock > * > * For SRP related structures that allow lock-free reads, the write lock > * is indicated below. > @@ -148,8 +149,9 @@ struct ifnet { /* and the entries */ > TAILQ_ENTRY(ifnet) if_list; /* [NK] all struct ifnets are chained */ > TAILQ_ENTRY(ifnet) if_tmplist; /* [T] temporary list */ > TAILQ_HEAD(, ifaddr) if_addrlist; /* [N] list of addresses per if */ > - TAILQ_HEAD(, ifmaddr) if_maddrlist; /* [N] list of multicast records */ > + TAILQ_HEAD(, ifmaddr) if_maddrlist; /* [m] list of multicast records */ > TAILQ_HEAD(, ifg_list) if_groups; /* [N] list of groups per if */ > + struct rwlock if_maddrlock; > struct task_list if_addrhooks; /* [I] address change callbacks */ > struct task_list if_linkstatehooks; /* [I] link change callbacks*/ > struct task_list if_detachhooks; /* [I] detach callbacks */ > @@ -266,10 +268,10 @@ struct ifaddr { > * Interface multicast address. > */ > struct ifmaddr { > - struct sockaddr *ifma_addr; /* Protocol address */ > - unsigned int ifma_ifidx; /* Index of the interface */ > + TAILQ_ENTRY(ifmaddr) ifma_list; /* [m] Per-interface list */ > + struct sockaddr *ifma_addr; /* [I] Protocol address */ > struct refcnt ifma_refcnt; /* Count of references */ > - TAILQ_ENTRY(ifmaddr) ifma_list; /* Per-interface list */ > + unsigned int ifma_ifidx; /* [I] Index of the interface */ > }; > > /* > Index: netinet/igmp.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/igmp.c,v > diff -u -p -r1.93 igmp.c > --- netinet/igmp.c 2 Dec 2025 15:52:04 -0000 1.93 > +++ netinet/igmp.c 2 Dec 2025 20:37:23 -0000 > @@ -341,6 +341,7 @@ igmp_input_if(struct ifnet *ifp, struct > * except those that are already running and those > * that belong to a "local" group (224.0.0.X). > */ > + rw_enter_write(&ifp->if_maddrlock); > TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) { > if (ifma->ifma_addr->sa_family != AF_INET) > continue; > @@ -353,6 +354,7 @@ igmp_input_if(struct ifnet *ifp, struct > running = 1; > } > } > + rw_exit_write(&ifp->if_maddrlock); > } else { > if (!IN_MULTICAST(ip->ip_dst.s_addr)) { > igmpstat_inc(igps_rcv_badqueries); > @@ -372,6 +374,7 @@ igmp_input_if(struct ifnet *ifp, struct > * timers already running, check if they need to be > * reset. > */ > + rw_enter_write(&ifp->if_maddrlock); > TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) { > if (ifma->ifma_addr->sa_family != AF_INET) > continue; > @@ -400,6 +403,7 @@ igmp_input_if(struct ifnet *ifp, struct > } > } > } > + rw_exit_write(&ifp->if_maddrlock); > } > > break; > @@ -436,6 +440,7 @@ igmp_input_if(struct ifnet *ifp, struct > * If we belong to the group being reported, stop > * our timer for that group. > */ > + rw_enter_write(&ifp->if_maddrlock); > inm = in_lookupmulti(&igmp->igmp_group, ifp); > if (inm != NULL) { > inm->inm_timer = 0; > @@ -456,6 +461,7 @@ igmp_input_if(struct ifnet *ifp, struct > break; > } > } > + rw_exit_write(&ifp->if_maddrlock); > > break; > > @@ -504,6 +510,7 @@ igmp_input_if(struct ifnet *ifp, struct > * If we belong to the group being reported, stop > * our timer for that group. > */ > + rw_enter_write(&ifp->if_maddrlock); > inm = in_lookupmulti(&igmp->igmp_group, ifp); > if (inm != NULL) { > inm->inm_timer = 0; > @@ -520,6 +527,7 @@ igmp_input_if(struct ifnet *ifp, struct > break; > } > } > + rw_exit_write(&ifp->if_maddrlock); > > break; > > @@ -542,6 +550,8 @@ igmp_joingroup(struct in_multi *inm, str > { > int i, running = 0; > > + rw_assert_wrlock(&ifp->if_maddrlock); > + > inm->inm_state = IGMP_IDLE_MEMBER; > > if (!IN_LOCAL_GROUP(inm->inm_addr.s_addr) && > @@ -564,6 +574,8 @@ igmp_joingroup(struct in_multi *inm, str > void > igmp_leavegroup(struct in_multi *inm, struct ifnet *ifp) > { > + rw_assert_anylock(&ifp->if_maddrlock); > + > switch (inm->inm_state) { > case IGMP_DELAYING_MEMBER: > case IGMP_IDLE_MEMBER: > @@ -598,7 +610,7 @@ igmp_fasttimo(void) > return; > membar_consumer(); > > - NET_LOCK(); > + NET_LOCK_SHARED(); > > TAILQ_FOREACH(ifp, &ifnetlist, if_list) { > if (igmp_checktimer(ifp)) > @@ -608,7 +620,7 @@ igmp_fasttimo(void) > membar_producer(); > atomic_store_int(&igmp_timers_are_running, running); > > - NET_UNLOCK(); > + NET_UNLOCK_SHARED(); > } > > int > @@ -618,8 +630,7 @@ igmp_checktimer(struct ifnet *ifp) > struct ifmaddr *ifma; > int running = 0; > > - NET_ASSERT_LOCKED(); > - > + rw_enter_write(&ifp->if_maddrlock); > TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) { > if (ifma->ifma_addr->sa_family != AF_INET) > continue; > @@ -640,6 +651,7 @@ igmp_checktimer(struct ifnet *ifp) > running = 1; > } > } > + rw_exit_write(&ifp->if_maddrlock); > > return (running); > } > Index: netinet/in.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/in.c,v > diff -u -p -r1.190 in.c > --- netinet/in.c 2 Dec 2025 15:52:04 -0000 1.190 > +++ netinet/in.c 2 Dec 2025 20:37:11 -0000 > @@ -853,7 +853,7 @@ in_lookupmulti(const struct in_addr *add > struct in_multi *inm = NULL; > struct ifmaddr *ifma; > > - NET_ASSERT_LOCKED(); > + rw_assert_anylock(&ifp->if_maddrlock); > > TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) { > if (ifma->ifma_addr->sa_family == AF_INET && > @@ -871,54 +871,67 @@ in_lookupmulti(const struct in_addr *add > struct in_multi * > in_addmulti(const struct in_addr *addr, struct ifnet *ifp) > { > - struct in_multi *inm; > + struct in_multi *inm, *new_inm = NULL; > struct ifreq ifr; > > /* > * See if address already in list. > */ > + rw_enter_write(&ifp->if_maddrlock); > inm = in_lookupmulti(addr, ifp); > - if (inm != NULL) { > - /* > - * Found it; just increment the reference count. > - */ > - refcnt_take(&inm->inm_refcnt); > - } else { > - /* > - * New address; allocate a new multicast record > - * and link it into the interface's multicast list. > - */ > - inm = malloc(sizeof(*inm), M_IPMADDR, M_WAITOK | M_ZERO); > - inm->inm_sin.sin_len = sizeof(struct sockaddr_in); > - inm->inm_sin.sin_family = AF_INET; > - inm->inm_sin.sin_addr = *addr; > - refcnt_init_trace(&inm->inm_refcnt, DT_REFCNT_IDX_IFMADDR); > - inm->inm_ifidx = ifp->if_index; > - inm->inm_ifma.ifma_addr = sintosa(&inm->inm_sin); > + if (inm != NULL) > + goto found; > + rw_exit_write(&ifp->if_maddrlock); > > - /* > - * Ask the network driver to update its multicast reception > - * filter appropriately for the new address. > - */ > - memset(&ifr, 0, sizeof(ifr)); > - memcpy(&ifr.ifr_addr, &inm->inm_sin, sizeof(inm->inm_sin)); > - KERNEL_LOCK(); > - if ((*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr) != 0) { > - KERNEL_UNLOCK(); > - free(inm, M_IPMADDR, sizeof(*inm)); > - return (NULL); > - } > + /* > + * New address; allocate a new multicast record > + * and link it into the interface's multicast list. > + */ > + new_inm = malloc(sizeof(*inm), M_IPMADDR, M_WAITOK | M_ZERO); > + > + /* > + * Ask the network driver to update its multicast reception > + * filter appropriately for the new address. > + */ > + memset(&ifr, 0, sizeof(ifr)); > + satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in); > + satosin(&ifr.ifr_addr)->sin_family = AF_INET; > + satosin(&ifr.ifr_addr)->sin_addr = *addr; > + KERNEL_LOCK(); > + if ((*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr) != 0) { > KERNEL_UNLOCK(); > + goto out; > + } > + KERNEL_UNLOCK(); > > - TAILQ_INSERT_HEAD(&ifp->if_maddrlist, &inm->inm_ifma, > - ifma_list); > + rw_enter_write(&ifp->if_maddrlock); > + /* check again after unlock and lock */ > + inm = in_lookupmulti(addr, ifp); > + if (inm != NULL) > + goto found; > + inm = new_inm; > + inm->inm_sin.sin_len = sizeof(struct sockaddr_in); > + inm->inm_sin.sin_family = AF_INET; > + inm->inm_sin.sin_addr = *addr; > + refcnt_init_trace(&inm->inm_refcnt, DT_REFCNT_IDX_IFMADDR); > + inm->inm_ifidx = ifp->if_index; > + inm->inm_ifma.ifma_addr = sintosa(&inm->inm_sin); > > - /* > - * Let IGMP know that we have joined a new IP multicast group. > - */ > - igmp_joingroup(inm, ifp); > - } > + TAILQ_INSERT_HEAD(&ifp->if_maddrlist, &inm->inm_ifma, ifma_list); > + > + /* > + * Let IGMP know that we have joined a new IP multicast group. > + */ > + igmp_joingroup(inm, ifp); > + rw_exit_write(&ifp->if_maddrlock); > + > + return (inm); > > + found: > + refcnt_take(&inm->inm_refcnt); > + rw_exit_write(&ifp->if_maddrlock); > + out: > + free(new_inm, M_IPMADDR, sizeof(*inm)); > return (inm); > } > > @@ -931,19 +944,21 @@ in_delmulti(struct in_multi *inm) > struct ifreq ifr; > struct ifnet *ifp; > > - NET_ASSERT_LOCKED(); > - > if (refcnt_rele(&inm->inm_refcnt) == 0) > return; > > ifp = if_get(inm->inm_ifidx); > if (ifp != NULL) { > + rw_enter_write(&ifp->if_maddrlock); > /* > * No remaining claims to this record; let IGMP know that > * we are leaving the multicast group. > */ > igmp_leavegroup(inm, ifp); > > + TAILQ_REMOVE(&ifp->if_maddrlist, &inm->inm_ifma, ifma_list); > + rw_exit_write(&ifp->if_maddrlock); > + > /* > * Notify the network driver to update its multicast > * reception filter. > @@ -956,9 +971,8 @@ in_delmulti(struct in_multi *inm) > (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr); > KERNEL_UNLOCK(); > > - TAILQ_REMOVE(&ifp->if_maddrlist, &inm->inm_ifma, ifma_list); > + if_put(ifp); > } > - if_put(ifp); > > free(inm, M_IPMADDR, sizeof(*inm)); > } > @@ -973,8 +987,10 @@ in_hasmulti(const struct in_addr *addr, > struct in_multi *inm; > int joined; > > + rw_enter_read(&ifp->if_maddrlock); > inm = in_lookupmulti(addr, ifp); > joined = (inm != NULL); > + rw_exit_read(&ifp->if_maddrlock); > > return (joined); > } > Index: netinet/in_var.h > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/in_var.h,v > diff -u -p -r1.44 in_var.h > --- netinet/in_var.h 2 Dec 2025 15:52:04 -0000 1.44 > +++ netinet/in_var.h 2 Dec 2025 20:34:11 -0000 > @@ -87,11 +87,11 @@ struct in_multi { > #define inm_refcnt inm_ifma.ifma_refcnt > #define inm_ifidx inm_ifma.ifma_ifidx > > - struct sockaddr_in inm_sin; /* IPv4 multicast address */ > + struct sockaddr_in inm_sin; /* [I] IPv4 multicast address */ > #define inm_addr inm_sin.sin_addr > > - u_int inm_state; /* state of membership */ > - u_int inm_timer; /* IGMP membership report timer */ > + u_int inm_state; /* [m] state of membership */ > + u_int inm_timer; /* [m] IGMP membership report */ > > struct router_info *inm_rti; /* router version info */ > }; > Index: netinet6/in6.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/in6.c,v > diff -u -p -r1.275 in6.c > --- netinet6/in6.c 13 Nov 2025 23:30:01 -0000 1.275 > +++ netinet6/in6.c 2 Dec 2025 21:36:52 -0000 > @@ -1007,7 +1007,7 @@ in6_lookupmulti(const struct in6_addr *a > struct in6_multi *in6m = NULL; > struct ifmaddr *ifma; > > - NET_ASSERT_LOCKED(); > + rw_assert_anylock(&ifp->if_maddrlock); > > TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) { > if (ifma->ifma_addr->sa_family == AF_INET6 && > @@ -1026,62 +1026,71 @@ in6_lookupmulti(const struct in6_addr *a > struct in6_multi * > in6_addmulti(const struct in6_addr *addr, struct ifnet *ifp, int *errorp) > { > + struct in6_multi *in6m, *new_in6m = NULL; > struct in6_ifreq ifr; > - struct in6_multi *in6m; > - > - NET_ASSERT_LOCKED(); > > *errorp = 0; > /* > * See if address already in list. > */ > + rw_enter_write(&ifp->if_maddrlock); > in6m = in6_lookupmulti(addr, ifp); > - if (in6m != NULL) { > - /* > - * Found it; just increment the reference count. > - */ > - refcnt_take(&in6m->in6m_refcnt); > - } else { > - /* > - * New address; allocate a new multicast record > - * and link it into the interface's multicast list. > - */ > - in6m = malloc(sizeof(*in6m), M_IPMADDR, M_NOWAIT | M_ZERO); > - if (in6m == NULL) { > - *errorp = ENOBUFS; > - return (NULL); > - } > + if (in6m != NULL) > + goto found; > + rw_exit_write(&ifp->if_maddrlock); > > - in6m->in6m_sin.sin6_len = sizeof(struct sockaddr_in6); > - in6m->in6m_sin.sin6_family = AF_INET6; > - in6m->in6m_sin.sin6_addr = *addr; > - refcnt_init_trace(&in6m->in6m_refcnt, DT_REFCNT_IDX_IFMADDR); > - in6m->in6m_ifidx = ifp->if_index; > - in6m->in6m_ifma.ifma_addr = sin6tosa(&in6m->in6m_sin); > + /* > + * New address; allocate a new multicast record > + * and link it into the interface's multicast list. > + */ > + new_in6m = malloc(sizeof(*in6m), M_IPMADDR, M_NOWAIT | M_ZERO); > + if (new_in6m == NULL) { > + *errorp = ENOBUFS; > + return (NULL); > + } > > - /* > - * Ask the network driver to update its multicast reception > - * filter appropriately for the new address. > - */ > - memcpy(&ifr.ifr_addr, &in6m->in6m_sin, sizeof(in6m->in6m_sin)); > - KERNEL_LOCK(); > - *errorp = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr); > - KERNEL_UNLOCK(); > - if (*errorp) { > - free(in6m, M_IPMADDR, sizeof(*in6m)); > - return (NULL); > - } > + /* > + * Ask the network driver to update its multicast reception > + * filter appropriately for the new address. > + */ > + 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 = *addr; > + KERNEL_LOCK(); > + *errorp = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr); > + KERNEL_UNLOCK(); > + if (*errorp) > + goto out; > + > + rw_enter_write(&ifp->if_maddrlock); > + /* check again after unlock and lock */ > + in6m = in6_lookupmulti(addr, ifp); > + if (in6m != NULL) > + goto found; > + in6m = new_in6m; > + in6m->in6m_sin.sin6_len = sizeof(struct sockaddr_in6); > + in6m->in6m_sin.sin6_family = AF_INET6; > + in6m->in6m_sin.sin6_addr = *addr; > + refcnt_init_trace(&in6m->in6m_refcnt, DT_REFCNT_IDX_IFMADDR); > + in6m->in6m_ifidx = ifp->if_index; > + in6m->in6m_ifma.ifma_addr = sin6tosa(&in6m->in6m_sin); > + > + TAILQ_INSERT_HEAD(&ifp->if_maddrlist, &in6m->in6m_ifma, ifma_list); > > - TAILQ_INSERT_HEAD(&ifp->if_maddrlist, &in6m->in6m_ifma, > - ifma_list); > + /* > + * Let MLD6 know that we have joined a new IP6 multicast group. > + */ > + mld6_start_listening(in6m, ifp); > + rw_exit_write(&ifp->if_maddrlock); > > - /* > - * Let MLD6 know that we have joined a new IP6 multicast > - * group. > - */ > - mld6_start_listening(in6m); > - } > + return (in6m); > > + found: > + refcnt_take(&in6m->in6m_refcnt); > + rw_exit_write(&ifp->if_maddrlock); > + out: > + free(new_in6m, M_IPMADDR, sizeof(*in6m)); > return (in6m); > } > > @@ -1094,36 +1103,37 @@ in6_delmulti(struct in6_multi *in6m) > struct in6_ifreq ifr; > struct ifnet *ifp; > > - NET_ASSERT_LOCKED(); > + if (refcnt_rele(&in6m->in6m_refcnt) == 0) > + return; > > - if (refcnt_rele(&in6m->in6m_refcnt) != 0) { > + ifp = if_get(in6m->in6m_ifidx); > + if (ifp != NULL) { > + rw_enter_write(&ifp->if_maddrlock); > /* > * No remaining claims to this record; let MLD6 know > * that we are leaving the multicast group. > */ > - mld6_stop_listening(in6m); > - ifp = if_get(in6m->in6m_ifidx); > + mld6_stop_listening(in6m, ifp); > + > + TAILQ_REMOVE(&ifp->if_maddrlist, &in6m->in6m_ifma, ifma_list); > + rw_exit_write(&ifp->if_maddrlock); > > /* > * Notify the network driver to update its multicast > * reception filter. > */ > - if (ifp != NULL) { > - bzero(&ifr.ifr_addr, sizeof(struct sockaddr_in6)); > - ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6); > - ifr.ifr_addr.sin6_family = AF_INET6; > - ifr.ifr_addr.sin6_addr = in6m->in6m_addr; > - KERNEL_LOCK(); > - (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr); > - KERNEL_UNLOCK(); > + 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 = in6m->in6m_addr; > + KERNEL_LOCK(); > + (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr); > + KERNEL_UNLOCK(); > > - TAILQ_REMOVE(&ifp->if_maddrlist, &in6m->in6m_ifma, > - ifma_list); > - } > if_put(ifp); > - > - free(in6m, M_IPMADDR, sizeof(*in6m)); > } > + > + free(in6m, M_IPMADDR, sizeof(*in6m)); > } > > /* > @@ -1136,8 +1146,10 @@ in6_hasmulti(const struct in6_addr *addr > struct in6_multi *in6m; > int joined; > > + rw_enter_read(&ifp->if_maddrlock); > in6m = in6_lookupmulti(addr, ifp); > joined = (in6m != NULL); > + rw_exit_read(&ifp->if_maddrlock); > > return (joined); > } > Index: netinet6/in6_var.h > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/in6_var.h,v > diff -u -p -r1.82 in6_var.h > --- netinet6/in6_var.h 12 Nov 2025 11:37:08 -0000 1.82 > +++ netinet6/in6_var.h 2 Dec 2025 21:30:09 -0000 > @@ -316,11 +316,11 @@ struct in6_multi { > #define in6m_refcnt in6m_ifma.ifma_refcnt > #define in6m_ifidx in6m_ifma.ifma_ifidx > > - struct sockaddr_in6 in6m_sin; /* IPv6 multicast address */ > + struct sockaddr_in6 in6m_sin; /* [I] IPv6 multicast address */ > #define in6m_addr in6m_sin.sin6_addr > > - u_int in6m_state; /* state of membership */ > - u_int in6m_timer; /* MLD6 membership report timer */ > + u_int in6m_state; /* [m] state of membership */ > + u_int in6m_timer; /* [m] MLD6 membership report */ > }; > > static __inline struct in6_multi * > Index: netinet6/mld6.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/mld6.c,v > diff -u -p -r1.70 mld6.c > --- netinet6/mld6.c 12 Nov 2025 19:11:10 -0000 1.70 > +++ netinet6/mld6.c 2 Dec 2025 21:21:04 -0000 > @@ -112,12 +112,14 @@ mld6_init(void) > } > > void > -mld6_start_listening(struct in6_multi *in6m) > +mld6_start_listening(struct in6_multi *in6m, struct ifnet *ifp) > { > /* XXX: These are necessary for KAME's link-local hack */ > struct in6_addr all_nodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT; > int running = 0; > > + rw_assert_wrlock(&ifp->if_maddrlock); > + > /* > * RFC2710 page 10: > * The node never sends a Report or Done for the link-scope all-nodes > @@ -147,12 +149,14 @@ mld6_start_listening(struct in6_multi *i > } > > void > -mld6_stop_listening(struct in6_multi *in6m) > +mld6_stop_listening(struct in6_multi *in6m, struct ifnet *ifp) > { > /* XXX: These are necessary for KAME's link-local hack */ > struct in6_addr all_nodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT; > struct in6_addr all_routers = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; > > + rw_assert_anylock(&ifp->if_maddrlock); > + > all_nodes.s6_addr16[1] = htons(in6m->in6m_ifidx); > /* XXX: necessary when mrouting */ > all_routers.s6_addr16[1] = htons(in6m->in6m_ifidx); > @@ -254,6 +258,7 @@ mld6_input(struct mbuf *m, int off) > timer = 1; > all_nodes.s6_addr16[1] = htons(ifp->if_index); > > + rw_enter_write(&ifp->if_maddrlock); > TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) { > if (ifma->ifma_addr->sa_family != AF_INET6) > continue; > @@ -281,6 +286,7 @@ mld6_input(struct mbuf *m, int off) > } > } > } > + rw_exit_write(&ifp->if_maddrlock); > > if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr)) > mldh->mld_addr.s6_addr16[1] = 0; /* XXX */ > @@ -308,11 +314,13 @@ mld6_input(struct mbuf *m, int off) > * If we belong to the group being reported, stop > * our timer for that group. > */ > + rw_enter_write(&ifp->if_maddrlock); > in6m = in6_lookupmulti(&mldh->mld_addr, ifp); > if (in6m) { > in6m->in6m_timer = 0; /* transit to idle state */ > in6m->in6m_state = MLD_OTHERLISTENER; /* clear flag */ > } > + rw_exit_write(&ifp->if_maddrlock); > > if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr)) > mldh->mld_addr.s6_addr16[1] = 0; /* XXX */ > @@ -355,7 +363,7 @@ mld6_fasttimo(void) > return; > membar_consumer(); > > - NET_LOCK(); > + NET_LOCK_SHARED(); > > TAILQ_FOREACH(ifp, &ifnetlist, if_list) { > if (mld6_checktimer(ifp)) > @@ -365,7 +373,7 @@ mld6_fasttimo(void) > membar_producer(); > atomic_store_int(&mld6_timers_are_running, running); > > - NET_UNLOCK(); > + NET_UNLOCK_SHARED(); > } > > int > @@ -375,8 +383,7 @@ mld6_checktimer(struct ifnet *ifp) > struct ifmaddr *ifma; > int running = 0; > > - NET_ASSERT_LOCKED(); > - > + rw_enter_write(&ifp->if_maddrlock); > TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) { > if (ifma->ifma_addr->sa_family != AF_INET6) > continue; > @@ -390,6 +397,7 @@ mld6_checktimer(struct ifnet *ifp) > running = 1; > } > } > + rw_exit_write(&ifp->if_maddrlock); > > return (running); > } > Index: netinet6/mld6_var.h > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/mld6_var.h,v > diff -u -p -r1.7 mld6_var.h > --- netinet6/mld6_var.h 12 Nov 2025 19:11:10 -0000 1.7 > +++ netinet6/mld6_var.h 2 Dec 2025 20:58:44 -0000 > @@ -45,8 +45,8 @@ > > void mld6_init(void); > void mld6_input(struct mbuf *, int); > -void mld6_start_listening(struct in6_multi *); > -void mld6_stop_listening(struct in6_multi *); > +void mld6_start_listening(struct in6_multi *, struct ifnet *); > +void mld6_stop_listening(struct in6_multi *, struct ifnet *); > void mld6_fasttimo(void); > #endif /* _KERNEL */ >