Ensure to call if_mcast_op with holding IFNET_LOCK

Note that CARP doesn't deal with IFNET_LOCK yet.
This commit is contained in:
ozaki-r 2017-12-15 04:03:46 +00:00
parent 8644c58702
commit bde7231efb
11 changed files with 158 additions and 34 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: if.c,v 1.414 2017/12/14 05:46:54 ozaki-r Exp $ */
/* $NetBSD: if.c,v 1.415 2017/12/15 04:03:46 ozaki-r Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@ -90,7 +90,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.414 2017/12/14 05:46:54 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.415 2017/12/15 04:03:46 ozaki-r Exp $");
#if defined(_KERNEL_OPT)
#include "opt_inet.h"
@ -2721,12 +2721,27 @@ if_put(const struct ifnet *ifp, struct psref *psref)
psref_release(psref, &ifp->if_psref, ifnet_psref_class);
}
/*
* Return ifp having idx. Return NULL if not found. Normally if_byindex
* should be used.
*/
ifnet_t *
_if_byindex(u_int idx)
{
return (__predict_true(idx < if_indexlim)) ? ifindex2ifnet[idx] : NULL;
}
/*
* Return ifp having idx. Return NULL if not found or the found ifp is
* already deactivated.
*/
ifnet_t *
if_byindex(u_int idx)
{
ifnet_t *ifp;
ifp = (__predict_true(idx < if_indexlim)) ? ifindex2ifnet[idx] : NULL;
ifp = _if_byindex(idx);
if (ifp != NULL && if_is_deactivated(ifp))
ifp = NULL;
return ifp;
@ -3570,6 +3585,10 @@ if_mcast_op(ifnet_t *ifp, const unsigned long cmd, const struct sockaddr *sa)
int rc;
struct ifreq ifr;
/* CARP still doesn't deal with the lock yet */
#if !defined(NCARP) || (NCARP == 0)
KASSERT(IFNET_LOCKED(ifp));
#endif
if (ifp->if_mcastop != NULL)
rc = (*ifp->if_mcastop)(ifp, cmd, sa);
else {

View File

@ -1,4 +1,4 @@
/* $NetBSD: if.h,v 1.253 2017/12/11 03:29:20 ozaki-r Exp $ */
/* $NetBSD: if.h,v 1.254 2017/12/15 04:03:46 ozaki-r Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
@ -1026,6 +1026,7 @@ int if_clone_list(int, char *, int *);
struct ifnet *ifunit(const char *);
struct ifnet *if_get(const char *, struct psref *);
ifnet_t *if_byindex(u_int);
ifnet_t *_if_byindex(u_int);
ifnet_t *if_get_byindex(u_int, struct psref *);
ifnet_t *if_get_bylla(const void *, unsigned char, struct psref *);
void if_put(const struct ifnet *, struct psref *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_vlan.c,v 1.119 2017/12/11 03:29:20 ozaki-r Exp $ */
/* $NetBSD: if_vlan.c,v 1.120 2017/12/15 04:03:46 ozaki-r Exp $ */
/*-
* Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
@ -78,7 +78,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 1.119 2017/12/11 03:29:20 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 1.120 2017/12/15 04:03:46 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -1160,7 +1160,9 @@ vlan_ether_addmulti(struct ifvlan *ifv, struct ifreq *ifr)
mib = ifv->ifv_mib;
KERNEL_LOCK_UNLESS_IFP_MPSAFE(mib->ifvm_p);
IFNET_LOCK(mib->ifvm_p);
error = if_mcast_op(mib->ifvm_p, SIOCADDMULTI, sa);
IFNET_UNLOCK(mib->ifvm_p);
KERNEL_UNLOCK_UNLESS_IFP_MPSAFE(mib->ifvm_p);
if (error != 0)
@ -1201,7 +1203,9 @@ vlan_ether_delmulti(struct ifvlan *ifv, struct ifreq *ifr)
/* We no longer use this multicast address. Tell parent so. */
mib = ifv->ifv_mib;
IFNET_LOCK(mib->ifvm_p);
error = if_mcast_op(mib->ifvm_p, SIOCDELMULTI, sa);
IFNET_UNLOCK(mib->ifvm_p);
if (error == 0) {
/* And forget about this address. */
@ -1236,8 +1240,10 @@ vlan_ether_purgemulti(struct ifvlan *ifv)
}
while ((mc = LIST_FIRST(&ifv->ifv_mc_listhead)) != NULL) {
IFNET_LOCK(mib->ifvm_p);
(void)if_mcast_op(mib->ifvm_p, SIOCDELMULTI,
(const struct sockaddr *)&mc->mc_addr);
IFNET_UNLOCK(mib->ifvm_p);
LIST_REMOVE(mc, mc_entries);
free(mc, M_DEVBUF);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: in.c,v 1.210 2017/11/17 07:37:12 ozaki-r Exp $ */
/* $NetBSD: in.c,v 1.211 2017/12/15 04:03:46 ozaki-r Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -91,7 +91,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.210 2017/11/17 07:37:12 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.211 2017/12/15 04:03:46 ozaki-r Exp $");
#include "arp.h"
@ -912,11 +912,14 @@ in_addrhash_remove(struct in_ifaddr *ia)
void
in_purgeif(struct ifnet *ifp) /* MUST be called at splsoftnet() */
{
IFNET_LOCK(ifp);
if_purgeaddrs(ifp, AF_INET, in_purgeaddr);
igmp_purgeif(ifp); /* manipulates pools */
#ifdef MROUTING
ip_mrouter_detach(ifp);
#endif
IFNET_UNLOCK(ifp);
}
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: in_pcb.c,v 1.179 2017/08/10 04:31:58 ryo Exp $ */
/* $NetBSD: in_pcb.c,v 1.180 2017/12/15 04:03:46 ozaki-r Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -93,7 +93,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1.179 2017/08/10 04:31:58 ryo Exp $");
__KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1.180 2017/12/15 04:03:46 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -777,7 +777,10 @@ in_pcbpurgeif0(struct inpcbtable *table, struct ifnet *ifp)
need_unlock = true;
}
/* IFNET_LOCK must be taken after solock */
IFNET_LOCK(ifp);
in_purgeifmcast(inp->inp_moptions, ifp);
IFNET_UNLOCK(ifp);
if (need_unlock)
inp_unlock(inp);

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_output.c,v 1.286 2017/12/11 05:47:18 ryo Exp $ */
/* $NetBSD: ip_output.c,v 1.287 2017/12/15 04:03:46 ozaki-r Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -91,7 +91,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.286 2017/12/11 05:47:18 ryo Exp $");
__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.287 2017/12/15 04:03:46 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -1771,7 +1771,10 @@ ip_add_membership(struct ip_moptions *imo, const struct sockopt *sopt)
* Everything looks good; add a new record to the multicast
* address list for the given interface.
*/
if ((imo->imo_membership[i] = in_addmulti(&ia, ifp)) == NULL) {
IFNET_LOCK(ifp);
imo->imo_membership[i] = in_addmulti(&ia, ifp);
IFNET_UNLOCK(ifp);
if (imo->imo_membership[i] == NULL) {
error = ENOBUFS;
goto out;
}
@ -1830,7 +1833,9 @@ ip_drop_membership(struct ip_moptions *imo, const struct sockopt *sopt)
* Give up the multicast address record to which the
* membership points.
*/
IFNET_LOCK(ifp);
in_delmulti(imo->imo_membership[i]);
IFNET_UNLOCK(ifp);
/*
* Remove the gap in the membership array.
@ -2023,8 +2028,15 @@ ip_freemoptions(struct ip_moptions *imo)
/* The owner of imo (inp) should be protected by solock */
if (imo != NULL) {
for (i = 0; i < imo->imo_num_memberships; ++i)
in_delmulti(imo->imo_membership[i]);
for (i = 0; i < imo->imo_num_memberships; ++i) {
struct in_multi *inm = imo->imo_membership[i];
struct ifnet *ifp = inm->inm_ifp;
IFNET_LOCK(ifp);
in_delmulti(inm);
/* ifp should not leave thanks to solock */
IFNET_UNLOCK(ifp);
}
kmem_intr_free(imo, sizeof(*imo));
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: in6.c,v 1.254 2017/11/23 07:09:20 ozaki-r Exp $ */
/* $NetBSD: in6.c,v 1.255 2017/12/15 04:03:46 ozaki-r Exp $ */
/* $KAME: in6.c,v 1.198 2001/07/18 09:12:38 itojun Exp $ */
/*
@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.254 2017/11/23 07:09:20 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.255 2017/12/15 04:03:46 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -1385,6 +1385,7 @@ in6_purgeaddr(struct ifaddr *ifa)
struct in6_multi_mship *imm;
KASSERT(!ifa_held(ifa));
KASSERT(IFNET_LOCKED(ifp));
ifa->ifa_flags |= IFA_DESTROYING;
@ -1400,12 +1401,14 @@ in6_purgeaddr(struct ifaddr *ifa)
/*
* leave from multicast groups we have joined for the interface
*/
again:
mutex_enter(&in6_ifaddr_lock);
while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) {
LIST_REMOVE(imm, i6mm_chain);
mutex_exit(&in6_ifaddr_lock);
KASSERT(imm->i6mm_maddr->in6m_ifp == ifp);
in6_leavegroup(imm);
mutex_enter(&in6_ifaddr_lock);
goto again;
}
mutex_exit(&in6_ifaddr_lock);
@ -1456,7 +1459,9 @@ void
in6_purgeif(struct ifnet *ifp)
{
IFNET_LOCK(ifp);
in6_ifdetach(ifp);
IFNET_UNLOCK(ifp);
}
void

View File

@ -1,4 +1,4 @@
/* $NetBSD: in6_pcb.c,v 1.161 2017/04/25 05:44:11 ozaki-r Exp $ */
/* $NetBSD: in6_pcb.c,v 1.162 2017/12/15 04:03:46 ozaki-r Exp $ */
/* $KAME: in6_pcb.c,v 1.84 2001/02/08 18:02:08 itojun Exp $ */
/*
@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: in6_pcb.c,v 1.161 2017/04/25 05:44:11 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: in6_pcb.c,v 1.162 2017/12/15 04:03:46 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -875,11 +875,18 @@ in6_pcbpurgeif0(struct inpcbtable *table, struct ifnet *ifp)
i6mm_chain, nimm) {
if (imm->i6mm_maddr->in6m_ifp == ifp) {
LIST_REMOVE(imm, i6mm_chain);
IFNET_LOCK(ifp);
in6_leavegroup(imm);
IFNET_UNLOCK(ifp);
}
}
}
/* IFNET_LOCK must be taken after solock */
IFNET_LOCK(ifp);
in_purgeifmcast(in6p->in6p_v4moptions, ifp);
IFNET_UNLOCK(ifp);
if (need_unlock)
in6p_unlock(in6p);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip6_output.c,v 1.195 2017/11/25 13:18:02 kre Exp $ */
/* $NetBSD: ip6_output.c,v 1.196 2017/12/15 04:03:46 ozaki-r Exp $ */
/* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */
/*
@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.195 2017/11/25 13:18:02 kre Exp $");
__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.196 2017/12/15 04:03:46 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -2606,7 +2606,9 @@ ip6_setmoptions(const struct sockopt *sopt, struct in6pcb *in6p)
* Everything looks good; add a new record to the multicast
* address list for the given interface.
*/
IFNET_LOCK(ifp);
imm = in6_joingroup(ifp, &ia, &error, 0);
IFNET_UNLOCK(ifp);
if (imm == NULL)
goto put_break;
LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain);
@ -2616,7 +2618,8 @@ ip6_setmoptions(const struct sockopt *sopt, struct in6pcb *in6p)
break;
}
case IPV6_LEAVE_GROUP:
case IPV6_LEAVE_GROUP: {
struct ifnet *in6m_ifp;
/*
* Drop a multicast group membership.
* Group must be a valid IP6 multicast address.
@ -2698,8 +2701,13 @@ ip6_setmoptions(const struct sockopt *sopt, struct in6pcb *in6p)
* membership points.
*/
LIST_REMOVE(imm, i6mm_chain);
in6m_ifp = imm->i6mm_maddr->in6m_ifp;
IFNET_LOCK(in6m_ifp);
in6_leavegroup(imm);
/* in6m_ifp should not leave thanks to in6p_lock */
IFNET_UNLOCK(in6m_ifp);
break;
}
default:
error = EOPNOTSUPP;
@ -2778,8 +2786,15 @@ ip6_freemoptions(struct ip6_moptions *im6o)
/* The owner of im6o (in6p) should be protected by solock */
LIST_FOREACH_SAFE(imm, &im6o->im6o_memberships, i6mm_chain, nimm) {
struct ifnet *ifp;
LIST_REMOVE(imm, i6mm_chain);
ifp = imm->i6mm_maddr->in6m_ifp;
IFNET_LOCK(ifp);
in6_leavegroup(imm);
/* ifp should not leave thanks to solock */
IFNET_UNLOCK(ifp);
}
free(im6o, M_IPMOPTS);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: nd6.c,v 1.239 2017/11/17 07:37:12 ozaki-r Exp $ */
/* $NetBSD: nd6.c,v 1.240 2017/12/15 04:03:46 ozaki-r Exp $ */
/* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */
/*
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.239 2017/11/17 07:37:12 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.240 2017/12/15 04:03:46 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_net_mpsafe.h"
@ -614,6 +614,7 @@ nd6_timer_work(struct work *wk, void *arg)
/* check address lifetime */
if (IFA6_IS_INVALID(ia6)) {
int regen = 0;
struct ifnet *ifp;
/*
* If the expiring address is temporary, try
@ -627,13 +628,30 @@ nd6_timer_work(struct work *wk, void *arg)
*/
if (ip6_use_tempaddr &&
(ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0) {
IFNET_LOCK(ia6->ia_ifa.ifa_ifp);
if (regen_tmpaddr(ia6) == 0)
regen = 1;
IFNET_UNLOCK(ia6->ia_ifa.ifa_ifp);
}
ia6_release(ia6, &psref);
in6_purgeaddr(&ia6->ia_ifa);
ifp = ia6->ia_ifa.ifa_ifp;
IFNET_LOCK(ifp);
/*
* Need to take the lock first to prevent if_detach
* from running in6_purgeaddr concurrently.
*/
if (!if_is_deactivated(ifp)) {
ia6_release(ia6, &psref);
in6_purgeaddr(&ia6->ia_ifa);
} else {
/*
* ifp is being destroyed, ia6 will be destroyed
* by if_detach.
*/
ia6_release(ia6, &psref);
}
ia6 = NULL;
IFNET_UNLOCK(ifp);
if (regen)
goto addrloop; /* XXX: see below */
@ -1883,20 +1901,53 @@ nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp)
_s = pserialize_read_enter();
for (ia = IN6_ADDRLIST_READER_FIRST(); ia;
ia = ia_next) {
struct ifnet *ifa_ifp;
int bound;
struct psref psref;
/* ia might be removed. keep the next ptr. */
ia_next = IN6_ADDRLIST_READER_NEXT(ia);
if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0)
continue;
if (ia->ia6_ndpr == pfx) {
pserialize_read_exit(_s);
ND6_UNLOCK();
/* XXX NOMPSAFE? */
/* in6_purgeaddr may destroy pfx. */
if (ia->ia6_ndpr != pfx)
continue;
bound = curlwp_bind();
ia6_acquire(ia, &psref);
pserialize_read_exit(_s);
ND6_UNLOCK();
ifa_ifp = ia->ia_ifa.ifa_ifp;
if (ifa_ifp == ifp) {
/* Already have IFNET_LOCK(ifp) */
KASSERT(!if_is_deactivated(ifp));
ia6_release(ia, &psref);
in6_purgeaddr(&ia->ia_ifa);
curlwp_bindx(bound);
goto restart;
}
IFNET_LOCK(ifa_ifp);
/*
* Need to take the lock first to prevent
* if_detach from running in6_purgeaddr
* concurrently.
*/
if (!if_is_deactivated(ifa_ifp)) {
ia6_release(ia, &psref);
in6_purgeaddr(&ia->ia_ifa);
} else {
/*
* ifp is being destroyed, ia will be
* destroyed by if_detach.
*/
ia6_release(ia, &psref);
/* XXX may cause busy loop */
}
IFNET_UNLOCK(ifa_ifp);
curlwp_bindx(bound);
goto restart;
}
pserialize_read_exit(_s);

View File

@ -1,4 +1,4 @@
/* $NetBSD: nd6_rtr.c,v 1.135 2017/03/14 04:21:38 ozaki-r Exp $ */
/* $NetBSD: nd6_rtr.c,v 1.136 2017/12/15 04:03:46 ozaki-r Exp $ */
/* $KAME: nd6_rtr.c,v 1.95 2001/02/07 08:09:47 itojun Exp $ */
/*
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: nd6_rtr.c,v 1.135 2017/03/14 04:21:38 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: nd6_rtr.c,v 1.136 2017/12/15 04:03:46 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_net_mpsafe.h"
@ -319,6 +319,7 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len)
IN6_PRINT(ip6buf, &ip6->ip6_src),
if_name(ifp), ndi->chlim, nd_ra->nd_ra_curhoplimit);
}
IFNET_LOCK(ifp);
ND6_WLOCK();
dr = defrtrlist_update(&drtr);
}
@ -378,6 +379,7 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len)
}
}
ND6_UNLOCK();
IFNET_UNLOCK(ifp);
/*
* MTU