From: Alexander Bluhm Subject: unlock igmp and mld6 fast timer To: tech@openbsd.org Date: Tue, 2 Dec 2025 23:01:36 +0100 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 */