/*
- * Copyright (c) 2003-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
*/
int ip6_temp_regen_advance = TEMPADDR_REGEN_ADVANCE;
-extern lck_mtx_t *rt_mtx;
extern lck_mtx_t *nd6_mutex;
/*
int icmp6len)
{
struct ifnet *ifp = m->m_pkthdr.rcvif;
- struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index];
+ struct nd_ifinfo *ndi = NULL;
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
struct nd_router_advert *nd_ra;
struct in6_addr saddr6 = ip6->ip6_src;
struct nd_defrouter dr0;
u_int32_t advreachable = nd_ra->nd_ra_reachable;
+ lck_rw_lock_shared(nd_if_rwlock);
+ if (ifp->if_index >= nd_ifinfo_indexlim) {
+ lck_rw_done(nd_if_rwlock);
+ goto freeit;
+ }
+ ndi = &nd_ifinfo[ifp->if_index];
dr0.rtaddr = saddr6;
dr0.flags = nd_ra->nd_ra_flags_reserved;
dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
ndi->retrans = ntohl(nd_ra->nd_ra_retransmit);
if (nd_ra->nd_ra_curhoplimit)
ndi->chlim = nd_ra->nd_ra_curhoplimit;
+ lck_rw_done(nd_if_rwlock);
+ ndi = NULL;
dr = defrtrlist_update(&dr0);
}
goto skip;
}
+ lck_rw_lock_shared(nd_if_rwlock);
+ if (ifp->if_index >= nd_ifinfo_indexlim) {
+ lck_rw_done(nd_if_rwlock);
+ goto freeit;
+ }
+ ndi = &nd_ifinfo[ifp->if_index];
/* upper bound */
if (ndi->maxmtu) {
if (mtu <= ndi->maxmtu) {
int change = (ndi->linkmtu != mtu);
ndi->linkmtu = mtu;
+ lck_rw_done(nd_if_rwlock);
if (change) /* in6_maxmtu may change */
in6_setmaxmtu();
} else {
"exceeds maxmtu %d, ignoring\n",
mtu, ip6_sprintf(&ip6->ip6_src),
ndi->maxmtu));
+ lck_rw_done(nd_if_rwlock);
}
} else {
+ lck_rw_done(nd_if_rwlock);
nd6log((LOG_INFO, "nd6_ra_input: mtu option "
"mtu=%d sent from %s; maxmtu unknown, "
"ignoring\n",
mtu, ip6_sprintf(&ip6->ip6_src)));
}
+ ndi = NULL;
}
skip:
struct rtentry *rt;
{
struct rt_addrinfo info;
+ struct ifnet *ifp = rt->rt_ifp;
- lck_mtx_assert(rt_mtx, LCK_MTX_ASSERT_OWNED);
+ RT_LOCK_ASSERT_HELD(rt);
bzero((caddr_t)&info, sizeof(info));
+ /* Lock ifp for if_addrlist */
+ ifnet_lock_shared(ifp);
info.rti_info[RTAX_DST] = rt_key(rt);
info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
info.rti_info[RTAX_NETMASK] = rt_mask(rt);
info.rti_info[RTAX_IFP] =
- TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr;
+ TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr;
info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
rt_missmsg(cmd, &info, rt->rt_flags, 0);
+ ifnet_lock_done(ifp);
}
void
def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6;
gate.sin6_addr = new->rtaddr;
- lck_mtx_lock(rt_mtx);
- (void)rtrequest_locked(RTM_ADD, (struct sockaddr *)&def,
- (struct sockaddr *)&gate, (struct sockaddr *)&mask,
- RTF_GATEWAY, &newrt);
+ (void) rtrequest(RTM_ADD, (struct sockaddr *)&def,
+ (struct sockaddr *)&gate, (struct sockaddr *)&mask,
+ RTF_GATEWAY, &newrt);
if (newrt) {
+ RT_LOCK(newrt);
nd6_rtmsg(RTM_ADD, newrt); /* tell user process */
- rtunref(newrt);
+ RT_REMREF_LOCKED(newrt);
+ RT_UNLOCK(newrt);
}
- lck_mtx_unlock(rt_mtx);
return;
}
struct ifaddr *ifa = NULL;
struct rtentry *newrt = NULL;
int error;
- u_long flags;
+ u_int32_t flags;
bzero(&def, sizeof(def));
bzero(&mask, sizeof(mask));
return;
}
- lck_mtx_lock(rt_mtx);
flags = ifa->ifa_flags;
- error = rtrequest_locked(RTM_ADD, (struct sockaddr *)&def, ifa->ifa_addr,
- (struct sockaddr *)&mask, flags, &newrt);
+ error = rtrequest(RTM_ADD, (struct sockaddr *)&def, ifa->ifa_addr,
+ (struct sockaddr *)&mask, flags, &newrt);
if (error != 0) {
nd6log((LOG_ERR,
"defrouter_addifreq: failed to install a route to "
"interface %s (errno = %d)\n",
if_name(ifp), error));
-
- if (newrt) /* maybe unnecessary, but do it for safety */
- rtunref(newrt);
} else {
if (newrt) {
+ RT_LOCK(newrt);
nd6_rtmsg(RTM_ADD, newrt);
- rtunref(newrt);
+ RT_REMREF_LOCKED(newrt);
+ RT_UNLOCK(newrt);
}
in6_post_msg(ifp, KEV_INET6_DEFROUTER, (struct in6_ifaddr *)ifa);
}
- lck_mtx_unlock(rt_mtx);
ifafree(ifa);
}
def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6;
gate.sin6_addr = dr->rtaddr;
- lck_mtx_lock(rt_mtx);
- rtrequest_locked(RTM_DELETE, (struct sockaddr *)&def,
- (struct sockaddr *)&gate,
- (struct sockaddr *)&mask,
- RTF_GATEWAY, &oldrt);
+ (void) rtrequest(RTM_DELETE, (struct sockaddr *)&def,
+ (struct sockaddr *)&gate, (struct sockaddr *)&mask,
+ RTF_GATEWAY, &oldrt);
if (oldrt) {
+ RT_LOCK(oldrt);
nd6_rtmsg(RTM_DELETE, oldrt);
- rtfree_locked(oldrt);
+ RT_UNLOCK(oldrt);
+ rtfree(oldrt);
}
if (dofree) /* XXX: necessary? */
FREE(dr, M_IP6NDP);
- lck_mtx_unlock(rt_mtx);
}
void
struct nd_defrouter *dr, int nd6locked)
{
struct nd_defrouter *deldr = NULL;
- struct nd_ifinfo *ndi = &nd_ifinfo[dr->ifp->if_index];
struct nd_prefix *pr;
+ struct ifnet *ifp = dr->ifp;
/*
* Flush all the routing table entries that use the router
* as a next hop.
*/
- if (!ip6_forwarding && (ip6_accept_rtadv || (dr->ifp->if_eflags & IFEF_ACCEPT_RTADVD))) {
+ if (!ip6_forwarding &&
+ (ip6_accept_rtadv || (ifp->if_eflags & IFEF_ACCEPT_RTADVD))) {
/* above is a good condition? */
- rt6_flush(&dr->rtaddr, dr->ifp);
+ rt6_flush(&dr->rtaddr, ifp);
}
if (nd6locked == 0)
if (deldr)
defrouter_select();
- ndi->ndefrouters--;
- if (ndi->ndefrouters < 0) {
- log(LOG_WARNING, "defrtrlist_del: negative count on %s\n",
- if_name(dr->ifp));
+ lck_rw_lock_shared(nd_if_rwlock);
+ if (ifp->if_index < nd_ifinfo_indexlim) {
+ struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index];
+ ndi->ndefrouters--;
+ if (ndi->ndefrouters < 0) {
+ log(LOG_WARNING, "defrtrlist_del: negative "
+ "count on %s\n", if_name(ifp));
+ }
}
+ lck_rw_done(nd_if_rwlock);
if (nd6locked == 0)
lck_mtx_unlock(nd6_mutex);
for (dr = TAILQ_FIRST(&nd_defrouter); dr;
dr = TAILQ_NEXT(dr, dr_entry)) {
- if ((rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp, 0)) &&
- (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
- ND6_IS_LLINFO_PROBREACH(ln)) {
- /* Got it, and move it to the head */
- TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
- TAILQ_INSERT_HEAD(&nd_defrouter, dr, dr_entry);
- break;
+ /* Callee returns a locked route upon success */
+ if ((rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp, 0)) != NULL) {
+ RT_LOCK_ASSERT_HELD(rt);
+ if ((ln = rt->rt_llinfo) != NULL &&
+ ND6_IS_LLINFO_PROBREACH(ln)) {
+ RT_REMREF_LOCKED(rt);
+ RT_UNLOCK(rt);
+ /* Got it, and move it to the head */
+ TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
+ TAILQ_INSERT_HEAD(&nd_defrouter, dr, dr_entry);
+ break;
+ }
+ RT_REMREF_LOCKED(rt);
+ RT_UNLOCK(rt);
}
}
struct nd_defrouter *new)
{
struct nd_defrouter *dr, *n;
- struct nd_ifinfo *ndi = &nd_ifinfo[new->ifp->if_index];
+ struct ifnet *ifp = new->ifp;
+ struct nd_ifinfo *ndi;
lck_mtx_lock(nd6_mutex);
- if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) {
+ if ((dr = defrouter_lookup(&new->rtaddr, ifp)) != NULL) {
/* entry exists */
if (new->rtlifetime == 0) {
defrtrlist_del(dr, 1);
return(NULL);
}
+ n = (struct nd_defrouter *)_MALLOC(sizeof(*n), M_IP6NDP, M_NOWAIT);
+ if (n == NULL) {
+ lck_mtx_unlock(nd6_mutex);
+ return(NULL);
+ }
+
+ lck_rw_lock_shared(nd_if_rwlock);
+ if (ifp->if_index >= nd_ifinfo_indexlim)
+ goto freeit;
+ ndi = &nd_ifinfo[ifp->if_index];
if (ip6_maxifdefrouters >= 0 &&
ndi->ndefrouters >= ip6_maxifdefrouters) {
+freeit:
+ lck_rw_done(nd_if_rwlock);
lck_mtx_unlock(nd6_mutex);
+ FREE(n, M_IP6NDP);
return (NULL);
}
+ ndi->ndefrouters++;
+ lck_rw_done(nd_if_rwlock);
- n = (struct nd_defrouter *)_MALLOC(sizeof(*n), M_IP6NDP, M_NOWAIT);
- if (n == NULL) {
- lck_mtx_unlock(nd6_mutex);
- return(NULL);
- }
bzero(n, sizeof(*n));
*n = *new;
TAILQ_INSERT_TAIL(&nd_defrouter, n, dr_entry);
if (TAILQ_FIRST(&nd_defrouter) == n)
defrouter_select();
-
- ndi->ndefrouters++;
-
+
lck_mtx_unlock(nd6_mutex);
return(n);
}
struct nd_prefix *pr, *pr_next;
struct in6_ifaddr *ia;
struct ifaddr *ifa, *ifa_next;
-
+
lck_mtx_lock(nd6_mutex);
for (pr = nd_prefix.lh_first; pr; pr = pr_next) {
((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
!LIST_EMPTY(&pr->ndpr_advrtrs)))
continue;
-
+repeat:
+ ifnet_lock_shared(ifp);
for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa_next) {
ifa_next = ifa->ifa_list.tqe_next;
if (ifa->ifa_addr->sa_family != AF_INET6)
ia = (struct in6_ifaddr *)ifa;
if ((ia->ia6_flags & IN6_IFF_AUTOCONF) ==
IN6_IFF_AUTOCONF && ia->ia6_ndpr == pr) {
+ ifaref(ifa);
+ /*
+ * Purging the address requires writer access
+ * to the address list, so drop the ifnet lock
+ * now and repeat from beginning.
+ */
+ ifnet_lock_done(ifp);
in6_purgeaddr(ifa, 1);
+ ifafree(ifa);
+ goto repeat;
}
}
+ ifnet_lock_done(ifp);
if (pr->ndpr_refcnt == 0)
prelist_remove(pr, 1);
}
struct nd_prefix **newp)
{
struct nd_prefix *new = NULL;
+ struct ifnet *ifp = pr->ndpr_ifp;
+ struct nd_ifinfo *ndi = NULL;
int i;
- struct nd_ifinfo *ndi = &nd_ifinfo[pr->ndpr_ifp->if_index];
if (ip6_maxifprefixes >= 0) {
- if (ndi->nprefixes >= ip6_maxifprefixes / 2)
- purge_detached(pr->ndpr_ifp);
- if (ndi->nprefixes >= ip6_maxifprefixes)
+ lck_rw_lock_shared(nd_if_rwlock);
+ if (ifp->if_index >= nd_ifinfo_indexlim) {
+ lck_rw_done(nd_if_rwlock);
+ return (EINVAL);
+ }
+ ndi = &nd_ifinfo[ifp->if_index];
+ if (ndi->nprefixes >= ip6_maxifprefixes / 2) {
+ lck_rw_done(nd_if_rwlock);
+ purge_detached(ifp);
+ lck_rw_lock_shared(nd_if_rwlock);
+ /*
+ * Refresh pointer since nd_ifinfo[] may have grown;
+ * repeating the bounds check against nd_ifinfo_indexlim
+ * isn't necessary since the array never shrinks.
+ */
+ ndi = &nd_ifinfo[ifp->if_index];
+ }
+ if (ndi->nprefixes >= ip6_maxifprefixes) {
+ lck_rw_done(nd_if_rwlock);
return(ENOMEM);
+ }
+ lck_rw_done(nd_if_rwlock);
}
new = (struct nd_prefix *)_MALLOC(sizeof(*new), M_IP6NDP, M_NOWAIT);
nd6log((LOG_ERR, "nd6_prelist_add: failed to make "
"the prefix %s/%d on-link on %s (errno=%d)\n",
ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
- pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
+ pr->ndpr_plen, if_name(ifp), e));
/* proceed anyway. XXX: is it correct? */
}
}
pfxrtr_add(new, dr);
}
+ lck_rw_lock_shared(nd_if_rwlock);
+ /*
+ * Refresh pointer since nd_ifinfo[] may have grown;
+ * repeating the bounds check against nd_ifinfo_indexlim
+ * isn't necessary since the array never shrinks.
+ */
+ ndi = &nd_ifinfo[ifp->if_index];
ndi->nprefixes++;
+ lck_rw_done(nd_if_rwlock);
lck_mtx_unlock(nd6_mutex);
struct nd_prefix *pr, int nd6locked)
{
struct nd_pfxrouter *pfr, *next;
+ struct ifnet *ifp = pr->ndpr_ifp;
int e;
- struct nd_ifinfo *ndi = &nd_ifinfo[pr->ndpr_ifp->if_index];
/* make sure to invalidate the prefix until it is really freed. */
pr->ndpr_vltime = 0;
nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink "
"on %s, errno=%d\n",
ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
- pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
+ pr->ndpr_plen, if_name(ifp), e));
/* what should we do? */
}
FREE(pfr, M_IP6NDP);
}
- ndi->nprefixes--;
- if (ndi->nprefixes < 0) {
- log(LOG_WARNING, "prelist_remove: negative count on %s\n",
- if_name(pr->ndpr_ifp));
+ lck_rw_lock_shared(nd_if_rwlock);
+ if (ifp->if_index < nd_ifinfo_indexlim) {
+ struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index];
+ ndi->nprefixes--;
+ if (ndi->nprefixes < 0) {
+ log(LOG_WARNING, "prelist_remove: negative "
+ "count on %s\n", if_name(ifp));
+ }
}
+ lck_rw_done(nd_if_rwlock);
FREE(pr, M_IP6NDP);
*/
if (ip6_use_tempaddr) {
int e;
- if ((e = in6_tmpifadd(ia6, 1)) != 0) {
+ if ((e = in6_tmpifadd(ia6, 1, M_NOWAIT)) != 0) {
nd6log((LOG_NOTICE, "prelist_update: "
"failed to create a temporary "
"address, errno=%d\n",
e));
}
}
+ ifafree(&ia6->ia_ifa);
+ ia6 = NULL;
/*
* A newly added address might affect the status
for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr;
pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) {
+ /* Callee returns a locked route upon success */
if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0,
- pfxrtr->router->ifp, 0)) &&
- (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
- ND6_IS_LLINFO_PROBREACH(ln))
- break; /* found */
+ pfxrtr->router->ifp, 0)) != NULL) {
+ RT_LOCK_ASSERT_HELD(rt);
+ if ((ln = rt->rt_llinfo) != NULL &&
+ ND6_IS_LLINFO_PROBREACH(ln)) {
+ RT_REMREF_LOCKED(rt);
+ RT_UNLOCK(rt);
+ break; /* found */
+ }
+ RT_REMREF_LOCKED(rt);
+ RT_UNLOCK(rt);
+ }
}
return(pfxrtr);
struct ifnet *ifp = pr->ndpr_ifp;
struct sockaddr_in6 mask6;
struct nd_prefix *opr;
- u_long rtflags;
+ u_int32_t rtflags;
int error = 0;
struct rtentry *rt = NULL;
if (ifa->ifa_addr->sa_family == AF_INET6)
break;
}
+ if (ifa != NULL)
+ ifaref(ifa);
ifnet_lock_done(ifp);
/* should we care about ia6_flags? */
}
mask6.sin6_addr = pr->ndpr_mask;
if (rtlocked == 0)
- lck_mtx_lock(rt_mtx);
+ lck_mtx_lock(rnh_lock);
rtflags = ifa->ifa_flags | RTF_CLONING | RTF_UP;
if (nd6_need_cache(ifp)) {
ifa->ifa_addr, (struct sockaddr *)&mask6,
rtflags, &rt);
if (error == 0) {
- if (rt != NULL) /* this should be non NULL, though */
+ if (rt != NULL) { /* this should be non NULL, though */
+ RT_LOCK(rt);
nd6_rtmsg(RTM_ADD, rt);
+ RT_UNLOCK(rt);
+ }
pr->ndpr_stateflags |= NDPRF_ONLINK;
}
else {
}
if (rt != NULL)
- rtunref(rt);
+ RT_REMREF(rt);
if (rtlocked == 0)
- lck_mtx_unlock(rt_mtx);
+ lck_mtx_unlock(rnh_lock);
+
+ ifafree(ifa);
+
return(error);
}
mask6.sin6_family = AF_INET6;
mask6.sin6_len = sizeof(sa6);
bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr));
- lck_mtx_lock(rt_mtx);
+ lck_mtx_lock(rnh_lock);
error = rtrequest_locked(RTM_DELETE, (struct sockaddr *)&sa6, NULL,
(struct sockaddr *)&mask6, 0, &rt);
if (error == 0) {
pr->ndpr_stateflags &= ~NDPRF_ONLINK;
/* report the route deletion to the routing socket. */
- if (rt != NULL)
+ if (rt != NULL) {
+ RT_LOCK(rt);
nd6_rtmsg(RTM_DELETE, rt);
+ RT_UNLOCK(rt);
+ }
/*
* There might be the same prefix on another interface,
if (rt != NULL)
rtfree_locked(rt);
- lck_mtx_unlock(rt_mtx);
+ lck_mtx_unlock(rnh_lock);
return(error);
}
/* if link-local address is not eligible, do not autoconfigure. */
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) {
printf("in6_ifadd: link-local address not ready\n");
+ ifafree(ifa);
return NULL;
}
#endif
nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s "
"(prefix=%d ifid=%d)\n",
if_name(ifp), prefixlen, 128 - plen0));
+ ifafree(ifa);
return NULL;
}
*/
pr->ndpr_addr = ifra.ifra_addr.sin6_addr;
+ ifafree(ifa);
+ ifa = NULL;
+
/* allocate ifaddr structure, link into chain, etc. */
- if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) {
+ if ((error = in6_update_ifa(ifp, &ifra, NULL, M_NOWAIT)) != 0) {
nd6log((LOG_ERR,
"in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n",
ip6_sprintf(&ifra.ifra_addr.sin6_addr), if_name(ifp),
int
in6_tmpifadd(
const struct in6_ifaddr *ia0, /* corresponding public address */
- int forcegen)
+ int forcegen,
+ int how)
{
struct ifnet *ifp = ia0->ia_ifa.ifa_ifp;
- struct in6_ifaddr *newia;
+ struct in6_ifaddr *ia, *newia;
struct in6_aliasreq ifra;
int i, error;
int trylimit = 3; /* XXX: adhoc value */
* interface identifier and repeat this step.
* RFC 3041 3.3 (4).
*/
- if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) {
+ if ((ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr)) != NULL) {
+ ifafree(&ia->ia_ifa);
if (trylimit-- == 0) {
nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find "
"a unique random IFID\n"));
ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY);
/* allocate ifaddr structure, link into chain, etc. */
- if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0)
+ if ((error = in6_update_ifa(ifp, &ifra, NULL, how)) != 0)
return(error);
newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
lck_mtx_lock(nd6_mutex);
newia->ia6_ndpr = ia0->ia6_ndpr;
newia->ia6_ndpr->ndpr_refcnt++;
-
/*
* A newly added address might affect the status of other addresses.
* XXX: when the temporary address is generated with a new public
*/
pfxlist_onlink_check(1);
lck_mtx_unlock(nd6_mutex);
+ ifafree(&newia->ia_ifa);
return(0);
}
if (!IN6_IS_ADDR_LINKLOCAL(gateway)) {
return;
}
- lck_mtx_lock(rt_mtx);
+ lck_mtx_lock(rnh_lock);
/* XXX: hack for KAME's link-local address kludge */
gateway->s6_addr16[1] = htons(ifp->if_index);
rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway);
- lck_mtx_unlock(rt_mtx);
+ lck_mtx_unlock(rnh_lock);
}
static int
struct rtentry *rt = (struct rtentry *)rn;
struct in6_addr *gate = (struct in6_addr *)arg;
- lck_mtx_assert(rt_mtx, LCK_MTX_ASSERT_OWNED);
+ lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED);
- if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6)
+ RT_LOCK(rt);
+ if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6) {
+ RT_UNLOCK(rt);
return(0);
+ }
- if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr))
+ if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr)) {
+ RT_UNLOCK(rt);
return(0);
-
+ }
/*
* Do not delete a static route.
* XXX: this seems to be a bit ad-hoc. Should we consider the
* 'cloned' bit instead?
*/
- if ((rt->rt_flags & RTF_STATIC) != 0)
+ if ((rt->rt_flags & RTF_STATIC) != 0) {
+ RT_UNLOCK(rt);
return(0);
-
+ }
/*
* We delete only host route. This means, in particular, we don't
* delete default route.
*/
- if ((rt->rt_flags & RTF_HOST) == 0)
+ if ((rt->rt_flags & RTF_HOST) == 0) {
+ RT_UNLOCK(rt);
return(0);
+ }
- return(rtrequest_locked(RTM_DELETE, rt_key(rt),
- rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0));
+ /*
+ * Safe to drop rt_lock and use rt_key, rt_gateway, since holding
+ * rnh_lock here prevents another thread from calling rt_setgate()
+ * on this route.
+ */
+ RT_UNLOCK(rt);
+ return (rtrequest_locked(RTM_DELETE, rt_key(rt), rt->rt_gateway,
+ rt_mask(rt), rt->rt_flags, 0));
#undef SIN6
}
int ifindex)
{
int error = 0;
+ ifnet_t def_ifp = NULL;
- if (ifindex < 0 || if_index < ifindex)
+ ifnet_head_lock_shared();
+ if (ifindex < 0 || if_index < ifindex) {
+ ifnet_head_done();
return(EINVAL);
+ }
+ def_ifp = ifindex2ifnet[ifindex];
+ ifnet_head_done();
lck_mtx_lock(nd6_mutex);
if (nd6_defifindex != ifindex) {
nd6_defifindex = ifindex;
if (nd6_defifindex > 0)
- nd6_defifp = ifindex2ifnet[nd6_defifindex];
+ nd6_defifp = def_ifp;
else
nd6_defifp = NULL;