commit 2120b82f48585d4c65f185cbf50194f81364a4f1
Author: Ryota Ozaki <ozaki-r@iij.ad.jp>
Date:   Tue Jul 26 16:35:37 2016 +0900

    Apply psz/psref to ia6

diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
index 9beb3b9..5442d36 100644
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -160,7 +160,7 @@ static struct mbuf *ni6_input(struct mbuf *, int);
 static struct mbuf *ni6_nametodns(const char *, int, int);
 static int ni6_dnsmatch(const char *, int, const char *, int);
 static int ni6_addrs(struct icmp6_nodeinfo *, struct mbuf *,
-			  struct ifnet **, char *);
+			  struct ifnet **, char *, struct psref *);
 static int ni6_store_addrs(struct icmp6_nodeinfo *, struct icmp6_nodeinfo *,
 				struct ifnet *, int);
 static int icmp6_notify_error(struct mbuf *, int, int, int);
@@ -1200,8 +1200,10 @@ ni6_input(struct mbuf *m, int off)
 	struct ip6_hdr *ip6;
 	int oldfqdn = 0;	/* if 1, return pascal string (03 draft) */
 	char *subj = NULL;
-	int s;
 	struct ifnet *rcvif;
+	int s, ss;
+	struct ifaddr *ifa;
+	struct psref psref;
 
 	ip6 = mtod(m, struct ip6_hdr *);
 	IP6_EXTHDR_GET(ni6, struct icmp6_nodeinfo *, m, off, sizeof(*ni6));
@@ -1220,12 +1222,17 @@ ni6_input(struct mbuf *m, int off)
 	 */
 	sockaddr_in6_init(&sin6, &ip6->ip6_dst, 0, 0, 0);
 	/* XXX scopeid */
-	if (ifa_ifwithaddr(sin6tosa(&sin6)))
+	ss = pserialize_read_enter();
+	ifa = ifa_ifwithaddr(sin6tosa(&sin6));
+	if (ifa != NULL)
 		; /* unicast/anycast, fine */
 	else if (IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr))
 		; /* link-local multicast, fine */
-	else
+	else {
+		pserialize_read_exit(ss);
 		goto bad;
+	}
+	pserialize_read_exit(ss);
 
 	/* validate query Subject field. */
 	qtype = ntohs(ni6->ni_qtype);
@@ -1359,7 +1366,7 @@ ni6_input(struct mbuf *m, int off)
 		replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen);
 		break;
 	case NI_QTYPE_NODEADDR:
-		addrs = ni6_addrs(ni6, m, &ifp, subj);
+		addrs = ni6_addrs(ni6, m, &ifp, subj, &psref);
 		if ((replylen += addrs * (sizeof(struct in6_addr) +
 					  sizeof(u_int32_t))) > MCLBYTES)
 			replylen = MCLBYTES; /* XXX: will truncate pkt later */
@@ -1387,6 +1394,7 @@ ni6_input(struct mbuf *m, int off)
 	/* allocate an mbuf to reply. */
 	MGETHDR(n, M_DONTWAIT, m->m_type);
 	if (n == NULL) {
+		if_put(ifp, &psref);
 		m_freem(m);
 		return (NULL);
 	}
@@ -1454,6 +1462,8 @@ ni6_input(struct mbuf *m, int off)
 		    sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo);
 		lenlim = M_TRAILINGSPACE(n);
 		copied = ni6_store_addrs(ni6, nni6, ifp, lenlim);
+		if_put(ifp, &psref);
+		ifp = NULL;
 		/* XXX: reset mbuf length */
 		n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
 			sizeof(struct icmp6_nodeinfo) + copied;
@@ -1468,6 +1478,7 @@ ni6_input(struct mbuf *m, int off)
 	return (n);
 
   bad:
+	if_put(ifp, &psref);
 	m_freem(m);
 	if (n)
 		m_freem(n);
@@ -1657,7 +1668,7 @@ ni6_dnsmatch(const char *a, int alen, const char *b, int blen)
  */
 static int
 ni6_addrs(struct icmp6_nodeinfo *ni6, struct mbuf *m,
-    struct ifnet **ifpp, char *subj)
+    struct ifnet **ifpp, char *subj, struct psref *psref)
 {
 	struct ifnet *ifp;
 	struct in6_ifaddr *ia6;
@@ -1665,6 +1676,7 @@ ni6_addrs(struct icmp6_nodeinfo *ni6, struct mbuf *m,
 	struct sockaddr_in6 *subj_ip6 = NULL; /* XXX pedant */
 	int addrs = 0, addrsofif, iffound = 0;
 	int niflags = ni6->ni_flags;
+	int s;
 
 	if ((niflags & NI_NODEADDR_FLAG_ALL) == 0) {
 		switch (ni6->ni_code) {
@@ -1682,6 +1694,7 @@ ni6_addrs(struct icmp6_nodeinfo *ni6, struct mbuf *m,
 		}
 	}
 
+	s = pserialize_read_enter();
 	IFNET_READER_FOREACH(ifp) {
 		addrsofif = 0;
 		IFADDR_READER_FOREACH(ifa, ifp) {
@@ -1733,12 +1746,15 @@ ni6_addrs(struct icmp6_nodeinfo *ni6, struct mbuf *m,
 			addrsofif++; /* count the address */
 		}
 		if (iffound) {
+			if_acquire_NOMPSAFE(ifp, psref);
+			pserialize_read_exit(s);
 			*ifpp = ifp;
 			return (addrsofif);
 		}
 
 		addrs += addrsofif;
 	}
+	pserialize_read_exit(s);
 
 	return (addrs);
 }
@@ -1748,7 +1764,7 @@ ni6_store_addrs(struct icmp6_nodeinfo *ni6,
 	struct icmp6_nodeinfo *nni6, struct ifnet *ifp0,
 	int resid)
 {
-	struct ifnet *ifp = ifp0 ? ifp0 : IFNET_READER_FIRST();
+	struct ifnet *ifp;
 	struct in6_ifaddr *ia6;
 	struct ifaddr *ifa;
 	struct ifnet *ifp_dep = NULL;
@@ -1756,10 +1772,13 @@ ni6_store_addrs(struct icmp6_nodeinfo *ni6,
 	u_char *cp = (u_char *)(nni6 + 1);
 	int niflags = ni6->ni_flags;
 	u_int32_t ltime;
+	int s;
 
 	if (ifp0 == NULL && !(niflags & NI_NODEADDR_FLAG_ALL))
 		return (0);	/* needless to copy */
 
+	s = pserialize_read_enter();
+	ifp = ifp0 ? ifp0 : IFNET_READER_FIRST();
   again:
 
 	for (; ifp; ifp = IFNET_READER_NEXT(ifp))
@@ -1820,7 +1839,7 @@ ni6_store_addrs(struct icmp6_nodeinfo *ni6,
 				 * Set the truncate flag and return.
 				 */
 				nni6->ni_flags |= NI_NODEADDR_FLAG_TRUNCATE;
-				return (copied);
+				goto out;
 			}
 
 			/*
@@ -1876,7 +1895,8 @@ ni6_store_addrs(struct icmp6_nodeinfo *ni6,
 
 		goto again;
 	}
-
+out:
+	pserialize_read_exit(s);
 	return (copied);
 }
 
@@ -2067,16 +2087,21 @@ icmp6_reflect(struct mbuf *m, size_t off)
 			struct sockaddr_in6 sin6;
 			struct sockaddr sa;
 		} u;
+		int _s;
+		struct ifaddr *ifa;
 
 		sockaddr_in6_init(&u.sin6, &origdst, 0, 0, 0);
 
-		ia = ifatoia6(ifa_ifwithaddr(&u.sa));
+		_s = pserialize_read_enter();
+		ifa = ifa_ifwithaddr(&u.sa);
 
-		if (ia == NULL)
-			;
-		else if ((ia->ia6_flags &
-			 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)) == 0)
-			src = &ia->ia_addr.sin6_addr;
+		if (ifa != NULL) {
+			ia = ifatoia6(ifa);
+			if ((ia->ia6_flags &
+				 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)) == 0)
+				src = &ia->ia_addr.sin6_addr;
+		}
+		pserialize_read_exit(_s);
 	}
 
 	if (src == NULL) {
@@ -2438,11 +2463,15 @@ icmp6_redirect_output(struct mbuf *m0, struct rtentry *rt)
 	{
 		/* get ip6 linklocal address for ifp(my outgoing interface). */
 		struct in6_ifaddr *ia;
+		int s = pserialize_read_enter();
 		if ((ia = in6ifa_ifpforlinklocal(ifp,
 						 IN6_IFF_NOTREADY|
-						 IN6_IFF_ANYCAST)) == NULL)
+						 IN6_IFF_ANYCAST)) == NULL) {
+			pserialize_read_exit(s);
 			goto fail;
+		}
 		ifp_ll6 = &ia->ia_addr.sin6_addr;
+		pserialize_read_exit(s);
 	}
 
 	/* get ip6 linklocal address for the router. */
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index eaaad1b..f61235a 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -143,6 +143,7 @@ const struct sockaddr_in6 sa6_any = {sizeof(sa6_any), AF_INET6,
 				     0, 0, IN6ADDR_ANY_INIT, 0};
 
 struct pslist_head	in6_ifaddr_list;
+kmutex_t		in6_ifaddr_lock;
 
 static int in6_lifaddr_ioctl(struct socket *, u_long, void *,
 	struct ifnet *);
@@ -155,6 +156,7 @@ in6_init(void)
 {
 
 	PSLIST_INIT(&in6_ifaddr_list);
+	mutex_init(&in6_ifaddr_lock, MUTEX_DEFAULT, IPL_NONE);
 }
 
 /*
@@ -189,6 +191,8 @@ in6_ifremlocal(struct ifaddr *ifa)
 	struct in6_ifaddr *ia;
 	struct ifaddr *alt_ifa = NULL;
 	int ia_count = 0;
+	struct psref psref;
+	int s;
 
 	/*
 	 * Some of BSD variants do not remove cloned routes
@@ -218,6 +222,7 @@ in6_ifremlocal(struct ifaddr *ifa)
 	 * XXX agree, especially now that I have fixed the dangling
 	 * XXX ifp-pointers bug.
 	 */
+	s = pserialize_read_enter();
 	IN6_ADDRLIST_READER_FOREACH(ia) {
 		if (!IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ia->ia_addr.sin6_addr))
 			continue;
@@ -226,11 +231,17 @@ in6_ifremlocal(struct ifaddr *ifa)
 		if (++ia_count > 1 && alt_ifa != NULL)
 			break;
 	}
+	if (ia_count > 1 && alt_ifa != NULL)
+		ifa_acquire(alt_ifa, &psref);
+	pserialize_read_exit(s);
 
 	if (ia_count == 0)
 		return;
 
 	rt_ifa_remlocal(ifa, ia_count == 1 ? NULL : alt_ifa);
+
+	if (ia_count > 1 && alt_ifa != NULL)
+		ifa_release(alt_ifa, &psref);
 }
 
 int
@@ -279,7 +290,9 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
 	struct	in6_ifaddr *ia = NULL;
 	struct	in6_aliasreq *ifra = (struct in6_aliasreq *)data;
 	struct sockaddr_in6 *sa6;
-	int error;
+	int error, bound;
+	struct psref psref;
+	bool run_hooks = false;
 
 	switch (cmd) {
 	case SIOCAADDRCTL_POLICY:
@@ -395,14 +408,17 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
 		sa6 = NULL;
 		break;
 	}
+
+	error = 0;
+	bound = curlwp_bind();
 	if (sa6 && sa6->sin6_family == AF_INET6) {
 		if (sa6->sin6_scope_id != 0)
 			error = sa6_embedscope(sa6, 0);
 		else
 			error = in6_setscope(&sa6->sin6_addr, ifp, NULL);
 		if (error != 0)
-			return error;
-		ia = in6ifa_ifpwithaddr(ifp, &sa6->sin6_addr);
+			goto out;
+		ia = in6ifa_ifpwithaddr_psref(ifp, &sa6->sin6_addr, &psref);
 	} else
 		ia = NULL;
 
@@ -414,7 +430,8 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
 		 * Since IPv6 allows a node to assign multiple addresses
 		 * on a single interface, SIOCSIFxxx ioctls are deprecated.
 		 */
-		return EINVAL;
+		error = EINVAL;
+		goto release;
 
 	case SIOCDIFADDR_IN6:
 		/*
@@ -424,8 +441,10 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
 		 * interface address from the day one, we consider "remove the
 		 * first one" semantics to be not preferable.
 		 */
-		if (ia == NULL)
-			return EADDRNOTAVAIL;
+		if (ia == NULL) {
+			error = EADDRNOTAVAIL;
+			goto out;
+		}
 		/* FALLTHROUGH */
 #ifdef OSIOCAIFADDR_IN6
 	case OSIOCAIFADDR_IN6:
@@ -436,8 +455,10 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
 		 * the corresponding operation.
 		 */
 		if (ifra->ifra_addr.sin6_family != AF_INET6 ||
-		    ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6))
-			return EAFNOSUPPORT;
+		    ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6)) {
+			error = EAFNOSUPPORT;
+			goto release;
+		}
 		/* Privileged. */
 
 		break;
@@ -453,8 +474,10 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
 	case OSIOCGIFALIFETIME_IN6:
 #endif
 		/* must think again about its semantics */
-		if (ia == NULL)
-			return EADDRNOTAVAIL;
+		if (ia == NULL) {
+			error = EADDRNOTAVAIL;
+			goto out;
+		}
 		break;
 	}
 
@@ -463,19 +486,21 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
 	case SIOCGIFADDR_IN6:
 		ifr->ifr_addr = ia->ia_addr;
 		if ((error = sa6_recoverscope(&ifr->ifr_addr)) != 0)
-			return error;
+			break;
 		break;
 
 	case SIOCGIFDSTADDR_IN6:
-		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
-			return EINVAL;
+		if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
+			error = EINVAL;
+			break;
+		}
 		/*
 		 * XXX: should we check if ifa_dstaddr is NULL and return
 		 * an error?
 		 */
 		ifr->ifr_dstaddr = ia->ia_dstaddr;
 		if ((error = sa6_recoverscope(&ifr->ifr_dstaddr)) != 0)
-			return error;
+			break;
 		break;
 
 	case SIOCGIFNETMASK_IN6:
@@ -487,8 +512,10 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
 		break;
 
 	case SIOCGIFSTAT_IN6:
-		if (ifp == NULL)
-			return EINVAL;
+		if (ifp == NULL) {
+			error = EINVAL;
+			break;
+		}
 		memset(&ifr->ifr_ifru.ifru_stat, 0,
 		    sizeof(ifr->ifr_ifru.ifru_stat));
 		ifr->ifr_ifru.ifru_stat =
@@ -496,8 +523,10 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
 		break;
 
 	case SIOCGIFSTAT_ICMP6:
-		if (ifp == NULL)
-			return EINVAL;
+		if (ifp == NULL) {
+			error = EINVAL;
+			break;
+		}
 		memset(&ifr->ifr_ifru.ifru_icmp6stat, 0,
 		    sizeof(ifr->ifr_ifru.ifru_icmp6stat));
 		ifr->ifr_ifru.ifru_icmp6stat =
@@ -569,6 +598,8 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
 		struct nd_prefixctl prc0;
 		struct nd_prefix *pr;
 		struct in6_addrlifetime *lt;
+		struct in6_ifaddr *_ia;
+		int s;
 
 		/* reject read-only flags */
 		if ((ifra->ifra_flags & IN6_IFF_DUPLICATED) != 0 ||
@@ -576,7 +607,8 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
 		    (ifra->ifra_flags & IN6_IFF_TENTATIVE) != 0 ||
 		    (ifra->ifra_flags & IN6_IFF_NODAD) != 0 ||
 		    (ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0) {
-			return EINVAL;
+			error = EINVAL;
+			break;
 		}
 		/*
 		 * ia6t_expire and ia6t_preferred won't be used for now,
@@ -589,19 +621,31 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
 			lt->ia6t_preferred =
 			    time_wall_to_mono(lt->ia6t_preferred);
 		/*
-		 * first, make or update the interface address structure,
-		 * and link it to the list.
+		 * first, make (ia == NULL) or update (ia != NULL) the interface
+		 * address structure, and link it to the list.
 		 */
 		if ((error = in6_update_ifa(ifp, ifra, ia, 0)) != 0)
-			return error;
-		if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr))
-		    == NULL) {
+			break;
+		s = pserialize_read_enter();
+		_ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr);
+		if (_ia == NULL) {
+			pserialize_read_exit(s);
 		    	/*
 			 * this can happen when the user specify the 0 valid
 			 * lifetime.
 			 */
 			break;
 		}
+		/*
+		 * If ia == NULL, _ia has been created and we need to acquire
+		 * a reference. Otherwise, a reference is already taken.
+		 */
+		if (ia == NULL) {
+			ia6_acquire(_ia, &psref);
+			ia = _ia;
+		} else
+			KASSERT(_ia == ia);
+		pserialize_read_exit(s);
 
 		/*
 		 * then, make the prefix on-link on the interface.
@@ -647,11 +691,12 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
 			 * interface route.
 			 */
 			if ((error = nd6_prelist_add(&prc0, NULL, &pr)) != 0)
-				return error;
+				break;
 			if (pr == NULL) {
 				log(LOG_ERR, "nd6_prelist_add succeeded but "
 				    "no prefix\n");
-				return EINVAL; /* XXX panic here? */
+				error = EINVAL; /* XXX panic here? */
+				break;
 			}
 		}
 
@@ -682,8 +727,7 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
 		 */
 		pfxlist_onlink_check();
 
-		(void)pfil_run_hooks(if_pfil, (struct mbuf **)SIOCAIFADDR_IN6,
-		    ifp, PFIL_IFADDR);
+		run_hooks = true;
 		break;
 	}
 
@@ -702,19 +746,26 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
 		 * Note that in6_purgeaddr() will decrement ndpr_refcnt.
 		 */
 		pr = ia->ia6_ndpr;
+		ia6_release(ia, &psref);
 		in6_purgeaddr(&ia->ia_ifa);
+		ia = NULL;
 		if (pr && pr->ndpr_refcnt == 0)
 			prelist_remove(pr);
-		(void)pfil_run_hooks(if_pfil, (struct mbuf **)SIOCDIFADDR_IN6,
-		    ifp, PFIL_IFADDR);
+		run_hooks = true;
 		break;
 	}
 
 	default:
-		return ENOTTY;
+		error = ENOTTY;
 	}
+release:
+	ia6_release(ia, &psref);
 
-	return 0;
+	if (run_hooks)
+		pfil_run_hooks(if_pfil, (struct mbuf **)cmd, ifp, PFIL_IFADDR);
+out:
+	curlwp_bindx(bound);
+	return error;
 }
 
 int
@@ -1037,7 +1088,9 @@ in6_update_ifa1(struct ifnet *ifp, struct in6_aliasreq *ifra,
 	/*
 	 * Insert ia to the global list and ifa to the interface's list.
 	 */
+	mutex_enter(&in6_ifaddr_lock);
 	IN6_ADDRLIST_WRITER_INSERT_TAIL(ia);
+	mutex_exit(&in6_ifaddr_lock);
 
 	/* gain a refcnt for the link from in6_ifaddr */
 	ifaref(&ia->ia_ifa);
@@ -1346,11 +1399,10 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
 {
 	int	s = splnet();
 
-	ifa_remove(ifp, &ia->ia_ifa);
-
+	mutex_enter(&in6_ifaddr_lock);
 	IN6_ADDRLIST_WRITER_REMOVE(ia);
-	/* TODO psref_target_destroy */
-	IN6_ADDRLIST_ENTRY_DESTROY(ia);
+	ifa_remove(ifp, &ia->ia_ifa);
+	mutex_exit(&in6_ifaddr_lock);
 
 	/*
 	 * XXX thorpej@NetBSD.org -- if the interface is going
@@ -1389,6 +1441,8 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
 	if ((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0)
 		pfxlist_onlink_check();
 
+	IN6_ADDRLIST_ENTRY_DESTROY(ia);
+
 	/*
 	 * release another refcnt for the link from in6_ifaddr.
 	 * Note that we should decrement the refcnt at least once for all *BSD.
@@ -1481,6 +1535,8 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, void *data,
 		struct in6_aliasreq ifra;
 		struct in6_addr *xhostid = NULL;
 		int prefixlen;
+		int bound = curlwp_bind();
+		struct psref psref;
 
 		if ((iflr->flags & IFLR_PREFIX) != 0) {
 			struct sockaddr_in6 *sin6;
@@ -1490,20 +1546,27 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, void *data,
 			 * address.  xhostid points to the first link-local
 			 * address attached to the interface.
 			 */
-			ia = in6ifa_ifpforlinklocal(ifp, 0);
-			if (ia == NULL)
+			ia = in6ifa_ifpforlinklocal_psref(ifp, 0, &psref);
+			if (ia == NULL) {
+				curlwp_bindx(bound);
 				return EADDRNOTAVAIL;
+			}
 			xhostid = IFA_IN6(&ia->ia_ifa);
 
 		 	/* prefixlen must be <= 64. */
-			if (64 < iflr->prefixlen)
+			if (64 < iflr->prefixlen) {
+				ia6_release(ia, &psref);
+				curlwp_bindx(bound);
 				return EINVAL;
+			}
 			prefixlen = iflr->prefixlen;
 
 			/* hostid part must be zero. */
 			sin6 = (struct sockaddr_in6 *)&iflr->addr;
 			if (sin6->sin6_addr.s6_addr32[2] != 0
 			 || sin6->sin6_addr.s6_addr32[3] != 0) {
+				ia6_release(ia, &psref);
+				curlwp_bindx(bound);
 				return EINVAL;
 			}
 		} else
@@ -1533,6 +1596,11 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, void *data,
 				    xhostid->s6_addr32[3];
 			}
 		}
+		if (xhostid) {
+			ia6_release(ia, &psref);
+			ia = NULL;
+		}
+		curlwp_bindx(bound);
 
 		ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
 		in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen);
@@ -1548,6 +1616,7 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, void *data,
 		struct in6_addr mask, candidate, match;
 		struct sockaddr_in6 *sin6;
 		int cmp;
+		int error, s;
 
 		memset(&mask, 0, sizeof(mask));
 		if (iflr->flags & IFLR_PREFIX) {
@@ -1580,6 +1649,7 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, void *data,
 			}
 		}
 
+		s = pserialize_read_enter();
 		IFADDR_READER_FOREACH(ifa, ifp) {
 			if (ifa->ifa_addr->sa_family != AF_INET6)
 				continue;
@@ -1600,19 +1670,19 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, void *data,
 			if (IN6_ARE_ADDR_EQUAL(&candidate, &match))
 				break;
 		}
-		if (!ifa)
-			return EADDRNOTAVAIL;
+		if (!ifa) {
+			error = EADDRNOTAVAIL;
+			goto error;
+		}
 		ia = ifa2ia6(ifa);
 
 		if (cmd == SIOCGLIFADDR) {
-			int error;
-
 			/* fill in the if_laddrreq structure */
 			memcpy(&iflr->addr, &ia->ia_addr, ia->ia_addr.sin6_len);
 			error = sa6_recoverscope(
 			    (struct sockaddr_in6 *)&iflr->addr);
 			if (error != 0)
-				return error;
+				goto error;
 
 			if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
 				memcpy(&iflr->dstaddr, &ia->ia_dstaddr,
@@ -1620,7 +1690,7 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, void *data,
 				error = sa6_recoverscope(
 				    (struct sockaddr_in6 *)&iflr->dstaddr);
 				if (error != 0)
-					return error;
+					goto error;
 			} else
 				memset(&iflr->dstaddr, 0, sizeof(iflr->dstaddr));
 
@@ -1629,7 +1699,7 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, void *data,
 
 			iflr->flags = ia->ia6_flags;	/* XXX */
 
-			return 0;
+			error = 0;
 		} else {
 			struct in6_aliasreq ifra;
 
@@ -1651,8 +1721,13 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, void *data,
 			    ia->ia_prefixmask.sin6_len);
 
 			ifra.ifra_flags = ia->ia6_flags;
+			pserialize_read_exit(s);
+
 			return in6_control(so, SIOCDIFADDR_IN6, &ifra, ifp);
 		}
+	error:
+		pserialize_read_exit(s);
+		return error;
 	    }
 	}
 
@@ -1757,6 +1832,21 @@ in6ifa_ifpforlinklocal(const struct ifnet *ifp, const int ignoreflags)
 	return (struct in6_ifaddr *)best_ifa;
 }
 
+struct in6_ifaddr *
+in6ifa_ifpforlinklocal_psref(const struct ifnet *ifp, const int ignoreflags,
+    struct psref *psref)
+{
+	struct in6_ifaddr *ia;
+	int s = pserialize_read_enter();
+
+	ia = in6ifa_ifpforlinklocal(ifp, ignoreflags);
+	if (ia != NULL)
+		ia6_acquire(ia, psref);
+	pserialize_read_exit(s);
+
+	return ia;
+}
+
 /*
  * find the internet address corresponding to a given address.
  * ifaddr is returned referenced.
@@ -1765,13 +1855,10 @@ struct in6_ifaddr *
 in6ifa_ifwithaddr(const struct in6_addr *addr, uint32_t zoneid)
 {
 	struct in6_ifaddr *ia;
+	int s;
 
-#ifdef __FreeBSD__
-	IN6_IFADDR_RLOCK();
-	LIST_FOREACH(ia, IN6ADDR_HASH(addr), ia6_hash) {
-#else
+	s = pserialize_read_enter();
 	IN6_ADDRLIST_READER_FOREACH(ia) {
-#endif
 		if (IN6_ARE_ADDR_EQUAL(IA6_IN6(ia), addr)) {
 			if (zoneid != 0 &&
 			    zoneid != ia->ia_addr.sin6_scope_id)
@@ -1780,9 +1867,8 @@ in6ifa_ifwithaddr(const struct in6_addr *addr, uint32_t zoneid)
 			break;
 		}
 	}
-#ifdef __FreeBSD__
-	IN6_IFADDR_RUNLOCK();
-#endif
+	pserialize_read_exit(s);
+
 	return ia;
 }
 
@@ -1805,6 +1891,21 @@ in6ifa_ifpwithaddr(const struct ifnet *ifp, const struct in6_addr *addr)
 	return (struct in6_ifaddr *)best_ifa;
 }
 
+struct in6_ifaddr *
+in6ifa_ifpwithaddr_psref(const struct ifnet *ifp, const struct in6_addr *addr,
+    struct psref *psref)
+{
+	struct in6_ifaddr *ia;
+	int s = pserialize_read_enter();
+
+	ia = in6ifa_ifpwithaddr(ifp, addr);
+	if (ia != NULL)
+		ia6_acquire(ia, psref);
+	pserialize_read_exit(s);
+
+	return ia;
+}
+
 static struct in6_ifaddr *
 bestia(struct in6_ifaddr *best_ia, struct in6_ifaddr *ia)
 {
@@ -2044,6 +2145,7 @@ in6_if_link_up(struct ifnet *ifp)
 {
 	struct ifaddr *ifa;
 	struct in6_ifaddr *ia;
+	int s, bound;
 
 	/* Ensure it's sane to run DAD */
 	if (ifp->if_link_state == LINK_STATE_DOWN)
@@ -2051,9 +2153,16 @@ in6_if_link_up(struct ifnet *ifp)
 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
 		return;
 
+	bound = curlwp_bind();
+	s = pserialize_read_enter();
 	IFADDR_READER_FOREACH(ifa, ifp) {
+		struct psref psref;
+
 		if (ifa->ifa_addr->sa_family != AF_INET6)
 			continue;
+
+		ifa_acquire(ifa, &psref);
+		pserialize_read_exit(s);
 		ia = (struct in6_ifaddr *)ifa;
 
 		/* If detached then mark as tentative */
@@ -2084,7 +2193,12 @@ in6_if_link_up(struct ifnet *ifp)
 			/* +1 ensures callout is always used */
 			nd6_dad_start(ifa, rand_delay + 1);
 		}
+
+		s = pserialize_read_enter();
+		ifa_release(ifa, &psref);
 	}
+	pserialize_read_exit(s);
+	curlwp_bindx(bound);
 
 	/* Restore any detached prefixes */
 	pfxlist_onlink_check();
@@ -2111,13 +2225,21 @@ in6_if_link_down(struct ifnet *ifp)
 {
 	struct ifaddr *ifa;
 	struct in6_ifaddr *ia;
+	int s, bound;
 
 	/* Any prefixes on this interface should be detached as well */
 	pfxlist_onlink_check();
 
+	bound = curlwp_bind();
+	s = pserialize_read_enter();
 	IFADDR_READER_FOREACH(ifa, ifp) {
+		struct psref psref;
+
 		if (ifa->ifa_addr->sa_family != AF_INET6)
 			continue;
+
+		ifa_acquire(ifa, &psref);
+		pserialize_read_exit(s);
 		ia = (struct in6_ifaddr *)ifa;
 
 		/* Stop DAD processing */
@@ -2139,7 +2261,12 @@ in6_if_link_down(struct ifnet *ifp)
 			    ~(IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED);
 			rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL);
 		}
+
+		s = pserialize_read_enter();
+		ifa_release(ifa, &psref);
 	}
+	pserialize_read_exit(s);
+	curlwp_bindx(bound);
 }
 
 void
@@ -2320,18 +2447,22 @@ in6_lltable_rtcheck(struct ifnet *ifp,
 
 	rt = rtalloc1(l3addr, 0);
 	if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) || rt->rt_ifp != ifp) {
+		int s;
 		struct ifaddr *ifa;
 		/*
 		 * Create an ND6 cache for an IPv6 neighbor
 		 * that is not covered by our own prefix.
 		 */
 		/* XXX ifaof_ifpforaddr should take a const param */
+		s = pserialize_read_enter();
 		ifa = ifaof_ifpforaddr(l3addr, ifp);
 		if (ifa != NULL) {
+			pserialize_read_exit(s);
 			if (rt != NULL)
 				rtfree(rt);
 			return 0;
 		}
+		pserialize_read_exit(s);
 		log(LOG_INFO, "IPv6 address: \"%s\" is not on the network\n",
 		    ip6_sprintf(&((const struct sockaddr_in6 *)l3addr)->sin6_addr));
 		if (rt != NULL)
diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c
index 932dc64..206e312 100644
--- a/sys/netinet6/in6_ifattach.c
+++ b/sys/netinet6/in6_ifattach.c
@@ -320,31 +320,35 @@ int
 in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6)
 {
 	struct ifaddr *ifa;
-	const struct sockaddr_dl *sdl = NULL, *tsdl;
+	const struct sockaddr_dl *sdl = NULL;
 	const char *addr;
 	size_t addrlen;
 	static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 	static u_int8_t allone[8] =
 		{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+	int s;
 
+	s = pserialize_read_enter();
 	IFADDR_READER_FOREACH(ifa, ifp) {
+		const struct sockaddr_dl *tsdl;
 		if (ifa->ifa_addr->sa_family != AF_LINK)
 			continue;
 		tsdl = satocsdl(ifa->ifa_addr);
 		if (tsdl == NULL || tsdl->sdl_alen == 0)
 			continue;
-		if (sdl == NULL || ifa == ifp->if_dl || ifa == ifp->if_hwdl)
+		if (sdl == NULL || ifa == ifp->if_dl || ifa == ifp->if_hwdl) {
 			sdl = tsdl;
+			addr = CLLADDR(sdl);
+			addrlen = sdl->sdl_alen;
+		}
 		if (ifa == ifp->if_hwdl)
 			break;
 	}
+	pserialize_read_exit(s);
 
 	if (sdl == NULL)
 		return -1;
 
-	addr = CLLADDR(sdl);
-	addrlen = sdl->sdl_alen;
-
 	switch (ifp->if_type) {
 	case IFT_IEEE1394:
 	case IFT_IEEE80211:
@@ -532,7 +536,7 @@ in6_ifattach_linklocal(struct ifnet *ifp, struct ifnet *altifp)
 	struct in6_ifaddr *ia __diagused;
 	struct in6_aliasreq ifra;
 	struct nd_prefixctl prc0;
-	int i, error;
+	int i, error, s;
 
 	/*
 	 * configure link-local address.
@@ -589,8 +593,10 @@ in6_ifattach_linklocal(struct ifnet *ifp, struct ifnet *altifp)
 		return -1;
 	}
 
+	s = pserialize_read_enter();
 	ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */
 	KASSERTMSG(ia, "ia == NULL in in6_ifattach_linklocal");
+	pserialize_read_exit(s);
 
 	/*
 	 * Make the link-local prefix (fe80::/64%link) as on-link.
@@ -811,24 +817,29 @@ in6_ifattach(struct ifnet *ifp, struct ifnet *altifp)
 	 * XXX multiple loopback interface case.
 	 */
 	if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
+		int s = pserialize_read_enter();
 		in6 = in6addr_loopback;
 		if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
-			if (in6_ifattach_loopback(ifp) != 0)
+			if (in6_ifattach_loopback(ifp) != 0) {
+				pserialize_read_exit(s);
 				return;
+			}
 		}
+		pserialize_read_exit(s);
 	}
 
 	/*
 	 * assign a link-local address, if there's none.
 	 */
 	if (!(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
-	    ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL)
-	{
+	    ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL) {
+		int s = pserialize_read_enter();
 		ia = in6ifa_ifpforlinklocal(ifp, 0);
 		if (ia == NULL && in6_ifattach_linklocal(ifp, altifp) != 0) {
 			printf("%s: cannot assign link-local address\n",
 			    ifp->if_xname);
 		}
+		pserialize_read_exit(s);
 	}
 }
 
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c
index 0aa3d4d..8fc19a3 100644
--- a/sys/netinet6/in6_pcb.c
+++ b/sys/netinet6/in6_pcb.c
@@ -203,6 +203,7 @@ static int
 in6_pcbbind_addr(struct in6pcb *in6p, struct sockaddr_in6 *sin6, struct lwp *l)
 {
 	int error;
+	int s;
 
 	/*
 	 * We should check the family, but old programs
@@ -219,9 +220,12 @@ in6_pcbbind_addr(struct in6pcb *in6p, struct sockaddr_in6 *sin6, struct lwp *l)
 	if ((error = sa6_embedscope(sin6, ip6_use_defzone)) != 0)
 		return (error);
 
+	s = pserialize_read_enter();
 	if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
-		if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY) != 0)
-			return (EINVAL);
+		if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY) != 0) {
+			error = EINVAL;
+			goto out;
+		}
 		if (sin6->sin6_addr.s6_addr32[3]) {
 			struct sockaddr_in sin;
 
@@ -230,18 +234,27 @@ in6_pcbbind_addr(struct in6pcb *in6p, struct sockaddr_in6 *sin6, struct lwp *l)
 			sin.sin_family = AF_INET;
 			bcopy(&sin6->sin6_addr.s6_addr32[3],
 			    &sin.sin_addr, sizeof(sin.sin_addr));
-			if (!IN_MULTICAST(sin.sin_addr.s_addr) &&
-			    ifa_ifwithaddr((struct sockaddr *)&sin) == NULL)
-				return EADDRNOTAVAIL;
+			if (!IN_MULTICAST(sin.sin_addr.s_addr)) {
+				struct ifaddr *ifa;
+				ifa = ifa_ifwithaddr((struct sockaddr *)&sin);
+				if (ifa == NULL) {
+					error = EADDRNOTAVAIL;
+					goto out;
+				}
+			}
 		}
 	} else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
 		// succeed
 	} else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
-		struct ifaddr *ia = NULL;
+		struct ifaddr *ifa = NULL;
 
-		if ((in6p->in6p_flags & IN6P_FAITH) == 0 &&
-		    (ia = ifa_ifwithaddr(sin6tosa(sin6))) == NULL)
-			return (EADDRNOTAVAIL);
+		if ((in6p->in6p_flags & IN6P_FAITH) == 0) {
+			ifa = ifa_ifwithaddr(sin6tosa(sin6));
+			if (ifa == NULL) {
+				error = EADDRNOTAVAIL;
+				goto out;
+			}
+		}
 
 		/*
 		 * bind to an anycast address might accidentally
@@ -256,17 +269,18 @@ in6_pcbbind_addr(struct in6pcb *in6p, struct sockaddr_in6 *sin6, struct lwp *l)
 		 * flag to control the bind(2) behavior against
 		 * deprecated addresses (default: forbid bind(2)).
 		 */
-		if (ia &&
-		    ifatoia6(ia)->ia6_flags &
-		    (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED))
-			return (EADDRNOTAVAIL);
+		if (ifa &&
+		    ifatoia6(ifa)->ia6_flags &
+		    (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED)) {
+			error = EADDRNOTAVAIL;
+			goto out;
+		}
 	}
-
-
 	in6p->in6p_laddr = sin6->sin6_addr;
-
-
-	return (0);
+	error = 0;
+out:
+	pserialize_read_exit(s);
+	return error;
 }
 
 /*
diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c
index 8a7055f..71ed583 100644
--- a/sys/netinet6/in6_src.c
+++ b/sys/netinet6/in6_src.c
@@ -192,6 +192,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
 	struct in6_addr *ret_ia = NULL;
 	int bound = curlwp_bind();
 #define PSREF (psref == NULL) ? &local_psref : psref
+	int s;
 
 	KASSERT((ifpp != NULL && psref != NULL) ||
 	        (ifpp == NULL && psref == NULL));
@@ -222,6 +223,8 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
 	    !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) {
 		struct sockaddr_in6 srcsock;
 		struct in6_ifaddr *ia6;
+		int _s;
+		struct ifaddr *ifa;
 
 		/*
 		 * Determine the appropriate zone id of the source based on
@@ -240,9 +243,16 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
 				goto exit;
 		}
 
-		ia6 = ifatoia6(ifa_ifwithaddr(sin6tosa(&srcsock)));
-		if (ia6 == NULL ||
-		    (ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
+		_s = pserialize_read_enter();
+		ifa = ifa_ifwithaddr(sin6tosa(&srcsock));
+		if (ifa == NULL) {
+			pserialize_read_exit(_s);
+			*errorp = EADDRNOTAVAIL;
+			goto exit;
+		}
+		ia6 = ifatoia6(ifa);
+		if (ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY)) {
+			pserialize_read_exit(_s);
 			*errorp = EADDRNOTAVAIL;
 			goto exit;
 		}
@@ -250,6 +260,8 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
 		if (ifpp)
 			*ifpp = ifp;
 		ret_ia = &ia6->ia_addr.sin6_addr;
+		pserialize_read_exit(_s);
+		/* XXX don't return pointer */
 		goto exit;
 	}
 
@@ -293,6 +305,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
 	if (*errorp != 0)
 		goto exit;
 
+	s = pserialize_read_enter();
 	IN6_ADDRLIST_READER_FOREACH(ia) {
 		int new_scope = -1, new_matchlen = -1;
 		struct in6_addrpolicy *new_policy = NULL;
@@ -551,6 +564,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
 	  out:
 		break;
 	}
+	pserialize_read_exit(s);
 
 	if ((ia = ia_best) == NULL) {
 		*errorp = EADDRNOTAVAIL;
diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h
index 9aff491..100f178 100644
--- a/sys/netinet6/in6_var.h
+++ b/sys/netinet6/in6_var.h
@@ -134,6 +134,25 @@ struct	in6_ifaddr {
 #endif
 };
 
+#ifdef _KERNEL
+static inline void
+ia6_acquire(struct in6_ifaddr *ia, struct psref *psref)
+{
+
+	KASSERT(ia != NULL);
+	ifa_acquire(&ia->ia_ifa, psref);
+}
+
+static inline void
+ia6_release(struct in6_ifaddr *ia, struct psref *psref)
+{
+
+	if (ia == NULL)
+		return;
+	ifa_release(&ia->ia_ifa, psref);
+}
+#endif
+
 /* control structure to manage address selection policy */
 struct in6_addrpolicy {
 	struct sockaddr_in6 addr; /* prefix address */
@@ -489,13 +508,17 @@ struct	in6_rrenumreq {
 
 #ifdef _KERNEL
 
+#include <sys/mutex.h>
+#include <sys/pserialize.h>
+
 #include <net/pktqueue.h>
 
 extern pktqueue_t *ip6_pktq;
 
 MALLOC_DECLARE(M_IP6OPT);
 
-extern struct pslist_head in6_ifaddr_list;
+extern struct pslist_head	in6_ifaddr_list;
+extern kmutex_t			in6_ifaddr_lock;
 
 #define IN6_ADDRLIST_ENTRY_INIT(__ia) \
 	PSLIST_ENTRY_INIT((__ia), ia6_pslist_entry)
@@ -573,6 +596,20 @@ in6_get_ia_from_ifp(struct ifnet *ifp)
 	return (struct in6_ifaddr *)ifa;
 }
 
+static inline struct in6_ifaddr *
+in6_get_ia_from_ifp_psref(struct ifnet *ifp, struct psref *psref)
+{
+	struct in6_ifaddr *ia;
+	int s;
+
+	s = pserialize_read_enter();
+	ia = in6_get_ia_from_ifp(ifp);
+	if (ia != NULL)
+		ia6_acquire(ia, psref);
+	pserialize_read_exit(s);
+
+	return ia;
+}
 #endif /* _KERNEL */
 
 /*
@@ -623,13 +660,18 @@ in6_lookup_multi(struct in6_addr *addr, struct ifnet *ifp)
 {
 	struct in6_multi *in6m;
 	struct in6_ifaddr *ia;
+	int s;
 
-	if ((ia = in6_get_ia_from_ifp(ifp)) == NULL)
+	s = pserialize_read_enter();
+	if ((ia = in6_get_ia_from_ifp(ifp)) == NULL) {
+		pserialize_read_exit(s);
 	  	return NULL;
+	}
 	LIST_FOREACH(in6m, &ia->ia6_multiaddrs, in6m_entry) {
 		if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, addr))
 			break;
 	}
+	pserialize_read_exit(s);
 	return in6m;
 }
 
@@ -659,6 +701,7 @@ in6_next_multi(struct in6_multistep *step)
 	}
 	while (step->i_ia != NULL) {
 		in6m = LIST_FIRST(&step->i_ia->ia6_multiaddrs);
+		/* FIXME NOMPSAFE */
 		step->i_ia = IN6_ADDRLIST_READER_NEXT(step->i_ia);
 		if (in6m != NULL) {
 			step->i_in6m = LIST_NEXT(in6m, in6m_entry);
@@ -672,6 +715,7 @@ static inline struct in6_multi *
 in6_first_multi(struct in6_multistep *step)
 {						
 
+	/* FIXME NOMPSAFE */
 	step->i_ia = IN6_ADDRLIST_READER_FIRST();
 	step->i_in6m = NULL;			
 	return in6_next_multi(step);		
@@ -748,9 +792,15 @@ void	in6_ifremlocal(struct ifaddr *);
 void	in6_ifaddlocal(struct ifaddr *);
 void	in6_createmkludge(struct ifnet *);
 void	in6_purgemkludge(struct ifnet *);
-struct in6_ifaddr *in6ifa_ifpforlinklocal(const struct ifnet *, int);
-struct in6_ifaddr *in6ifa_ifpwithaddr(const struct ifnet *,
-    const struct in6_addr *);
+struct in6_ifaddr *
+	in6ifa_ifpforlinklocal(const struct ifnet *, int);
+struct in6_ifaddr *
+	in6ifa_ifpforlinklocal_psref(const struct ifnet *, int, struct psref *);
+struct in6_ifaddr *
+	in6ifa_ifpwithaddr(const struct ifnet *, const struct in6_addr *);
+struct in6_ifaddr *
+	in6ifa_ifpwithaddr_psref(const struct ifnet *, const struct in6_addr *,
+	    struct psref *);
 struct in6_ifaddr *in6ifa_ifwithaddr(const struct in6_addr *, uint32_t);
 char	*ip6_sprintf(const struct in6_addr *);
 int	in6_matchlen(struct in6_addr *, struct in6_addr *);
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
index d14589e..0655481 100644
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -565,8 +565,10 @@ ip6_input(struct mbuf *m, struct ifnet *rcvif)
 	 */
 	if (deliverifp && ip6_getdstifaddr(m) == NULL) {
 		struct in6_ifaddr *ia6;
+		int s = pserialize_read_enter();
 
 		ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst);
+		/* Depends on ip6_setdstifaddr never sleep */
 		if (ia6 != NULL && ip6_setdstifaddr(m, ia6) == NULL) {
 			/*
 			 * XXX maybe we should drop the packet here,
@@ -574,6 +576,7 @@ ip6_input(struct mbuf *m, struct ifnet *rcvif)
 			 * to the upper layers.
 			 */
 		}
+		pserialize_read_exit(s);
 	}
 
 	/*
@@ -701,9 +704,11 @@ ip6_input(struct mbuf *m, struct ifnet *rcvif)
 #ifdef IFA_STATS
 	if (deliverifp != NULL) {
 		struct in6_ifaddr *ia6;
+		int s = pserialize_read_enter();
 		ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst);
 		if (ia6)
 			ia6->ia_ifa.ifa_data.ifad_inbytes += m->m_pkthdr.len;
+		pserialize_read_exit(s);
 	}
 #endif
 	IP6_STATINC(IP6_STAT_DELIVERED);
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index 764be7a..4f074ef 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -764,13 +764,16 @@ ip6_output(
 		/* case 1-a and 2-a */
 		struct in6_ifaddr *ia6;
 		int sw_csum;
+		int s;
 
 		ip6 = mtod(m, struct ip6_hdr *);
+		s = pserialize_read_enter();
 		ia6 = in6_ifawithifp(ifp, &ip6->ip6_src);
 		if (ia6) {
 			/* Record statistics for this interface address. */
 			ia6->ia_ifa.ifa_data.ifad_outbytes += m->m_pkthdr.len;
 		}
+		pserialize_read_exit(s);
 
 		sw_csum = m->m_pkthdr.csum_flags & ~ifp->if_csum_flags_tx;
 		if ((sw_csum & (M_CSUM_UDPv6|M_CSUM_TCPv6)) != 0) {
@@ -956,7 +959,9 @@ sendorfree:
 		m->m_nextpkt = 0;
 		if (error == 0) {
 			struct in6_ifaddr *ia6;
+			int s;
 			ip6 = mtod(m, struct ip6_hdr *);
+			s = pserialize_read_enter();
 			ia6 = in6_ifawithifp(ifp, &ip6->ip6_src);
 			if (ia6) {
 				/*
@@ -966,6 +971,7 @@ sendorfree:
 				ia6->ia_ifa.ifa_data.ifad_outbytes +=
 				    m->m_pkthdr.len;
 			}
+			pserialize_read_exit(s);
 			KASSERT(dst != NULL);
 			error = nd6_output(ifp, origifp, m, dst, rt);
 		} else
diff --git a/sys/netinet6/mld6.c b/sys/netinet6/mld6.c
index 356008b..4476ff7 100644
--- a/sys/netinet6/mld6.c
+++ b/sys/netinet6/mld6.c
@@ -402,7 +402,9 @@ mld_input(struct mbuf *m, int off)
 	 * if we sent the last report.
 	 */
 	switch (mldh->mld_type) {
-	case MLD_LISTENER_QUERY:
+	case MLD_LISTENER_QUERY: {
+		struct psref psref;
+
 		if (ifp->if_flags & IFF_LOOPBACK)
 			break;
 
@@ -428,10 +430,14 @@ mld_input(struct mbuf *m, int off)
 		 */
 		timer = ntohs(mldh->mld_maxdelay);
 
-		ia = in6_get_ia_from_ifp(ifp);
+		ia = in6_get_ia_from_ifp_psref(ifp, &psref);
 		if (ia == NULL)
 			break;
 
+		/* The following operations may sleep */
+		m_put_rcvif(ifp, &s);
+		ifp = NULL;
+
 		LIST_FOREACH(in6m, &ia->ia6_multiaddrs, in6m_entry) {
 			if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &all_in6) ||
 			    IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) <
@@ -457,7 +463,9 @@ mld_input(struct mbuf *m, int off)
 				mld_starttimer(in6m);
 			}
 		}
+		ia6_release(ia, &psref);
 		break;
+	    }
 
 	case MLD_LISTENER_REPORT:
 		/*
@@ -514,6 +522,8 @@ mld_sendpkt(struct in6_multi *in6m, int type,
 	struct in6_ifaddr *ia = NULL;
 	struct ifnet *ifp = in6m->in6m_ifp;
 	int ignflags;
+	struct psref psref;
+	int bound;
 
 	/*
 	 * At first, find a link local address on the outgoing interface
@@ -522,20 +532,31 @@ mld_sendpkt(struct in6_multi *in6m, int type,
 	 * the case where we first join a link-local address.
 	 */
 	ignflags = (IN6_IFF_NOTREADY|IN6_IFF_ANYCAST) & ~IN6_IFF_TENTATIVE;
-	if ((ia = in6ifa_ifpforlinklocal(ifp, ignflags)) == NULL)
+	bound = curlwp_bind();
+	ia = in6ifa_ifpforlinklocal_psref(ifp, ignflags, &psref);
+	if (ia == NULL) {
+		curlwp_bindx(bound);
 		return;
-	if ((ia->ia6_flags & IN6_IFF_TENTATIVE))
+	}
+	if ((ia->ia6_flags & IN6_IFF_TENTATIVE)) {
+		ia6_release(ia, &psref);
 		ia = NULL;
+	}
 
 	/* Allocate two mbufs to store IPv6 header and MLD header */
 	mldh = mld_allocbuf(&mh, sizeof(struct mld_hdr), in6m, type);
-	if (mldh == NULL)
+	if (mldh == NULL) {
+		ia6_release(ia, &psref);
+		curlwp_bindx(bound);
 		return;
+	}
 
 	/* fill src/dst here */
  	ip6 = mtod(mh, struct ip6_hdr *);
  	ip6->ip6_src = ia ? ia->ia_addr.sin6_addr : in6addr_any;
  	ip6->ip6_dst = dst ? *dst : in6m->in6m_addr;
+	ia6_release(ia, &psref);
+	curlwp_bindx(bound);
 
 	mldh->mld_addr = in6m->in6m_addr;
 	in6_clearscope(&mldh->mld_addr); /* XXX */
@@ -645,6 +666,7 @@ in6_addmulti(struct in6_addr *maddr6, struct ifnet *ifp,
 		 */
 		in6m->in6m_refcount++;
 	} else {
+		int _s;
 		/*
 		 * New address; allocate a new multicast record
 		 * and link it into the interface's multicast list.
@@ -664,8 +686,10 @@ in6_addmulti(struct in6_addr *maddr6, struct ifnet *ifp,
 		callout_init(&in6m->in6m_timer_ch, CALLOUT_MPSAFE);
 		callout_setfunc(&in6m->in6m_timer_ch, mld_timeo, in6m);
 
+		_s = pserialize_read_enter();
 		ia = in6_get_ia_from_ifp(ifp);
 		if (ia == NULL) {
+			pserialize_read_exit(_s);
 			callout_destroy(&in6m->in6m_timer_ch);
 			free(in6m, M_IPMADDR);
 			splx(s);
@@ -674,7 +698,9 @@ in6_addmulti(struct in6_addr *maddr6, struct ifnet *ifp,
 		}
 		in6m->in6m_ia = ia;
 		ifaref(&ia->ia_ifa); /* gain a reference */
+		/* FIXME NOMPSAFE: need to lock */
 		LIST_INSERT_HEAD(&ia->ia6_multiaddrs, in6m, in6m_entry);
+		pserialize_read_exit(_s);
 
 		/*
 		 * Ask the network driver to update its multicast reception
@@ -816,7 +842,9 @@ in6_savemkludge(struct in6_ifaddr *oia)
 {
 	struct in6_ifaddr *ia;
 	struct in6_multi *in6m;
+	int s;
 
+	s = pserialize_read_enter();
 	ia = in6_get_ia_from_ifp(oia->ia_ifp);
 	if (ia) {	/* there is another address */
 		KASSERT(ia != oia);
@@ -825,6 +853,7 @@ in6_savemkludge(struct in6_ifaddr *oia)
 			ifaref(&ia->ia_ifa);
 			ifafree(&in6m->in6m_ia->ia_ifa);
 			in6m->in6m_ia = ia;
+			/* FIXME NOMPSAFE: need to lock */
 			LIST_INSERT_HEAD(&ia->ia6_multiaddrs, in6m, in6m_entry);
 		}
 	} else {	/* last address on this if deleted, save */
@@ -844,6 +873,7 @@ in6_savemkludge(struct in6_ifaddr *oia)
 			LIST_INSERT_HEAD(&mk->mk_head, in6m, in6m_entry);
 		}
 	}
+	pserialize_read_exit(s);
 }
 
 /*
@@ -986,8 +1016,8 @@ in6_multicast_sysctl(SYSCTLFN_ARGS)
 	uint32_t tmp;
 	int error;
 	size_t written;
-	struct psref psref;
-	int bound;
+	struct psref psref, psref_ia;
+	int bound, s;
 
 	if (namelen != 1)
 		return EINVAL;
@@ -1001,6 +1031,7 @@ in6_multicast_sysctl(SYSCTLFN_ARGS)
 
 	if (oldp == NULL) {
 		*oldlenp = 0;
+		s = pserialize_read_enter();
 		IFADDR_READER_FOREACH(ifa, ifp) {
 			if (ifa->ifa_addr->sa_family != AF_INET6)
 				continue;
@@ -1010,6 +1041,7 @@ in6_multicast_sysctl(SYSCTLFN_ARGS)
 				    sizeof(uint32_t);
 			}
 		}
+		pserialize_read_exit(s);
 		if_put(ifp, &psref);
 		curlwp_bindx(bound);
 		return 0;
@@ -1017,9 +1049,14 @@ in6_multicast_sysctl(SYSCTLFN_ARGS)
 
 	error = 0;
 	written = 0;
+	s = pserialize_read_enter();
 	IFADDR_READER_FOREACH(ifa, ifp) {
 		if (ifa->ifa_addr->sa_family != AF_INET6)
 			continue;
+
+		ifa_acquire(ifa, &psref_ia);
+		pserialize_read_exit(s);
+
 		ifa6 = (struct in6_ifaddr *)ifa;
 		LIST_FOREACH(in6m, &ifa6->ia6_multiaddrs, in6m_entry) {
 			if (written + 2 * sizeof(struct in6_addr) +
@@ -1044,8 +1081,13 @@ in6_multicast_sysctl(SYSCTLFN_ARGS)
 			oldp = (char *)oldp + sizeof(tmp);
 			written += sizeof(tmp);
 		}
+
+		s = pserialize_read_enter();
+		ifa_release(ifa, &psref_ia);
 	}
+	pserialize_read_exit(s);
 done:
+	ifa_release(ifa, &psref_ia);
 	if_put(ifp, &psref);
 	curlwp_bindx(bound);
 	*oldlenp = written;
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index a40ce48..bdc3559 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -571,6 +571,8 @@ nd6_timer_work(struct work *wk, void *arg)
 	struct nd_defrouter *next_dr, *dr;
 	struct nd_prefix *next_pr, *pr;
 	struct in6_ifaddr *ia6, *nia6;
+	int s, bound;
+	struct psref psref;
 
 	callout_reset(&nd6_timer_ch, nd6_prune * hz,
 	    nd6_timer, NULL);
@@ -592,9 +594,15 @@ nd6_timer_work(struct work *wk, void *arg)
 	 * However, from a stricter speci-confrmance standpoint, we should
 	 * rather separate address lifetimes and prefix lifetimes.
 	 */
+	bound = curlwp_bind();
   addrloop:
-	for (ia6 = IN6_ADDRLIST_WRITER_FIRST(); ia6; ia6 = nia6) {
-		nia6 = IN6_ADDRLIST_WRITER_NEXT(ia6);
+	s = pserialize_read_enter();
+	for (ia6 = IN6_ADDRLIST_READER_FIRST(); ia6; ia6 = nia6) {
+		nia6 = IN6_ADDRLIST_READER_NEXT(ia6);
+
+		ia6_acquire(ia6, &psref);
+		pserialize_read_exit(s);
+
 		/* check address lifetime */
 		if (IFA6_IS_INVALID(ia6)) {
 			int regen = 0;
@@ -615,7 +623,9 @@ nd6_timer_work(struct work *wk, void *arg)
 					regen = 1;
 			}
 
+			ia6_release(ia6, &psref);
  			in6_purgeaddr(&ia6->ia_ifa);
+			ia6 = NULL;
 
 			if (regen)
 				goto addrloop; /* XXX: see below */
@@ -649,6 +659,7 @@ nd6_timer_work(struct work *wk, void *arg)
 					 * loop just for safety.  Or does this
 					 * significantly reduce performance??
 					 */
+					ia6_release(ia6, &psref);
 					goto addrloop;
 				}
 			}
@@ -663,7 +674,11 @@ nd6_timer_work(struct work *wk, void *arg)
 				    (struct ifaddr *)ia6, 0, NULL);
 			}
 		}
+		s = pserialize_read_enter();
+		ia6_release(ia6, &psref);
 	}
+	pserialize_read_exit(s);
+	curlwp_bindx(bound);
 
 	/* expire prefix list */
 	LIST_FOREACH_SAFE(pr, &nd_prefix, ndpr_entry, next_pr) {
@@ -702,8 +717,10 @@ regen_tmpaddr(const struct in6_ifaddr *ia6)
 	struct ifaddr *ifa;
 	struct ifnet *ifp;
 	struct in6_ifaddr *public_ifa6 = NULL;
+	int s;
 
 	ifp = ia6->ia_ifa.ifa_ifp;
+	s = pserialize_read_enter();
 	IFADDR_READER_FOREACH(ifa, ifp) {
 		struct in6_ifaddr *it6;
 
@@ -745,18 +762,24 @@ regen_tmpaddr(const struct in6_ifaddr *ia6)
 
 	if (public_ifa6 != NULL) {
 		int e;
+		struct psref psref;
 
+		ia6_acquire(public_ifa6, &psref);
+		pserialize_read_exit(s);
 		/*
 		 * Random factor is introduced in the preferred lifetime, so
 		 * we do not need additional delay (3rd arg to in6_tmpifadd).
 		 */
 		if ((e = in6_tmpifadd(public_ifa6, 0, 0)) != 0) {
+			ia6_release(public_ifa6, &psref);
 			log(LOG_NOTICE, "regen_tmpaddr: failed to create a new"
 			    " tmp addr, errno=%d\n", e);
 			return -1;
 		}
+		ia6_release(public_ifa6, &psref);
 		return 0;
 	}
+		pserialize_read_exit(s);
 
 	return -1;
 }
@@ -914,6 +937,7 @@ nd6_is_new_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp)
 {
 	struct nd_prefix *pr;
 	struct ifaddr *dstaddr;
+	int s;
 
 	/*
 	 * A link-local address is always a neighbor.
@@ -979,20 +1003,15 @@ nd6_is_new_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp)
 	 * If the address is assigned on the node of the other side of
 	 * a p2p interface, the address should be a neighbor.
 	 */
+	s = pserialize_read_enter();
 	dstaddr = ifa_ifwithdstaddr(sin6tocsa(addr));
 	if (dstaddr != NULL) {
 		if (dstaddr->ifa_ifp == ifp) {
-#ifdef __FreeBSD__
-			/* XXX we need to ifaref in ifa_ifwithdstaddr as well */
-			ifafree(dstaddr);
-#endif
+			pserialize_read_exit(s);
 			return 1;
 		}
-#ifdef __FreeBSD__
-		/* XXX we need to ifaref in ifa_ifwithdstaddr as well */
-		ifafree(dstaddr);
-#endif
 	}
+	pserialize_read_exit(s);
 
 	/*
 	 * If the default router list is empty, all addresses are regarded
@@ -1374,7 +1393,9 @@ nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
 	}
 
 	switch (req) {
-	case RTM_ADD:
+	case RTM_ADD: {
+		int s;
+
 		RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt));
 		/*
 		 * There is no backward compatibility :)
@@ -1481,6 +1502,7 @@ nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
 		 * check if rt_getkey(rt) is an address assigned
 		 * to the interface.
 		 */
+		s = pserialize_read_enter();
 		ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp,
 		    &satocsin6(rt_getkey(rt))->sin6_addr);
 		if (ifa != NULL) {
@@ -1517,8 +1539,8 @@ nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
 				}
 			}
 		}
-
 	out:
+		pserialize_read_exit(s);
 		/*
 		 * If we have too many cache entries, initiate immediate
 		 * purging for some entries.
@@ -1526,6 +1548,7 @@ nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
 		if (rt->rt_ifp != NULL)
 			nd6_gc_neighbors(LLTABLE6(rt->rt_ifp));
 		break;
+	    }
 
 	case RTM_DELETE:
 		/* leave from solicited node multicast for proxy ND */
@@ -1709,6 +1732,7 @@ nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp)
 			 */
 			int duplicated_linklocal = 0;
 
+			s = pserialize_read_enter();
 			IFADDR_READER_FOREACH(ifa, ifp) {
 				if (ifa->ifa_addr->sa_family != AF_INET6)
 					continue;
@@ -1720,6 +1744,7 @@ nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp)
 					break;
 				}
 			}
+			pserialize_read_exit(s);
 
 			if (duplicated_linklocal) {
 				ND.flags |= ND6_IFF_IFDISABLED;
@@ -1732,18 +1757,29 @@ nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp)
 					in6_if_up(ifp);
 			}
 		} else if (!(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
-		    (ND.flags & ND6_IFF_IFDISABLED))
-		{
+		    (ND.flags & ND6_IFF_IFDISABLED)) {
+			int bound = curlwp_bind(); 
 			/* Mark all IPv6 addresses as tentative. */
 
 			ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED;
+			s = pserialize_read_enter();
 			IFADDR_READER_FOREACH(ifa, ifp) {
+				struct psref psref;
 				if (ifa->ifa_addr->sa_family != AF_INET6)
 					continue;
+				ifa_acquire(ifa, &psref);
+				pserialize_read_exit(s);
+
 				nd6_dad_stop(ifa);
+
 				ia = (struct in6_ifaddr *)ifa;
 				ia->ia6_flags |= IN6_IFF_TENTATIVE;
+
+				s = pserialize_read_enter();
+				ifa_release(ifa, &psref);
 			}
+			pserialize_read_exit(s);
+			curlwp_bindx(bound);
 		}
 
 		if (ND.flags & ND6_IFF_AUTO_LINKLOCAL) {
@@ -1761,9 +1797,10 @@ nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp)
 				 * address is assigned, and IFF_UP, try to
 				 * assign one.
 				 */
-				 int haslinklocal = 0;
+				int haslinklocal = 0;
 
-				 IFADDR_READER_FOREACH(ifa, ifp) {
+				s = pserialize_read_enter();
+				IFADDR_READER_FOREACH(ifa, ifp) {
 					if (ifa->ifa_addr->sa_family !=AF_INET6)
 						continue;
 					ia = (struct in6_ifaddr *)ifa;
@@ -1771,8 +1808,9 @@ nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp)
 						haslinklocal = 1;
 						break;
 					}
-				 }
-				 if (!haslinklocal)
+				}
+				pserialize_read_exit(s);
+				if (!haslinklocal)
 					in6_ifattach(ifp, NULL);
 			}
 		}
@@ -1793,22 +1831,30 @@ nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp)
 		s = splsoftnet();
 		LIST_FOREACH_SAFE(pfx, &nd_prefix, ndpr_entry, next) {
 			struct in6_ifaddr *ia, *ia_next;
+			int _s;
 
 			if (IN6_IS_ADDR_LINKLOCAL(&pfx->ndpr_prefix.sin6_addr))
 				continue; /* XXX */
 
 			/* do we really have to remove addresses as well? */
-			for (ia = IN6_ADDRLIST_WRITER_FIRST(); ia;
+		restart:
+			_s = pserialize_read_enter();
+			for (ia = IN6_ADDRLIST_READER_FIRST(); ia;
 			     ia = ia_next) {
 				/* ia might be removed.  keep the next ptr. */
-				ia_next = IN6_ADDRLIST_WRITER_NEXT(ia);
+				ia_next = IN6_ADDRLIST_READER_NEXT(ia);
 
 				if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0)
 					continue;
 
-				if (ia->ia6_ndpr == pfx)
+				if (ia->ia6_ndpr == pfx) {
+					pserialize_read_exit(_s);
+					/* XXX NOMPSAFE? */
 					in6_purgeaddr(&ia->ia_ifa);
+					goto restart;
+				}
 			}
+			pserialize_read_exit(_s);
 			prelist_remove(pfx);
 		}
 		splx(s);
@@ -2172,6 +2218,7 @@ nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
 
 	if (rt != NULL && (rt->rt_flags & RTF_GATEWAY) != 0) {
 		struct sockaddr_in6 *gw6 = satosin6(rt->rt_gateway);
+		int s;
 
 		/* XXX remain the check to keep the original behavior. */
 		/*
@@ -2182,6 +2229,7 @@ nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
 		 * if the gateway is our own address, which is
 		 * sometimes used to install a route to a p2p link.
 		 */
+		s = pserialize_read_enter();
 		if (!nd6_is_addr_neighbor(gw6, ifp) ||
 		    in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) {
 			/*
@@ -2192,8 +2240,10 @@ nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
 			if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
 				senderr(EHOSTUNREACH);
 
+			pserialize_read_exit(s);
 			goto sendpkt;
 		}
+		pserialize_read_exit(s);
 	}
 
 	/*
diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c
index 62099a2..479ac31 100644
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -104,7 +104,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
 	struct in6_addr taddr6;
 	struct in6_addr myaddr6;
 	char *lladdr = NULL;
-	struct ifaddr *ifa;
+	struct ifaddr *ifa = NULL;
 	int lladdrlen = 0;
 	int anycast = 0, proxy = 0, tentative = 0;
 	int router = ip6_forwarding;
@@ -112,6 +112,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
 	union nd_opts ndopts;
 	const struct sockaddr_dl *proxydl = NULL;
 	struct psref psref;
+	struct psref psref_ia;
 
 	ifp = m_get_rcvif_psref(m, &psref);
 	if (ifp == NULL)
@@ -216,14 +217,20 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
 	 */
 	/* (1) and (3) check. */
 #if NCARP > 0
-	if (ifp->if_carp && ifp->if_type != IFT_CARP)
+	if (ifp->if_carp && ifp->if_type != IFT_CARP) {
+		int s = pserialize_read_enter();
 		ifa = carp_iamatch6(ifp->if_carp, &taddr6);
-	else
+		if (ifa != NULL)
+			ifa_acquire(ifa, &psref_ia);
+		pserialize_read_exit(s);
+	} else
 		ifa = NULL;
 	if (!ifa)
-		ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
+		ifa = (struct ifaddr *)in6ifa_ifpwithaddr_psref(ifp, &taddr6,
+		    &psref_ia);
 #else
-	ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
+	ifa = (struct ifaddr *)in6ifa_ifpwithaddr_psref(ifp, &taddr6,
+	    &psref_ia);
 #endif
 
 	/* (2) check. */
@@ -239,8 +246,8 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
 			/*
 			 * proxy NDP for single entry
 			 */
-			ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
-				IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
+			ifa = (struct ifaddr *)in6ifa_ifpforlinklocal_psref(ifp,
+				IN6_IFF_NOTREADY|IN6_IFF_ANYCAST, &psref_ia);
 			if (ifa) {
 				proxy = 1;
 				proxydl = satocsdl(rt->rt_gateway);
@@ -299,9 +306,13 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
 		 */
 		if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
 			nd6_dad_ns_input(ifa);
+		ifa_release(ifa, &psref_ia);
+		ifa = NULL;
 
 		goto freeit;
 	}
+	ifa_release(ifa, &psref_ia);
+	ifa = NULL;
 
 	/*
 	 * If the source address is unspecified address, entries must not
@@ -331,6 +342,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
 	    (router ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED,
 	    tlladdr, (const struct sockaddr *)proxydl);
  freeit:
+	ifa_release(ifa, &psref_ia);
 	m_put_rcvif_psref(ifp, &psref);
 	m_freem(m);
 	return;
@@ -340,6 +352,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
 	nd6log(LOG_ERR, "dst=%s\n", ip6_sprintf(&daddr6));
 	nd6log(LOG_ERR, "tgt=%s\n", ip6_sprintf(&taddr6));
 	ICMP6_STATINC(ICMP6_STAT_BADNS);
+	ifa_release(ifa, &psref_ia);
 	m_put_rcvif_psref(ifp, &psref);
 	m_freem(m);
 }
@@ -430,6 +443,7 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
 			goto bad;
 	}
 	if (!dad) {
+		int s;
 		/*
 		 * RFC2461 7.2.2:
 		 * "If the source address of the packet prompting the
@@ -445,6 +459,7 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
 		 * - hsrc belongs to the outgoing interface.
 		 * Otherwise, we perform the source address selection as usual.
 		 */
+		s = pserialize_read_enter();
 		if (hsrc && in6ifa_ifpwithaddr(ifp, hsrc))
 			src = hsrc;
 		else {
@@ -459,9 +474,11 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
 				nd6log(LOG_DEBUG, "source can't be "
 				    "determined: dst=%s, error=%d\n",
 				    ip6_sprintf(&dst_sa.sin6_addr), error);
+				pserialize_read_exit(s);
 				goto bad;
 			}
 		}
+		pserialize_read_exit(s);
 	} else {
 		/*
 		 * Source address for DAD packet must always be IPv6
@@ -559,6 +576,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
 	int rt_announce;
 	bool checklink = false;
 	struct psref psref;
+	struct psref psref_ia;
 
 	ifp = m_get_rcvif_psref(m, &psref);
 	if (ifp == NULL)
@@ -613,7 +631,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
 		lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
 	}
 
-	ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
+	ifa = (struct ifaddr *)in6ifa_ifpwithaddr_psref(ifp, &taddr6, &psref_ia);
 
 	/*
 	 * Target address matches one of my interface address.
@@ -627,6 +645,8 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
 	if (ifa
 	 && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE)) {
 		nd6_dad_na_input(ifa);
+		ifa_release(ifa, &psref_ia);
+		ifa = NULL;
 		goto freeit;
 	}
 
@@ -635,6 +655,8 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
 		log(LOG_ERR,
 		    "nd6_na_input: duplicate IP6 address %s\n",
 		    ip6_sprintf(&taddr6));
+		ifa_release(ifa, &psref_ia);
+		ifa = NULL;
 		goto freeit;
 	}
 
diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c
index 63ee03f..4ff457b 100644
--- a/sys/netinet6/nd6_rtr.c
+++ b/sys/netinet6/nd6_rtr.c
@@ -66,7 +66,7 @@ static int rtpref(struct nd_defrouter *);
 static struct nd_defrouter *defrtrlist_update(struct nd_defrouter *);
 static int prelist_update(struct nd_prefixctl *, struct nd_defrouter *,
     struct mbuf *, int);
-static struct in6_ifaddr *in6_ifadd(struct nd_prefixctl *, int);
+static struct in6_ifaddr *in6_ifadd(struct nd_prefixctl *, int, struct psref *);
 static struct nd_pfxrouter *pfxrtr_lookup(struct nd_prefix *,
 	struct nd_defrouter *);
 static void pfxrtr_add(struct nd_prefix *, struct nd_defrouter *);
@@ -898,6 +898,7 @@ purge_detached(struct ifnet *ifp)
 	struct ifaddr *ifa, *ifa_next;
 
 	for (pr = nd_prefix.lh_first; pr; pr = pr_next) {
+		int s;
 		pr_next = pr->ndpr_next;
 
 		/*
@@ -913,6 +914,8 @@ purge_detached(struct ifnet *ifp)
 		    !LIST_EMPTY(&pr->ndpr_advrtrs)))
 			continue;
 
+	restart:
+		s = pserialize_read_enter();
 		for (ifa = IFADDR_READER_FIRST(ifp); ifa; ifa = ifa_next) {
 			ifa_next = IFADDR_READER_NEXT(ifa);
 			if (ifa->ifa_addr->sa_family != AF_INET6)
@@ -920,9 +923,13 @@ purge_detached(struct ifnet *ifp)
 			ia = (struct in6_ifaddr *)ifa;
 			if ((ia->ia6_flags & IN6_IFF_AUTOCONF) ==
 			    IN6_IFF_AUTOCONF && ia->ia6_ndpr == pr) {
+				pserialize_read_exit(s);
 				in6_purgeaddr(ifa);
+				goto restart;
 			}
 		}
+		pserialize_read_exit(s);
+
 		if (pr->ndpr_refcnt == 0)
 			prelist_remove(pr);
 	}
@@ -1065,6 +1072,7 @@ prelist_update(struct nd_prefixctl *newprc,
 	int error = 0;
 	int auth;
 	struct in6_addrlifetime lt6_tmp;
+	int ss;
 
 	auth = 0;
 	if (m) {
@@ -1187,6 +1195,7 @@ prelist_update(struct nd_prefixctl *newprc,
 	 * consider autoconfigured addresses while RFC2462 simply said
 	 * "address".
 	 */
+	ss = pserialize_read_enter();
 	IFADDR_READER_FOREACH(ifa, ifp) {
 		struct in6_ifaddr *ia6;
 		u_int32_t remaininglifetime;
@@ -1308,9 +1317,12 @@ prelist_update(struct nd_prefixctl *newprc,
 		ia6->ia6_lifetime = lt6_tmp;
 		ia6->ia6_updatetime = time_uptime;
 	}
+	pserialize_read_exit(ss);
+
 	if (ia6_match == NULL && newprc->ndprc_vltime) {
 		int ifidlen;
 		struct in6_ifaddr *ia6;
+		struct psref psref;
 
 		/*
 		 * 5.5.3 (d) (continued)
@@ -1340,7 +1352,7 @@ prelist_update(struct nd_prefixctl *newprc,
 			goto end;
 		}
 
-		if ((ia6 = in6_ifadd(newprc, mcast)) != NULL) {
+		if ((ia6 = in6_ifadd(newprc, mcast, &psref)) != NULL) {
 			/*
 			 * note that we should use pr (not newprc) for reference.
 			 */
@@ -1367,6 +1379,7 @@ prelist_update(struct nd_prefixctl *newprc,
 					    "address, errno=%d\n", e);
 				}
 			}
+			ia6_release(ia6, &psref);
 
 			/*
 			 * A newly added address might affect the status
@@ -1426,6 +1439,7 @@ pfxlist_onlink_check(void)
 	struct in6_ifaddr *ia;
 	struct nd_defrouter *dr;
 	struct nd_pfxrouter *pfxrtr = NULL;
+	int s;
 
 	/*
 	 * Check if there is a prefix that has a reachable advertising
@@ -1540,6 +1554,7 @@ pfxlist_onlink_check(void)
 	 * always be attached.
 	 * The precise detection logic is same as the one for prefixes.
 	 */
+	s = pserialize_read_enter();
 	IN6_ADDRLIST_READER_FOREACH(ia) {
 		if (!(ia->ia6_flags & IN6_IFF_AUTOCONF))
 			continue;
@@ -1556,20 +1571,30 @@ pfxlist_onlink_check(void)
 		if (find_pfxlist_reachable_router(ia->ia6_ndpr))
 			break;
 	}
+	pserialize_read_exit(s);
 
 	if (ia) {
+		int bound = curlwp_bind();
+
+		s = pserialize_read_enter();
 		IN6_ADDRLIST_READER_FOREACH(ia) {
+			struct ifaddr *ifa = (struct ifaddr *)ia;
+			struct psref psref;
+
 			if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0)
 				continue;
 
 			if (ia->ia6_ndpr == NULL) /* XXX: see above. */
 				continue;
 
+			ia6_acquire(ia, &psref);
+			pserialize_read_exit(s);
+
 			if (find_pfxlist_reachable_router(ia->ia6_ndpr)) {
 				if (ia->ia6_flags & IN6_IFF_DETACHED) {
 					ia->ia6_flags &= ~IN6_IFF_DETACHED;
 					ia->ia6_flags |= IN6_IFF_TENTATIVE;
-					nd6_dad_start((struct ifaddr *)ia,
+					nd6_dad_start(ifa,
 					    0);
 					/* We will notify the routing socket
 					 * of the DAD result, so no need to
@@ -1579,23 +1604,43 @@ pfxlist_onlink_check(void)
 				if ((ia->ia6_flags & IN6_IFF_DETACHED) == 0) {
 					ia->ia6_flags |= IN6_IFF_DETACHED;
 					rt_newaddrmsg(RTM_NEWADDR,
-					    (struct ifaddr *)ia, 0, NULL);
+					    ifa, 0, NULL);
 				}
 			}
+
+			s = pserialize_read_enter();
+			ia6_release(ia, &psref);
 		}
+		pserialize_read_exit(s);
+		curlwp_bindx(bound);
 	}
 	else {
+		int bound = curlwp_bind();
+
+		s = pserialize_read_enter();
 		IN6_ADDRLIST_READER_FOREACH(ia) {
 			if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0)
 				continue;
 
 			if (ia->ia6_flags & IN6_IFF_DETACHED) {
+				struct ifaddr *ifa = (struct ifaddr *)ia;
+				struct psref psref;
+
 				ia->ia6_flags &= ~IN6_IFF_DETACHED;
 				ia->ia6_flags |= IN6_IFF_TENTATIVE;
+
+				ia6_acquire(ia, &psref);
+				pserialize_read_exit(s);
+
 				/* Do we need a delay in this case? */
-				nd6_dad_start((struct ifaddr *)ia, 0);
+				nd6_dad_start(ifa, 0);
+
+				s = pserialize_read_enter();
+				ia6_release(ia, &psref);
 			}
 		}
+		pserialize_read_exit(s);
+		curlwp_bindx(bound);
 	}
 }
 
@@ -1608,6 +1653,8 @@ nd6_prefix_onlink(struct nd_prefix *pr)
 	struct nd_prefix *opr;
 	u_long rtflags;
 	int error = 0;
+	struct psref psref;
+	int bound;
 
 	/* sanity check */
 	if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
@@ -1640,14 +1687,18 @@ nd6_prefix_onlink(struct nd_prefix *pr)
 	 * We prefer link-local addresses as the associated interface address.
 	 */
 	/* search for a link-local addr */
-	ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
-	    IN6_IFF_NOTREADY | IN6_IFF_ANYCAST);
+	bound = curlwp_bind();
+	ifa = (struct ifaddr *)in6ifa_ifpforlinklocal_psref(ifp,
+	    IN6_IFF_NOTREADY | IN6_IFF_ANYCAST, &psref);
 	if (ifa == NULL) {
-		/* XXX: freebsd does not have ifa_ifwithaf */
+		int s = pserialize_read_enter();
 		IFADDR_READER_FOREACH(ifa, ifp) {
 			if (ifa->ifa_addr->sa_family == AF_INET6)
 				break;
 		}
+		if (ifa != NULL)
+			ifa_acquire(ifa, &psref);
+		pserialize_read_exit(s);
 		/* should we care about ia6_flags? */
 	}
 	if (ifa == NULL) {
@@ -1661,6 +1712,7 @@ nd6_prefix_onlink(struct nd_prefix *pr)
 		    " to add route for a prefix(%s/%d) on %s\n",
 		    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
 		    pr->ndpr_plen, if_name(ifp));
+		curlwp_bindx(bound);
 		return (0);
 	}
 
@@ -1697,6 +1749,8 @@ nd6_prefix_onlink(struct nd_prefix *pr)
 		    ip6_sprintf(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr),
 		    ip6_sprintf(&mask6.sin6_addr), rtflags, error);
 	}
+	ifa_release(ifa, &psref);
+	curlwp_bindx(bound);
 
 	return (error);
 }
@@ -1772,7 +1826,7 @@ nd6_prefix_offlink(struct nd_prefix *pr)
 }
 
 static struct in6_ifaddr *
-in6_ifadd(struct nd_prefixctl *prc, int mcast)
+in6_ifadd(struct nd_prefixctl *prc, int mcast, struct psref *psref)
 {
 	struct ifnet *ifp = prc->ndprc_ifp;
 	struct ifaddr *ifa;
@@ -1782,6 +1836,7 @@ in6_ifadd(struct nd_prefixctl *prc, int mcast)
 	struct in6_addr mask;
 	int prefixlen = prc->ndprc_plen;
 	int updateflags;
+	int s;
 
 	in6_prefixlen2mask(&mask, prefixlen);
 
@@ -1805,11 +1860,14 @@ in6_ifadd(struct nd_prefixctl *prc, int mcast)
 	 * with the same interface identifier, than to have multiple addresses
 	 * with different interface identifiers.
 	 */
+	s = pserialize_read_enter();
 	ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */
 	if (ifa)
 		ib = (struct in6_ifaddr *)ifa;
-	else
+	else {
+		pserialize_read_exit(s);
 		return NULL;
+	}
 
 #if 0 /* don't care link local addr state, and always do DAD */
 	/* if link-local address is not eligible, do not autoconfigure. */
@@ -1825,6 +1883,7 @@ in6_ifadd(struct nd_prefixctl *prc, int mcast)
 		nd6log(LOG_INFO, "wrong prefixlen for %s "
 		    "(prefix=%d ifid=%d)\n",
 		    if_name(ifp), prefixlen, 128 - plen0);
+		pserialize_read_exit(s);
 		return NULL;
 	}
 
@@ -1852,6 +1911,7 @@ in6_ifadd(struct nd_prefixctl *prc, int mcast)
 	    (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]);
 	ifra.ifra_addr.sin6_addr.s6_addr32[3] |=
 	    (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]);
+	pserialize_read_exit(s);
 
 	/* new prefix mask. */
 	sockaddr_in6_init(&ifra.ifra_prefixmask, &mask, 0, 0, 0);
@@ -1869,12 +1929,15 @@ in6_ifadd(struct nd_prefixctl *prc, int mcast)
 	 * usually not happen, but we can still see this case, e.g., if we
 	 * have manually configured the exact address to be configured.
 	 */
+	s = pserialize_read_enter();
 	if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) {
 		/* this should be rare enough to make an explicit log */
 		log(LOG_INFO, "in6_ifadd: %s is already configured\n",
 		    ip6_sprintf(&ifra.ifra_addr.sin6_addr));
+		pserialize_read_exit(s);
 		return (NULL);
 	}
+	pserialize_read_exit(s);
 
 	/*
 	 * Allocate ifaddr structure, link into chain, etc.
@@ -1892,7 +1955,7 @@ in6_ifadd(struct nd_prefixctl *prc, int mcast)
 		return (NULL);	/* ifaddr must not have been allocated. */
 	}
 
-	ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
+	ia = in6ifa_ifpwithaddr_psref(ifp, &ifra.ifra_addr.sin6_addr, psref);
 
 	return (ia);		/* this is always non-NULL */
 }
@@ -2007,14 +2070,17 @@ in6_tmpifadd(
 	if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0)
 		return (error);
 
+	s = pserialize_read_enter();
 	newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
 	if (newia == NULL) {	/* XXX: can it happen? */
+		pserialize_read_exit(s);
 		nd6log(LOG_ERR,
 		    "ifa update succeeded, but we got no ifaddr\n");
 		return (EINVAL); /* XXX */
 	}
 	newia->ia6_ndpr = ia0->ia6_ndpr;
 	newia->ia6_ndpr->ndpr_refcnt++;
+	pserialize_read_exit(s);
 
 	/*
 	 * A newly added address might affect the status of other addresses.
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c
index 8470352..ec55db3 100644
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -671,8 +671,9 @@ rip6_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
 {
 	struct in6pcb *in6p = sotoin6pcb(so);
 	struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
-	struct ifaddr *ia = NULL;
+	struct ifaddr *ifa = NULL;
 	int error = 0;
+	int s;
 
 	KASSERT(solocked(so));
 	KASSERT(in6p != NULL);
@@ -692,15 +693,24 @@ rip6_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
 	 */
 	if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr))
 		return EADDRNOTAVAIL;
+	s = pserialize_read_enter();
 	if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
-	    (ia = ifa_ifwithaddr(sin6tosa(addr))) == 0)
-		return EADDRNOTAVAIL;
-	if (ia && ifatoia6(ia)->ia6_flags &
+	    (ifa = ifa_ifwithaddr(sin6tosa(addr))) == NULL) {
+		error = EADDRNOTAVAIL;
+		goto out;
+	}
+	if (ifa && (ifatoia6(ifa))->ia6_flags &
 	    (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
-	     IN6_IFF_DETACHED|IN6_IFF_DEPRECATED))
-		return EADDRNOTAVAIL;
+	     IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
+		error = EADDRNOTAVAIL;
+		goto out;
+	}
+
 	in6p->in6p_laddr = addr->sin6_addr;
-	return 0;
+	error = 0;
+out:
+	pserialize_read_exit(s);
+	return error;
 }
 
 static int
diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c
index 1c35875..075be64 100644
--- a/sys/netinet6/sctp6_usrreq.c
+++ b/sys/netinet6/sctp6_usrreq.c
@@ -1294,6 +1294,7 @@ static int
 sctp6_purgeif(struct socket *so, struct ifnet *ifp)
 {
 	struct ifaddr *ifa;
+	/* FIXME NOMPSAFE */
 	IFADDR_READER_FOREACH(ifa, ifp) {
 		if (ifa->ifa_addr->sa_family == PF_INET6) {
 			sctp_delete_ip_address(ifa);
diff --git a/sys/netinet6/udp6_output.c b/sys/netinet6/udp6_output.c
index e9a47dc..86d1574 100644
--- a/sys/netinet6/udp6_output.c
+++ b/sys/netinet6/udp6_output.c
@@ -227,6 +227,7 @@ udp6_output(struct in6pcb * const in6p, struct mbuf *m,
 
 		if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
 			struct psref psref;
+			int bound = curlwp_bind();
 
 			laddr = in6_selectsrc(sin6, optp,
 			    in6p->in6p_moptions,
@@ -236,9 +237,11 @@ udp6_output(struct in6pcb * const in6p, struct mbuf *m,
 			    (error = in6_setscope(&sin6->sin6_addr,
 			    oifp, NULL))) {
 				if_put(oifp, &psref);
+				curlwp_bindx(bound);
 				goto release;
 			}
 			if_put(oifp, &psref);
+			curlwp_bindx(bound);
 		} else {
 			/*
 			 * XXX: freebsd[34] does not have in_selectsrc, but