Modify most routines returning 'struct ifaddr *' to return references
rather than pointers, requiring callers to properly dispose of those
references.  The following routines now return references:

  ifaddr_byindex
  ifa_ifwithaddr
  ifa_ifwithbroadaddr
  ifa_ifwithdstaddr
  ifa_ifwithnet
  ifaof_ifpforaddr
  ifa_ifwithroute
  ifa_ifwithroute_fib
  rt_getifa
  rt_getifa_fib
  IFP_TO_IA
  ip_rtaddr
  in6_ifawithifp
  in6ifa_ifpforlinklocal
  in6ifa_ifpwithaddr
  in6_ifadd
  carp_iamatch6

Remove unused macro which didn't have required referencing:

  IFP_TO_IA6

This closes many small races in which changes to interface
or address lists while an ifaddr was in use could lead to use of freed
memory (etc).

In a few cases, add missing if_addr_list locking required to safely
acquire references.


Index: netinet/in.c
===================================================================
--- netinet/in.c	(revision 194622)
+++ netinet/in.c	(working copy)
@@ -219,7 +219,6 @@ in_control(struct socket *so, u_long cmd, caddr_t
 	register struct ifaddr *ifa;
 	struct in_addr allhosts_addr;
 	struct in_addr dst;
-	struct in_ifaddr *oia;
 	struct in_ifinfo *ii;
 	struct in_aliasreq *ifra = (struct in_aliasreq *)data;
 	struct sockaddr_in oldaddr;
@@ -323,8 +322,10 @@ in_control(struct socket *so, u_long cmd, caddr_t
 			break;
 		}
 	}
-	IF_ADDR_LOCK(ifp);
+	if (ia != NULL)
+		ifa_ref(&ia->ia_ifa);
 	if (ia == NULL) {
+		IF_ADDR_LOCK(ifp);
 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
 			iap = ifatoia(ifa);
 			if (iap->ia_addr.sin_family == AF_INET) {
@@ -336,6 +337,9 @@ in_control(struct socket *so, u_long cmd, caddr_t
 				break;
 			}
 		}
+		if (ia != NULL)
+			ifa_ref(&ia->ia_ifa);
+		IF_ADDR_UNLOCK(ifp);
 	}
 	if (ia == NULL)
 		iaIsFirst = 1;
@@ -345,23 +349,29 @@ in_control(struct socket *so, u_long cmd, caddr_t
 	case SIOCAIFADDR:
 	case SIOCDIFADDR:
 		if (ifra->ifra_addr.sin_family == AF_INET) {
+			struct in_ifaddr *oia;
+
 			for (oia = ia; ia; ia = TAILQ_NEXT(ia, ia_link)) {
 				if (ia->ia_ifp == ifp  &&
 				    ia->ia_addr.sin_addr.s_addr ==
 				    ifra->ifra_addr.sin_addr.s_addr)
 					break;
 			}
+			if (ia != NULL && ia != oia)
+				ifa_ref(&ia->ia_ifa);
+			if (oia != NULL && ia != oia)
+				ifa_free(&oia->ia_ifa);
 			if ((ifp->if_flags & IFF_POINTOPOINT)
 			    && (cmd == SIOCAIFADDR)
 			    && (ifra->ifra_dstaddr.sin_addr.s_addr
 				== INADDR_ANY)) {
 				error = EDESTADDRREQ;
-				goto out_unlock;
+				goto out;
 			}
 		}
 		if (cmd == SIOCDIFADDR && ia == NULL) {
 			error = EADDRNOTAVAIL;
-			goto out_unlock;
+			goto out;
 		}
 		/* FALLTHROUGH */
 	case SIOCSIFADDR:
@@ -373,7 +383,7 @@ in_control(struct socket *so, u_long cmd, caddr_t
 				    M_ZERO);
 			if (ia == NULL) {
 				error = ENOBUFS;
-				goto out_unlock;
+				goto out;
 			}
 
 			ifa = &ia->ia_ifa;
@@ -390,10 +400,15 @@ in_control(struct socket *so, u_long cmd, caddr_t
 			}
 			ia->ia_ifp = ifp;
 
+			ifa_ref(ifa);			/* if_addrhead */
+			IF_ADDR_LOCK(ifp);
 			TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
+			IF_ADDR_UNLOCK(ifp);
+			ifa_ref(ifa);			/* in_ifaddrhead */
 			s = splnet();
 			TAILQ_INSERT_TAIL(&V_in_ifaddrhead, ia, ia_link);
 			splx(s);
+			ifa_ref(ifa);			/* in_control */
 			iaIsNew = 1;
 		}
 		break;
@@ -405,64 +420,53 @@ in_control(struct socket *so, u_long cmd, caddr_t
 	case SIOCGIFBRDADDR:
 		if (ia == NULL) {
 			error = EADDRNOTAVAIL;
-			goto out_unlock;
+			goto out;
 		}
 		break;
 	}
 
 	/*
-	 * Most paths in this switch return directly or via out_unlock.  Only
-	 * paths that remove the address break in order to hit common removal
-	 * code.
-	 *
-	 * XXXRW: We enter the switch with IF_ADDR_LOCK() held, but leave
-	 * without it.  This is a bug.
+	 * Most paths in this switch return directly or via outk.  Only paths
+	 * that remove the address break in order to hit common removal code.
 	 */
-	IF_ADDR_LOCK_ASSERT(ifp);
 	switch (cmd) {
 	case SIOCGIFADDR:
 		*((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr;
-		goto out_unlock;
+		goto out;
 
 	case SIOCGIFBRDADDR:
 		if ((ifp->if_flags & IFF_BROADCAST) == 0) {
 			error = EINVAL;
-			goto out_unlock;
+			goto out;
 		}
 		*((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr;
-		goto out_unlock;
+		goto out;
 
 	case SIOCGIFDSTADDR:
 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
 			error = EINVAL;
-			goto out_unlock;
+			goto out;
 		}
 		*((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr;
-		goto out_unlock;
+		goto out;
 
 	case SIOCGIFNETMASK:
 		*((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask;
-		goto out_unlock;
+		goto out;
 
 	case SIOCSIFDSTADDR:
 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
 			error = EINVAL;
-			goto out_unlock;
+			goto out;
 		}
 		oldaddr = ia->ia_dstaddr;
 		ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr;
-		IF_ADDR_UNLOCK(ifp);
-
-		/*
-		 * XXXRW: Locks dropped for if_ioctl and rtinit, but ia is
-		 * still being used.
-		 */
 		if (ifp->if_ioctl != NULL) {
 			error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR,
 			    (caddr_t)ia);
 			if (error) {
 				ia->ia_dstaddr = oldaddr;
-				return (error);
+				goto out;
 			}
 		}
 		if (ia->ia_flags & IFA_ROUTE) {
@@ -472,23 +476,17 @@ in_control(struct socket *so, u_long cmd, caddr_t
 					(struct sockaddr *)&ia->ia_dstaddr;
 			rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
 		}
-		return (0);
+		goto out;
 
 	case SIOCSIFBRDADDR:
 		if ((ifp->if_flags & IFF_BROADCAST) == 0) {
 			error = EINVAL;
-			goto out_unlock;
+			goto out;
 		}
 		ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr;
-		goto out_unlock;
+		goto out;
 
 	case SIOCSIFADDR:
-		IF_ADDR_UNLOCK(ifp);
-
-		/*
-		 * XXXRW: Locks dropped for in_ifinit and in_joingroup, but ia
-		 * is still being used.
-		 */
 		error = in_ifinit(ifp, ia,
 		    (struct sockaddr_in *) &ifr->ifr_addr, 1);
 		if (error != 0 && iaIsNew)
@@ -502,12 +500,13 @@ in_control(struct socket *so, u_long cmd, caddr_t
 			}
 			EVENTHANDLER_INVOKE(ifaddr_event, ifp);
 		}
-		return (0);
+		error = 0;
+		goto out;
 
 	case SIOCSIFNETMASK:
 		ia->ia_sockmask.sin_addr = ifra->ifra_addr.sin_addr;
 		ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr);
-		goto out_unlock;
+		goto out;
 
 	case SIOCAIFADDR:
 		maskIsNew = 0;
@@ -521,12 +520,6 @@ in_control(struct socket *so, u_long cmd, caddr_t
 					       ia->ia_addr.sin_addr.s_addr)
 				hostIsNew = 0;
 		}
-		IF_ADDR_UNLOCK(ifp);
-
-		/*
-		 * XXXRW: Locks dropped for in_ifscrub and in_ifinit, but ia
-		 * is still being used.
-		 */
 		if (ifra->ifra_mask.sin_len) {
 			in_ifscrub(ifp, ia);
 			ia->ia_sockmask = ifra->ifra_mask;
@@ -545,7 +538,7 @@ in_control(struct socket *so, u_long cmd, caddr_t
 		    (hostIsNew || maskIsNew))
 			error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
 		if (error != 0 && iaIsNew)
-			break;
+			goto out;
 
 		if ((ifp->if_flags & IFF_BROADCAST) &&
 		    (ifra->ifra_broadaddr.sin_family == AF_INET))
@@ -559,15 +552,10 @@ in_control(struct socket *so, u_long cmd, caddr_t
 			}
 			EVENTHANDLER_INVOKE(ifaddr_event, ifp);
 		}
-		return (error);
+		goto out;
 
 	case SIOCDIFADDR:
-		IF_ADDR_UNLOCK(ifp);
-
 		/*
-		 * XXXRW: Locks dropped for in_ifscrub and in_ifadown, but ia
-		 * is still being used.
-		 *
 		 * in_ifscrub kills the interface route.
 		 */
 		in_ifscrub(ifp, ia);
@@ -580,6 +568,7 @@ in_control(struct socket *so, u_long cmd, caddr_t
 		 */
 		in_ifadown(&ia->ia_ifa, 1);
 		EVENTHANDLER_INVOKE(ifaddr_event, ifp);
+		ifa_free(&ia->ia_ifa);
 		error = 0;
 		break;
 
@@ -587,25 +576,25 @@ in_control(struct socket *so, u_long cmd, caddr_t
 		panic("in_control: unsupported ioctl");
 	}
 
-	/*
-	 * XXXRW: In a more ideal world, we would still be holding
-	 * IF_ADDR_LOCK here.
-	 */
 	IF_ADDR_LOCK(ifp);
 	TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
 	IF_ADDR_UNLOCK(ifp);
+	ifa_free(&ia->ia_ifa);				/* if_addrhead */
 	s = splnet();
 	TAILQ_REMOVE(&V_in_ifaddrhead, ia, ia_link);
+	ifa_free(&ia->ia_ifa);				/* in_ifaddrhead */
 	if (ia->ia_addr.sin_family == AF_INET) {
+		struct in_ifaddr *if_ia;
+
 		LIST_REMOVE(ia, ia_hash);
 		/*
 		 * If this is the last IPv4 address configured on this
 		 * interface, leave the all-hosts group.
 		 * No state-change report need be transmitted.
 		 */
-		oia = NULL;
-		IFP_TO_IA(ifp, oia);
-		if (oia == NULL) {
+		if_ia = NULL;
+		IFP_TO_IA(ifp, if_ia);
+		if (if_ia == NULL) {
 			ii = ((struct in_ifinfo *)ifp->if_afdata[AF_INET]);
 			IN_MULTI_LOCK();
 			if (ii->ii_allhosts) {
@@ -614,16 +603,14 @@ in_control(struct socket *so, u_long cmd, caddr_t
 				ii->ii_allhosts = NULL;
 			}
 			IN_MULTI_UNLOCK();
-		}
+		} else
+			ifa_free(&if_ia->ia_ifa);
 	}
-	ifa_free(&ia->ia_ifa);
 	splx(s);
-
+out:
+	if (ia != NULL)
+		ifa_free(&ia->ia_ifa);
 	return (error);
-
-out_unlock:
-	IF_ADDR_UNLOCK(ifp);
-	return (error);
 }
 
 /*
Index: netinet/ip_carp.c
===================================================================
--- netinet/ip_carp.c	(revision 194622)
+++ netinet/ip_carp.c	(working copy)
@@ -1239,6 +1239,7 @@ carp_iamatch6(void *v, struct in6_addr *taddr)
  			    (SC2IFP(vh)->if_flags & IFF_UP) &&
 			    (SC2IFP(vh)->if_drv_flags & IFF_DRV_RUNNING) &&
 			    vh->sc_state == MASTER) {
+				ifa_ref(ifa);
 				IF_ADDR_UNLOCK(SC2IFP(vh));
 			    	CARP_UNLOCK(cif);
 				return (ifa);
Index: netinet/ip_divert.c
===================================================================
--- netinet/ip_divert.c	(revision 194622)
+++ netinet/ip_divert.c	(working copy)
@@ -464,6 +464,7 @@ div_output(struct socket *so, struct mbuf *m, stru
 				goto cantsend;
 			}
 			m->m_pkthdr.rcvif = ifa->ifa_ifp;
+			ifa_free(ifa);
 		}
 #ifdef MAC
 		mac_socket_create_mbuf(so, m);
Index: netinet/in_pcb.c
===================================================================
--- netinet/in_pcb.c	(revision 194622)
+++ netinet/in_pcb.c	(working copy)
@@ -549,7 +549,6 @@ static int
 in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
     struct ucred *cred)
 {
-	struct in_ifaddr *ia;
 	struct ifaddr *ifa;
 	struct sockaddr *sa;
 	struct sockaddr_in *sin;
@@ -559,7 +558,6 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *fad
 	KASSERT(laddr != NULL, ("%s: laddr NULL", __func__));
 
 	error = 0;
-	ia = NULL;
 	bzero(&sro, sizeof(sro));
 
 	sin = (struct sockaddr_in *)&sro.ro_dst;
@@ -585,6 +583,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *fad
 	 * the source address from.
 	 */
 	if (sro.ro_rt == NULL || sro.ro_rt->rt_ifp == NULL) {
+		struct in_ifaddr *ia;
 		struct ifnet *ifp;
 
 		ia = ifatoia(ifa_ifwithdstaddr((struct sockaddr *)sin));
@@ -597,10 +596,12 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *fad
 
 		if (cred == NULL || !prison_flag(cred, PR_IP4)) {
 			laddr->s_addr = ia->ia_addr.sin_addr.s_addr;
+			ifa_free(&ia->ia_ifa);
 			goto done;
 		}
 
 		ifp = ia->ia_ifp;
+		ifa_free(&ia->ia_ifa);
 		ia = NULL;
 		IF_ADDR_LOCK(ifp);
 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
@@ -636,6 +637,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *fad
 	 * 3. as a last resort return the 'default' jail address.
 	 */
 	if ((sro.ro_rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0) {
+		struct in_ifaddr *ia;
 		struct ifnet *ifp;
 
 		/* If not jailed, use the default returned. */
@@ -658,10 +660,10 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *fad
 		 * 2. Check if we have any address on the outgoing interface
 		 *    belonging to this jail.
 		 */
+		ia = NULL;
 		ifp = sro.ro_rt->rt_ifp;
 		IF_ADDR_LOCK(ifp);
 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
-
 			sa = ifa->ifa_addr;
 			if (sa->sa_family != AF_INET)
 				continue;
@@ -694,6 +696,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *fad
 	 */
 	if ((sro.ro_rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
 		struct sockaddr_in sain;
+		struct in_ifaddr *ia;
 
 		bzero(&sain, sizeof(struct sockaddr_in));
 		sain.sin_family = AF_INET;
@@ -710,6 +713,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *fad
 				goto done;
 			}
 			laddr->s_addr = ia->ia_addr.sin_addr.s_addr;
+			ifa_free(&ia->ia_ifa);
 			goto done;
 		}
 
@@ -718,6 +722,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *fad
 			struct ifnet *ifp;
 
 			ifp = ia->ia_ifp;
+			ifa_free(&ia->ia_ifa);
 			ia = NULL;
 			IF_ADDR_LOCK(ifp);
 			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
Index: netinet/in_mcast.c
===================================================================
--- netinet/in_mcast.c	(revision 194622)
+++ netinet/in_mcast.c	(working copy)
@@ -1722,6 +1722,7 @@ inp_getmoptions(struct inpcb *inp, struct sockopt
 				if (ia != NULL) {
 					mreqn.imr_address =
 					    IA_SIN(ia)->sin_addr;
+					ifa_free(&ia->ia_ifa);
 				}
 			}
 		}
Index: netinet/ip_output.c
===================================================================
--- netinet/ip_output.c	(revision 194622)
+++ netinet/ip_output.c	(working copy)
@@ -288,6 +288,7 @@ again:
 			goto bad;
 		}
 		ia = ifatoia(ro->ro_rt->rt_ifa);
+		ifa_ref(&ia->ia_ifa);
 		ifp = ro->ro_rt->rt_ifp;
 		ro->ro_rt->rt_rmx.rmx_pksent++;
 		if (ro->ro_rt->rt_flags & RTF_GATEWAY)
@@ -667,6 +668,8 @@ done:
 	if (ro == &iproute && ro->ro_rt && !nortfree) {
 		RTFREE(ro->ro_rt);
 	}
+	if (ia != NULL)
+		ifa_free(&ia->ia_ifa);
 	return (error);
 bad:
 	m_freem(m);
Index: netinet/ip_input.c
===================================================================
--- netinet/ip_input.c	(revision 194622)
+++ netinet/ip_input.c	(working copy)
@@ -1331,8 +1331,8 @@ ipproto_unregister(u_char ipproto)
 }
 
 /*
- * Given address of next destination (final or next hop),
- * return internet address info of interface to be used to get there.
+ * Given address of next destination (final or next hop), return (referenced)
+ * internet address info of interface to be used to get there.
  */
 struct in_ifaddr *
 ip_rtaddr(struct in_addr dst, u_int fibnum)
@@ -1352,6 +1352,7 @@ ip_rtaddr(struct in_addr dst, u_int fibnum)
 		return (NULL);
 
 	ifa = ifatoia(sro.ro_rt->rt_ifa);
+	ifa_ref(&ifa->ia_ifa);
 	RTFREE(sro.ro_rt);
 	return (ifa);
 }
@@ -1526,11 +1527,16 @@ ip_forward(struct mbuf *m, int srcrt)
 		else {
 			if (mcopy)
 				m_freem(mcopy);
+			if (ia != NULL)
+				ifa_free(&ia->ia_ifa);
 			return;
 		}
 	}
-	if (mcopy == NULL)
+	if (mcopy == NULL) {
+		if (ia != NULL)
+			ifa_free(&ia->ia_ifa);
 		return;
+	}
 
 	switch (error) {
 
@@ -1588,6 +1594,8 @@ ip_forward(struct mbuf *m, int srcrt)
 		 */
 		if (V_ip_sendsourcequench == 0) {
 			m_freem(mcopy);
+			if (ia != NULL)
+				ifa_free(&ia->ia_ifa);
 			return;
 		} else {
 			type = ICMP_SOURCEQUENCH;
@@ -1597,8 +1605,12 @@ ip_forward(struct mbuf *m, int srcrt)
 
 	case EACCES:			/* ipfw denied packet */
 		m_freem(mcopy);
+		if (ia != NULL)
+			ifa_free(&ia->ia_ifa);
 		return;
 	}
+	if (ia != NULL)
+		ifa_free(&ia->ia_ifa);
 	icmp_error(mcopy, type, code, dest.s_addr, mtu);
 }
 
Index: netinet/ip_mroute.c
===================================================================
--- netinet/ip_mroute.c	(revision 194622)
+++ netinet/ip_mroute.c	(working copy)
@@ -883,6 +883,7 @@ add_vif(struct vifctl *vifcp)
 	    return EADDRNOTAVAIL;
 	}
 	ifp = ifa->ifa_ifp;
+	ifa_free(ifa);
     }
 
     if ((vifcp->vifc_flags & VIFF_TUNNEL) != 0) {
Index: netinet/ip_icmp.c
===================================================================
--- netinet/ip_icmp.c	(revision 194622)
+++ netinet/ip_icmp.c	(working copy)
@@ -536,10 +536,12 @@ icmp_input(struct mbuf *m, int off)
 		}
 		ia = (struct in_ifaddr *)ifaof_ifpforaddr(
 			    (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
-		if (ia == 0)
+		if (ia == NULL)
 			break;
-		if (ia->ia_ifp == 0)
+		if (ia->ia_ifp == NULL) {
+			ifa_free(&ia->ia_ifa);
 			break;
+		}
 		icp->icmp_type = ICMP_MASKREPLY;
 		if (V_icmpmaskfake == 0)
 			icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
@@ -551,6 +553,7 @@ icmp_input(struct mbuf *m, int off)
 			else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
 			    ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
 		}
+		ifa_free(&ia->ia_ifa);
 reflect:
 		ip->ip_len += hlen;	/* since ip_input deducts this */
 		ICMPSTAT_INC(icps_reflect);
@@ -748,6 +751,7 @@ icmp_reflect(struct mbuf *m)
 		goto done;
 	}
 	t = IA_SIN(ia)->sin_addr;
+	ifa_free(&ia->ia_ifa);
 match:
 #ifdef MAC
 	mac_netinet_icmp_replyinplace(m);
Index: netinet/ip_options.c
===================================================================
--- netinet/ip_options.c	(revision 194622)
+++ netinet/ip_options.c	(working copy)
@@ -164,9 +164,8 @@ ip_dooptions(struct mbuf *m, int pass)
 				goto bad;
 			}
 			ipaddr.sin_addr = ip->ip_dst;
-			ia = (struct in_ifaddr *)
-				ifa_ifwithaddr((struct sockaddr *)&ipaddr);
-			if (ia == NULL) {
+			if (ifa_ifwithaddr_check((struct sockaddr *)&ipaddr)
+			    == 0) {
 				if (opt == IPOPT_SSRR) {
 					type = ICMP_UNREACH;
 					code = ICMP_UNREACH_SRCFAIL;
@@ -245,6 +244,7 @@ dropit:
 			ip->ip_dst = ipaddr.sin_addr;
 			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
 			    sizeof(struct in_addr));
+			ifa_free(&ia->ia_ifa);
 			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
 			/*
 			 * Let ip_intr's mcast routing check handle mcast pkts
@@ -286,6 +286,7 @@ dropit:
 			}
 			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
 			    sizeof(struct in_addr));
+			ifa_free(&ia->ia_ifa);
 			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
 			break;
 
@@ -331,6 +332,7 @@ dropit:
 					continue;
 				(void)memcpy(sin, &IA_SIN(ia)->sin_addr,
 				    sizeof(struct in_addr));
+				ifa_free(&ia->ia_ifa);
 				cp[IPOPT_OFFSET] += sizeof(struct in_addr);
 				off += sizeof(struct in_addr);
 				break;
Index: netinet/in_var.h
===================================================================
--- netinet/in_var.h	(revision 194622)
+++ netinet/in_var.h	(working copy)
@@ -146,14 +146,16 @@ do { \
  * Macro for finding the internet address structure (in_ifaddr) corresponding
  * to a given interface (ifnet structure).
  */
-#define IFP_TO_IA(ifp, ia) \
-	/* struct ifnet *ifp; */ \
-	/* struct in_ifaddr *ia; */ \
-{ \
-	for ((ia) = TAILQ_FIRST(&V_in_ifaddrhead); \
-	    (ia) != NULL && (ia)->ia_ifp != (ifp); \
-	    (ia) = TAILQ_NEXT((ia), ia_link)) \
-		continue; \
+#define IFP_TO_IA(ifp, ia)						\
+	/* struct ifnet *ifp; */					\
+	/* struct in_ifaddr *ia; */					\
+{									\
+	for ((ia) = TAILQ_FIRST(&V_in_ifaddrhead);			\
+	    (ia) != NULL && (ia)->ia_ifp != (ifp);			\
+	    (ia) = TAILQ_NEXT((ia), ia_link))				\
+		continue;						\
+	if ((ia) != NULL)						\
+		ifa_ref(&(ia)->ia_ifa);					\
 }
 #endif
 
Index: netinet/igmp.c
===================================================================
--- netinet/igmp.c	(revision 194622)
+++ netinet/igmp.c	(working copy)
@@ -1234,8 +1234,10 @@ igmp_input_v1_report(struct ifnet *ifp, /*const*/
 	 */
 	if (V_igmp_recvifkludge && in_nullhost(ip->ip_src)) {
 		IFP_TO_IA(ifp, ia);
-		if (ia != NULL)
+		if (ia != NULL) {
 			ip->ip_src.s_addr = htonl(ia->ia_subnet);
+			ifa_free(&ia->ia_ifa);
+		}
 	}
 
 	CTR3(KTR_IGMPV3, "process v1 report %s on ifp %p(%s)",
@@ -1327,16 +1329,23 @@ igmp_input_v2_report(struct ifnet *ifp, /*const*/
 	 * group.
 	 */
 	IFP_TO_IA(ifp, ia);
-	if (ia != NULL && in_hosteq(ip->ip_src, IA_SIN(ia)->sin_addr))
+	if (ia != NULL && in_hosteq(ip->ip_src, IA_SIN(ia)->sin_addr)) {
+		ifa_free(&ia->ia_ifa);
 		return (0);
+	}
 
 	IGMPSTAT_INC(igps_rcv_reports);
 
-	if (ifp->if_flags & IFF_LOOPBACK)
+	if (ifp->if_flags & IFF_LOOPBACK) {
+		if (ia != NULL)
+			ifa_free(&ia->ia_ifa);
 		return (0);
+	}
 
 	if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr)) ||
 	    !in_hosteq(igmp->igmp_group, ip->ip_dst)) {
+		if (ia != NULL)
+			ifa_free(&ia->ia_ifa);
 		IGMPSTAT_INC(igps_rcv_badreports);
 		return (EINVAL);
 	}
@@ -1352,6 +1361,8 @@ igmp_input_v2_report(struct ifnet *ifp, /*const*/
 		if (ia != NULL)
 			ip->ip_src.s_addr = htonl(ia->ia_subnet);
 	}
+	if (ia != NULL)
+		ifa_free(&ia->ia_ifa);
 
 	CTR3(KTR_IGMPV3, "process v2 report %s on ifp %p(%s)",
 	     inet_ntoa(igmp->igmp_group), ifp, ifp->if_xname);
@@ -3535,8 +3546,10 @@ igmp_v3_encap_report(struct ifnet *ifp, struct mbu
 		struct in_ifaddr *ia;
 
 		IFP_TO_IA(ifp, ia);
-		if (ia != NULL)
+		if (ia != NULL) {
 			ip->ip_src = ia->ia_addr.sin_addr;
+			ifa_free(&ia->ia_ifa);
+		}
 	}
 
 	ip->ip_dst.s_addr = htonl(INADDR_ALLRPTS_GROUP);
Index: netipx/ipx_pcb.c
===================================================================
--- netipx/ipx_pcb.c	(revision 194622)
+++ netipx/ipx_pcb.c	(working copy)
@@ -158,7 +158,6 @@ noname:
 int
 ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td)
 {
-	struct ipx_ifaddr *ia;
 	struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)nam;
 	struct ipx_addr *dst;
 	struct route *ro;
@@ -167,8 +166,6 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockadd
 	IPX_LIST_LOCK_ASSERT();
 	IPX_LOCK_ASSERT(ipxp);
 
-	ia = NULL;
-
 	if (sipx->sipx_family != AF_IPX)
 		return (EAFNOSUPPORT);
 	if (sipx->sipx_port == 0 || ipx_nullhost(sipx->sipx_addr))
@@ -213,6 +210,8 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockadd
 		    rtalloc_ign(ro, 0);
 	}
 	if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) {
+		struct ipx_ifaddr *ia = NULL;
+
 		/*
 		 * If route is known or can be allocated now,
 		 * our src addr is taken from the i/f, else punt.
@@ -225,8 +224,10 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockadd
 		if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) {
 			IPX_IFADDR_RLOCK();
 			for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
-				if (ia->ia_ifp == ifp)
+				if (ia->ia_ifp == ifp) {
+					ifa_ref(&ia->ia_ifa);
 					break;
+				}
 			IPX_IFADDR_RUNLOCK();
 		}
 		if (ia == NULL) {
@@ -235,16 +236,28 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockadd
 			ia = (struct ipx_ifaddr *)
 				ifa_ifwithdstaddr((struct sockaddr *)sipx);
 			sipx->sipx_addr.x_port = fport;
-			if (ia == NULL)
+			if (ia == NULL) {
+				IPX_IFADDR_RLOCK();
 				ia = ipx_iaonnetof(&sipx->sipx_addr);
-			if (ia == NULL)
+				if (ia != NULL)
+					ifa_ref(&ia->ia_ifa);
+				IPX_IFADDR_RUNLOCK();
+			}
+			if (ia == NULL) {
+				IPX_IFADDR_RLOCK();
 				ia = ipx_ifaddr;
+				if (ia != NULL)
+					ifa_ref(&ia->ia_ifa);
+				IPX_IFADDR_RUNLOCK();
+			}
 			if (ia == NULL)
 				return (EADDRNOTAVAIL);
 		}
 		ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net;
+		ifa_free(&ia->ia_ifa);
 	}
 	if (ipx_nullhost(ipxp->ipxp_laddr)) {
+		struct ipx_ifaddr *ia = NULL;
 		/*
 		 * If route is known or can be allocated now,
 		 * our src addr is taken from the i/f, else punt.
@@ -257,8 +270,10 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockadd
 		if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) {
 			IPX_IFADDR_RLOCK();
 			for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
-				if (ia->ia_ifp == ifp)
+				if (ia->ia_ifp == ifp) {
+					ifa_ref(&ia->ia_ifa);
 					break;
+				}
 			IPX_IFADDR_RUNLOCK();
 		}
 		if (ia == NULL) {
@@ -270,17 +285,22 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockadd
 			if (ia == NULL) {
 				IPX_IFADDR_RLOCK();
 				ia = ipx_iaonnetof(&sipx->sipx_addr);
+				if (ia != NULL)
+					ifa_ref(&ia->ia_ifa);
 				IPX_IFADDR_RUNLOCK();
 			}
 			if (ia == NULL) {
 				IPX_IFADDR_RLOCK();
 				ia = ipx_ifaddr;
+				if (ia != NULL)
+					ifa_ref(&ia->ia_ifa);
 				IPX_IFADDR_RUNLOCK();
 			}
 			if (ia == NULL)
 				return (EADDRNOTAVAIL);
 		}
 		ipxp->ipxp_laddr.x_host = satoipx_addr(ia->ia_addr).x_host;
+		ifa_free(&ia->ia_ifa);
 	}
 	if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0))
 		return (EADDRINUSE);
Index: net80211/ieee80211.c
===================================================================
--- net80211/ieee80211.c	(revision 194622)
+++ net80211/ieee80211.c	(working copy)
@@ -301,6 +301,7 @@ ieee80211_ifattach(struct ieee80211com *ic,
 	sdl->sdl_type = IFT_ETHER;		/* XXX IFT_IEEE80211? */
 	sdl->sdl_alen = IEEE80211_ADDR_LEN;
 	IEEE80211_ADDR_COPY(LLADDR(sdl), macaddr);
+	ifa_free(ifa);
 }
 
 /*
Index: net/if.c
===================================================================
--- net/if.c	(revision 194622)
+++ net/if.c	(working copy)
@@ -264,6 +264,8 @@ ifaddr_byindex(u_short idx)
 
 	IFNET_RLOCK();
 	ifa = ifnet_byindex_locked(idx)->if_addr;
+	if (ifa != NULL)
+		ifa_ref(ifa);
 	IFNET_RUNLOCK();
 	return (ifa);
 }
@@ -1480,6 +1482,7 @@ ifa_ifwithaddr_internal(struct sockaddr *addr)
 			if (ifa->ifa_addr->sa_family != addr->sa_family)
 				continue;
 			if (sa_equal(addr, ifa->ifa_addr)) {
+				ifa_ref(ifa);
 				IF_ADDR_UNLOCK(ifp);
 				goto done;
 			}
@@ -1488,6 +1491,7 @@ ifa_ifwithaddr_internal(struct sockaddr *addr)
 			    ifa->ifa_broadaddr &&
 			    ifa->ifa_broadaddr->sa_len != 0 &&
 			    sa_equal(ifa->ifa_broadaddr, addr)) {
+				ifa_ref(ifa);
 				IF_ADDR_UNLOCK(ifp);
 				goto done;
 			}
@@ -1535,6 +1539,7 @@ ifa_ifwithbroadaddr(struct sockaddr *addr)
 			    ifa->ifa_broadaddr &&
 			    ifa->ifa_broadaddr->sa_len != 0 &&
 			    sa_equal(ifa->ifa_broadaddr, addr)) {
+				ifa_ref(ifa);
 				IF_ADDR_UNLOCK(ifp);
 				goto done;
 			}
@@ -1568,6 +1573,7 @@ ifa_ifwithdstaddr(struct sockaddr *addr)
 				continue;
 			if (ifa->ifa_dstaddr != NULL &&
 			    sa_equal(addr, ifa->ifa_dstaddr)) {
+				ifa_ref(ifa);
 				IF_ADDR_UNLOCK(ifp);
 				goto done;
 			}
@@ -1590,7 +1596,7 @@ ifa_ifwithnet(struct sockaddr *addr)
 	INIT_VNET_NET(curvnet);
 	struct ifnet *ifp;
 	struct ifaddr *ifa;
-	struct ifaddr *ifa_maybe = (struct ifaddr *) 0;
+	struct ifaddr *ifa_maybe = NULL;
 	u_int af = addr->sa_family;
 	char *addr_data = addr->sa_data, *cplim;
 
@@ -1605,8 +1611,10 @@ ifa_ifwithnet(struct sockaddr *addr)
 	}
 
 	/*
-	 * Scan though each interface, looking for ones that have
-	 * addresses in this address family.
+	 * Scan though each interface, looking for ones that have addresses
+	 * in this address family.  Maintain a reference on ifa_maybe once
+	 * we find one, as we release the IF_ADDR_LOCK() that kept it stable
+	 * when we move onto the next interface.
 	 */
 	IFNET_RLOCK();
 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
@@ -1627,6 +1635,7 @@ next:				continue;
 				 */
 				if (ifa->ifa_dstaddr != NULL &&
 				    sa_equal(addr, ifa->ifa_dstaddr)) {
+					ifa_ref(ifa);
 					IF_ADDR_UNLOCK(ifp);
 					goto done;
 				}
@@ -1637,6 +1646,7 @@ next:				continue;
 				 */
 				if (ifa->ifa_claim_addr) {
 					if ((*ifa->ifa_claim_addr)(ifa, addr)) {
+						ifa_ref(ifa);
 						IF_ADDR_UNLOCK(ifp);
 						goto done;
 					}
@@ -1667,17 +1677,24 @@ next:				continue;
 				 * before continuing to search
 				 * for an even better one.
 				 */
-				if (ifa_maybe == 0 ||
+				if (ifa_maybe == NULL ||
 				    rn_refines((caddr_t)ifa->ifa_netmask,
-				    (caddr_t)ifa_maybe->ifa_netmask))
+				    (caddr_t)ifa_maybe->ifa_netmask)) {
+					if (ifa_maybe != NULL)
+						ifa_free(ifa_maybe);
 					ifa_maybe = ifa;
+					ifa_ref(ifa_maybe);
+				}
 			}
 		}
 		IF_ADDR_UNLOCK(ifp);
 	}
 	ifa = ifa_maybe;
+	ifa_maybe = NULL;
 done:
 	IFNET_RUNLOCK();
+	if (ifa_maybe != NULL)
+		ifa_free(ifa_maybe);
 	return (ifa);
 }
 
@@ -1691,7 +1708,7 @@ ifaof_ifpforaddr(struct sockaddr *addr, struct ifn
 	struct ifaddr *ifa;
 	char *cp, *cp2, *cp3;
 	char *cplim;
-	struct ifaddr *ifa_maybe = 0;
+	struct ifaddr *ifa_maybe = NULL;
 	u_int af = addr->sa_family;
 
 	if (af >= AF_MAX)
@@ -1700,7 +1717,7 @@ ifaof_ifpforaddr(struct sockaddr *addr, struct ifn
 	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
 		if (ifa->ifa_addr->sa_family != af)
 			continue;
-		if (ifa_maybe == 0)
+		if (ifa_maybe == NULL)
 			ifa_maybe = ifa;
 		if (ifa->ifa_netmask == 0) {
 			if (sa_equal(addr, ifa->ifa_addr) ||
@@ -1726,6 +1743,8 @@ ifaof_ifpforaddr(struct sockaddr *addr, struct ifn
 	}
 	ifa = ifa_maybe;
 done:
+	if (ifa != NULL)
+		ifa_ref(ifa);
 	IF_ADDR_UNLOCK(ifp);
 	return (ifa);
 }
@@ -1752,7 +1771,6 @@ link_rtrequest(int cmd, struct rtentry *rt, struct
 		return;
 	ifa = ifaof_ifpforaddr(dst, ifp);
 	if (ifa) {
-		ifa_ref(ifa);		/* XXX */
 		oifa = rt->rt_ifa;
 		rt->rt_ifa = ifa;
 		ifa_free(oifa);
Index: net/route.c
===================================================================
--- net/route.c	(revision 194622)
+++ net/route.c	(working copy)
@@ -526,6 +526,7 @@ rtredirect_fib(struct sockaddr *dst,
 	struct ifaddr *ifa;
 	struct radix_node_head *rnh;
 
+	ifa = NULL;
 	rnh = rt_tables_get_rnh(fibnum, dst->sa_family);
 	if (rnh == NULL) {
 		error = EAFNOSUPPORT;
@@ -631,6 +632,8 @@ out:
 	info.rti_info[RTAX_NETMASK] = netmask;
 	info.rti_info[RTAX_AUTHOR] = src;
 	rt_missmsg(RTM_REDIRECT, &info, flags, error);
+	if (ifa != NULL)
+		ifa_free(ifa);
 }
 
 int
@@ -660,6 +663,9 @@ rtioctl_fib(u_long req, caddr_t data, u_int fibnum
 #endif /* INET */
 }
 
+/*
+ * For both ifa_ifwithroute() routines, 'ifa' is returned referenced.
+ */
 struct ifaddr *
 ifa_ifwithroute(int flags, struct sockaddr *dst, struct sockaddr *gateway)
 {
@@ -716,18 +722,22 @@ ifa_ifwithroute_fib(int flags, struct sockaddr *ds
 		default:
 			break;
 		}
+		if (!not_found && rt->rt_ifa != NULL) {
+			ifa = rt->rt_ifa;
+			ifa_ref(ifa);
+		}
 		RT_REMREF(rt);
 		RT_UNLOCK(rt);
-		if (not_found)
+		if (not_found || ifa == NULL)
 			return (NULL);
-		if ((ifa = rt->rt_ifa) == NULL)
-			return (NULL);
 	}
 	if (ifa->ifa_addr->sa_family != dst->sa_family) {
 		struct ifaddr *oifa = ifa;
 		ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
 		if (ifa == NULL)
 			ifa = oifa;
+		else
+			ifa_free(oifa);
 	}
 	return (ifa);
 }
@@ -786,6 +796,10 @@ rt_getifa(struct rt_addrinfo *info)
 	return (rt_getifa_fib(info, 0));
 }
 
+/*
+ * Look up rt_addrinfo for a specific fib.  Note that if rti_ifa is defined,
+ * it will be referenced so the caller must free it.
+ */
 int
 rt_getifa_fib(struct rt_addrinfo *info, u_int fibnum)
 {
@@ -798,8 +812,10 @@ rt_getifa_fib(struct rt_addrinfo *info, u_int fibn
 	 */
 	if (info->rti_ifp == NULL && ifpaddr != NULL &&
 	    ifpaddr->sa_family == AF_LINK &&
-	    (ifa = ifa_ifwithnet(ifpaddr)) != NULL)
+	    (ifa = ifa_ifwithnet(ifpaddr)) != NULL) {
 		info->rti_ifp = ifa->ifa_ifp;
+		ifa_free(ifa);
+	}
 	if (info->rti_ifa == NULL && ifaaddr != NULL)
 		info->rti_ifa = ifa_ifwithaddr(ifaaddr);
 	if (info->rti_ifa == NULL) {
@@ -1092,8 +1108,11 @@ rtrequest1_fib(int req, struct rt_addrinfo *info,
 			senderr(error);
 		ifa = info->rti_ifa;
 		rt = uma_zalloc(V_rtzone, M_NOWAIT | M_ZERO);
-		if (rt == NULL)
+		if (rt == NULL) {
+			if (ifa != NULL)
+				ifa_free(ifa);
 			senderr(ENOBUFS);
+		}
 		RT_LOCK_INIT(rt);
 		rt->rt_flags = RTF_UP | flags;
 		rt->rt_fibnum = fibnum;
@@ -1104,6 +1123,8 @@ rtrequest1_fib(int req, struct rt_addrinfo *info,
 		RT_LOCK(rt);
 		if ((error = rt_setgate(rt, dst, gateway)) != 0) {
 			RT_LOCK_DESTROY(rt);
+			if (ifa != NULL)
+				ifa_free(ifa);
 			uma_zfree(V_rtzone, rt);
 			senderr(error);
 		}
@@ -1122,11 +1143,10 @@ rtrequest1_fib(int req, struct rt_addrinfo *info,
 			bcopy(dst, ndst, dst->sa_len);
 
 		/*
-		 * Note that we now have a reference to the ifa.
+		 * We use the ifa reference returned by rt_getifa_fib().
 		 * This moved from below so that rnh->rnh_addaddr() can
 		 * examine the ifa and  ifa->ifa_ifp if it so desires.
 		 */
-		ifa_ref(ifa);
 		rt->rt_ifa = ifa;
 		rt->rt_ifp = ifa->ifa_ifp;
 		rt->rt_rmx.rmx_weight = 1;
Index: net/rtsock.c
===================================================================
--- net/rtsock.c	(revision 194622)
+++ net/rtsock.c	(working copy)
@@ -683,6 +683,13 @@ route_output(struct mbuf *m, struct socket *so)
 				RT_UNLOCK(rt);
 				RADIX_NODE_HEAD_LOCK(rnh);
 				error = rt_getifa_fib(&info, rt->rt_fibnum);
+				/*
+				 * XXXRW: Really we should release this
+				 * reference later, but this maintains
+				 * historical behavior.
+				 */
+				if (info.rti_ifa != NULL)
+					ifa_free(info.rti_ifa);
 				RADIX_NODE_HEAD_UNLOCK(rnh);
 				if (error != 0)
 					senderr(error);
Index: netinet6/in6_ifattach.c
===================================================================
--- netinet6/in6_ifattach.c	(revision 194622)
+++ netinet6/in6_ifattach.c	(working copy)
@@ -513,6 +513,7 @@ in6_ifattach_linklocal(struct ifnet *ifp, struct i
 		/* NOTREACHED */
 	}
 #endif
+	ifa_free(&ia->ia_ifa);
 
 	/*
 	 * Make the link-local prefix (fe80::%link/64) as on-link.
@@ -737,11 +738,15 @@ in6_ifattach(struct ifnet *ifp, struct ifnet *alti
 	 * XXX multiple loopback interface case.
 	 */
 	if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
+		struct ifaddr *ifa;
+
 		in6 = in6addr_loopback;
-		if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
+		ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &in6);
+		if (ifa == NULL) {
 			if (in6_ifattach_loopback(ifp) != 0)
 				return;
-		}
+		} else
+			ifa_free(ifa);
 	}
 
 	/*
@@ -755,7 +760,8 @@ in6_ifattach(struct ifnet *ifp, struct ifnet *alti
 			} else {
 				/* failed to assign linklocal address. bark? */
 			}
-		}
+		} else
+			ifa_free(&ia->ia_ifa);
 	}
 
 #ifdef IFT_STF			/* XXX */
Index: netinet6/raw_ip6.c
===================================================================
--- netinet6/raw_ip6.c	(revision 194622)
+++ netinet6/raw_ip6.c	(working copy)
@@ -714,7 +714,7 @@ rip6_bind(struct socket *so, struct sockaddr *nam,
 	INIT_VNET_INET6(so->so_vnet);
 	struct inpcb *inp;
 	struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
-	struct ifaddr *ia = NULL;
+	struct ifaddr *ifa = NULL;
 	int error = 0;
 
 	inp = sotoinpcb(so);
@@ -730,14 +730,17 @@ rip6_bind(struct socket *so, struct sockaddr *nam,
 		return (error);
 
 	if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
-	    (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0)
+	    (ifa = ifa_ifwithaddr((struct sockaddr *)addr)) == 0)
 		return (EADDRNOTAVAIL);
-	if (ia &&
-	    ((struct in6_ifaddr *)ia)->ia6_flags &
+	if (ifa != NULL &&
+	    ((struct in6_ifaddr *)ifa)->ia6_flags &
 	    (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
 	     IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
+		ifa_free(ifa);
 		return (EADDRNOTAVAIL);
 	}
+	if (ifa != NULL)
+		ifa_free(ifa);
 	INP_INFO_WLOCK(&V_ripcbinfo);
 	INP_WLOCK(inp);
 	inp->in6p_laddr = addr->sin6_addr;
Index: netinet6/in6_var.h
===================================================================
--- netinet6/in6_var.h	(revision 194622)
+++ netinet6/in6_var.h	(working copy)
@@ -498,25 +498,6 @@ do {								\
 
 extern struct in6_addr zeroin6_addr;
 extern u_char inet6ctlerrmap[];
-
-/*
- * Macro for finding the internet address structure (in6_ifaddr) corresponding
- * to a given interface (ifnet structure).
- */
-
-#define IFP_TO_IA6(ifp, ia)				\
-/* struct ifnet *ifp; */				\
-/* struct in6_ifaddr *ia; */				\
-do {									\
-	struct ifaddr *ifa;						\
-	IF_ADDR_LOCK_ASSERT(ifp);					\
-	TAILQ_FOREACH(ifa, &(ifp)->if_addrhead, ifa_link) {		\
-		if (ifa->ifa_addr->sa_family == AF_INET6)		\
-			break;						\
-	}								\
-	(ia) = (struct in6_ifaddr *)ifa;				\
-} while (/*CONSTCOND*/ 0)
-
 #endif /* _KERNEL */
 
 /*
Index: netinet6/ip6_output.c
===================================================================
--- netinet6/ip6_output.c	(revision 194622)
+++ netinet6/ip6_output.c	(working copy)
@@ -904,6 +904,7 @@ passout:
 			/* Record statistics for this interface address. */
 			ia6->ia_ifa.if_opackets++;
 			ia6->ia_ifa.if_obytes += m->m_pkthdr.len;
+			ifa_free(&ia6->ia_ifa);
 		}
 		error = nd6_output(ifp, origifp, m, dst, ro->ro_rt);
 		goto done;
Index: netinet6/icmp6.c
===================================================================
--- netinet6/icmp6.c	(revision 194622)
+++ netinet6/icmp6.c	(working copy)
@@ -2074,7 +2074,7 @@ icmp6_reflect(struct mbuf *m, size_t off)
 	INIT_VNET_INET6(curvnet);
 	struct ip6_hdr *ip6;
 	struct icmp6_hdr *icmp6;
-	struct in6_ifaddr *ia;
+	struct in6_ifaddr *ia = NULL;
 	int plen;
 	int type, code;
 	struct ifnet *outif = NULL;
@@ -2220,9 +2220,13 @@ icmp6_reflect(struct mbuf *m, size_t off)
 	if (outif)
 		icmp6_ifoutstat_inc(outif, type, code);
 
+	if (ia != NULL)
+		ifa_free(&ia->ia_ifa);
 	return;
 
  bad:
+	if (ia != NULL)
+		ifa_free(&ia->ia_ifa);
 	m_freem(m);
 	return;
 }
@@ -2541,6 +2545,8 @@ icmp6_redirect_output(struct mbuf *m0, struct rten
 						 IN6_IFF_ANYCAST)) == NULL)
 			goto fail;
 		ifp_ll6 = &ia->ia_addr.sin6_addr;
+		/* XXXRW: reference released prematurely. */
+		ifa_free(&ia->ia_ifa);
 	}
 
 	/* get ip6 linklocal address for the router. */
Index: netinet6/nd6.c
===================================================================
--- netinet6/nd6.c	(revision 194622)
+++ netinet6/nd6.c	(working copy)
@@ -957,8 +957,13 @@ nd6_is_new_addr_neighbor(struct sockaddr_in6 *addr
 	 * a p2p interface, the address should be a neighbor.
 	 */
 	dstaddr = ifa_ifwithdstaddr((struct sockaddr *)addr);
-	if ((dstaddr != NULL) && (dstaddr->ifa_ifp == ifp))
-		return (1);
+	if (dstaddr != NULL) {
+		if (dstaddr->ifa_ifp == ifp) {
+			ifa_free(dstaddr);
+			return (1);
+		}
+		ifa_free(dstaddr);
+	}
 
 	/*
 	 * If the default router list is empty, all addresses are regarded
Index: netinet6/nd6_nbr.c
===================================================================
--- netinet6/nd6_nbr.c	(revision 194622)
+++ netinet6/nd6_nbr.c	(working copy)
@@ -355,6 +355,8 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len
 	    (V_ip6_forwarding ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED,
 	    tlladdr, (struct sockaddr *)proxydl);
  freeit:
+	if (ifa != NULL)
+		ifa_free(ifa);
 	m_freem(m);
 	return;
 
@@ -366,6 +368,8 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len
 	nd6log((LOG_ERR, "nd6_ns_input: tgt=%s\n",
 		ip6_sprintf(ip6bufs, &taddr6)));
 	ICMP6STAT_INC(icp6s_badns);
+	if (ifa != NULL)
+		ifa_free(ifa);
 	m_freem(m);
 }
 
@@ -456,6 +460,8 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_
 			goto bad;
 	}
 	if (!dad) {
+		struct ifaddr *ifa;
+
 		/*
 		 * RFC2461 7.2.2:
 		 * "If the source address of the packet prompting the
@@ -486,9 +492,11 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_
 			else
 				hsrc = NULL;
 		}
-		if (hsrc && in6ifa_ifpwithaddr(ifp, hsrc))
+		if (hsrc && (ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp,
+		    hsrc)) != NULL) {
 			src = hsrc;
-		else {
+			ifa_free(ifa);
+		} else {
 			int error;
 			struct sockaddr_in6 dst_sa;
 
@@ -679,12 +687,14 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len
 	 */
 	if (ifa
 	 && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE)) {
+		ifa_free(ifa);
 		nd6_dad_na_input(ifa);
 		goto freeit;
 	}
 
 	/* Just for safety, maybe unnecessary. */
 	if (ifa) {
+		ifa_free(ifa);
 		log(LOG_ERR,
 		    "nd6_na_input: duplicate IP6 address %s\n",
 		    ip6_sprintf(ip6bufs, &taddr6));
Index: netinet6/in6.c
===================================================================
--- netinet6/in6.c	(revision 194622)
+++ netinet6/in6.c	(working copy)
@@ -321,8 +321,6 @@ in6_control(struct socket *so, u_long cmd, caddr_t
 		break;
 	}
 	if (sa6 && sa6->sin6_family == AF_INET6) {
-		int error = 0;
-
 		if (sa6->sin6_scope_id != 0)
 			error = sa6_embedscope(sa6, 0);
 		else
@@ -345,7 +343,8 @@ in6_control(struct socket *so, u_long cmd, caddr_t
 		 * on a single interface, SIOCSIFxxx ioctls are deprecated.
 		 */
 		/* we decided to obsolete this command (20000704) */
-		return (EINVAL);
+		error = EINVAL;
+		goto out;
 
 	case SIOCDIFADDR_IN6:
 		/*
@@ -355,8 +354,10 @@ in6_control(struct socket *so, u_long cmd, caddr_t
 		 * 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 */
 	case SIOCAIFADDR_IN6:
 		/*
@@ -364,16 +365,17 @@ in6_control(struct socket *so, u_long cmd, caddr_t
 		 * 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 out;
+		}
 
 		if (td != NULL) {
 			error = priv_check(td, (cmd == SIOCDIFADDR_IN6) ? 
 			    PRIV_NET_DELIFADDR : PRIV_NET_ADDIFADDR);
 			if (error)
-				return (error);
+				goto out;
 		}
-
 		break;
 
 	case SIOCGIFADDR_IN6:
@@ -384,9 +386,12 @@ in6_control(struct socket *so, u_long cmd, caddr_t
 	case SIOCGIFDSTADDR_IN6:
 	case SIOCGIFALIFETIME_IN6:
 		/* must think again about its semantics */
-		if (ia == NULL)
-			return (EADDRNOTAVAIL);
+		if (ia == NULL) {
+			error = EADDRNOTAVAIL;
+			goto out;
+		}
 		break;
+
 	case SIOCSIFALIFETIME_IN6:
 	    {
 		struct in6_addrlifetime *lt;
@@ -394,7 +399,7 @@ in6_control(struct socket *so, u_long cmd, caddr_t
 		if (td != NULL) {
 			error = priv_check(td, PRIV_NETINET_ALIFETIME6);
 			if (error)
-				return (error);
+				goto out;
 		}
 		if (ia == NULL)
 			return (EADDRNOTAVAIL);
@@ -402,34 +407,37 @@ in6_control(struct socket *so, u_long cmd, caddr_t
 		lt = &ifr->ifr_ifru.ifru_lifetime;
 		if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME &&
 		    lt->ia6t_vltime + time_second < time_second) {
-			return EINVAL;
+			error = EINVAL;
+			goto out;
 		}
 		if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME &&
 		    lt->ia6t_pltime + time_second < time_second) {
-			return EINVAL;
+			error = EINVAL;
+			goto out;
 		}
 		break;
 	    }
 	}
 
 	switch (cmd) {
-
 	case SIOCGIFADDR_IN6:
 		ifr->ifr_addr = ia->ia_addr;
 		if ((error = sa6_recoverscope(&ifr->ifr_addr)) != 0)
-			return (error);
+			goto out;
 		break;
 
 	case SIOCGIFDSTADDR_IN6:
-		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
-			return (EINVAL);
+		if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
+			error = EINVAL;
+			goto out;
+		}
 		/*
 		 * 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);
+			goto out;
 		break;
 
 	case SIOCGIFNETMASK_IN6:
@@ -441,8 +449,10 @@ in6_control(struct socket *so, u_long cmd, caddr_t
 		break;
 
 	case SIOCGIFSTAT_IN6:
-		if (ifp == NULL)
-			return EINVAL;
+		if (ifp == NULL) {
+			error = EINVAL;
+			goto out;
+		}
 		bzero(&ifr->ifr_ifru.ifru_stat,
 		    sizeof(ifr->ifr_ifru.ifru_stat));
 		ifr->ifr_ifru.ifru_stat =
@@ -450,8 +460,10 @@ in6_control(struct socket *so, u_long cmd, caddr_t
 		break;
 
 	case SIOCGIFSTAT_ICMP6:
-		if (ifp == NULL)
-			return EINVAL;
+		if (ifp == NULL) {
+			error = EINVAL;
+			goto out;
+		}
 		bzero(&ifr->ifr_ifru.ifru_icmp6stat,
 		    sizeof(ifr->ifr_ifru.ifru_icmp6stat));
 		ifr->ifr_ifru.ifru_icmp6stat =
@@ -515,7 +527,7 @@ in6_control(struct socket *so, u_long cmd, caddr_t
 
 	case SIOCAIFADDR_IN6:
 	{
-		int i, error = 0;
+		int i;
 		struct nd_prefixctl pr0;
 		struct nd_prefix *pr;
 
@@ -524,7 +536,9 @@ in6_control(struct socket *so, u_long cmd, caddr_t
 		 * and link it to the list.
 		 */
 		if ((error = in6_update_ifa(ifp, ifra, ia, 0)) != 0)
-			return (error);
+			goto out;
+		if (ia != NULL)
+			ifa_free(&ia->ia_ifa);
 		if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr))
 		    == NULL) {
 			/*
@@ -578,11 +592,12 @@ in6_control(struct socket *so, u_long cmd, caddr_t
 			 * interface route.
 			 */
 			if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0)
-				return (error);
+				goto out;
 			if (pr == NULL) {
 				log(LOG_ERR, "nd6_prelist_add succeeded but "
 				    "no prefix\n");
-				return (EINVAL); /* XXX panic here? */
+				error = EINVAL;
+				goto out;
 			}
 		}
 
@@ -640,12 +655,18 @@ in6_control(struct socket *so, u_long cmd, caddr_t
 	}
 
 	default:
-		if (ifp == NULL || ifp->if_ioctl == 0)
-			return (EOPNOTSUPP);
+		if (ifp == NULL || ifp->if_ioctl == 0) {
+			error = EOPNOTSUPP;
+			goto out;
+		}
 		return ((*ifp->if_ioctl)(ifp, cmd, data));
 	}
 
-	return (0);
+	error = 0;
+out:
+	if (ia != NULL)
+		ifa_free(&ia->ia_ifa);
+	return (error);
 }
 
 /*
@@ -1481,6 +1502,7 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, c
 		struct in6_addr *hostid = NULL;
 		int prefixlen;
 
+		ifa = NULL;
 		if ((iflr->flags & IFLR_PREFIX) != 0) {
 			struct sockaddr_in6 *sin6;
 
@@ -1532,6 +1554,8 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, c
 				    hostid->s6_addr32[3];
 			}
 		}
+		if (ifa != NULL)
+			ifa_free(ifa);
 
 		ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
 		in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen);
@@ -1779,6 +1803,7 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *i
 
 /*
  * Find an IPv6 interface link-local address specific to an interface.
+ * ifaddr is returned referenced.
  */
 struct in6_ifaddr *
 in6ifa_ifpforlinklocal(struct ifnet *ifp, int ignoreflags)
@@ -1796,6 +1821,8 @@ in6ifa_ifpforlinklocal(struct ifnet *ifp, int igno
 			break;
 		}
 	}
+	if (ifa != NULL)
+		ifa_ref(ifa);
 	IF_ADDR_UNLOCK(ifp);
 
 	return ((struct in6_ifaddr *)ifa);
@@ -1804,6 +1831,7 @@ in6ifa_ifpforlinklocal(struct ifnet *ifp, int igno
 
 /*
  * find the internet address corresponding to a given interface and address.
+ * ifaddr is returned referenced.
  */
 struct in6_ifaddr *
 in6ifa_ifpwithaddr(struct ifnet *ifp, struct in6_addr *addr)
@@ -1817,6 +1845,8 @@ in6ifa_ifpwithaddr(struct ifnet *ifp, struct in6_a
 		if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa)))
 			break;
 	}
+	if (ifa != NULL)
+		ifa_ref(ifa);
 	IF_ADDR_UNLOCK(ifp);
 
 	return ((struct in6_ifaddr *)ifa);
@@ -2049,6 +2079,7 @@ in6_ifawithifp(struct ifnet *ifp, struct in6_addr
 		}
 	}
 	if (besta) {
+		ifa_ref(&besta->ia_ifa);
 		IF_ADDR_UNLOCK(ifp);
 		return (besta);
 	}
@@ -2068,6 +2099,8 @@ in6_ifawithifp(struct ifnet *ifp, struct in6_addr
 			continue;
 		}
 
+		if (ifa != NULL)
+			ifa_ref(ifa);
 		IF_ADDR_UNLOCK(ifp);
 		return (struct in6_ifaddr *)ifa;
 	}
@@ -2319,6 +2352,7 @@ in6_lltable_rtcheck(struct ifnet *ifp, const struc
 		/* XXX ifaof_ifpforaddr should take a const param */
 		ifa = ifaof_ifpforaddr(__DECONST(struct sockaddr *, l3addr), ifp);
 		if (ifa != NULL) {
+			ifa_free(ifa);
 			if (rt != NULL)
 				RTFREE_LOCKED(rt);
 			return 0;
Index: netinet6/mld6.c
===================================================================
--- netinet6/mld6.c	(revision 194622)
+++ netinet6/mld6.c	(working copy)
@@ -1152,8 +1152,13 @@ mld_v1_input_report(struct ifnet *ifp, const struc
 	 */
 	ia = in6ifa_ifpforlinklocal(ifp, IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
 	if ((ia && IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, IA6_IN6(ia))) ||
-	    (ia == NULL && IN6_IS_ADDR_UNSPECIFIED(&src)))
+	    (ia == NULL && IN6_IS_ADDR_UNSPECIFIED(&src))) {
+		if (ia != NULL)
+			ifa_free(&ia->ia_ifa);
 		return (0);
+	}
+	if (ia != NULL)
+		ifa_free(&ia->ia_ifa);
 
 	CTR3(KTR_MLD, "process v1 report %s on ifp %p(%s)",
 	    ip6_sprintf(ip6tbuf, &mld->mld_addr), ifp, ifp->if_xname);
@@ -1796,11 +1801,16 @@ mld_v1_transmit_report(struct in6_multi *in6m, con
 	/* ia may be NULL if link-local address is tentative. */
 
 	MGETHDR(mh, M_DONTWAIT, MT_HEADER);
-	if (mh == NULL)
+	if (mh == NULL) {
+		if (ia != NULL)
+			ifa_free(&ia->ia_ifa);
 		return (ENOMEM);
+	}
 	MGET(md, M_DONTWAIT, MT_DATA);
 	if (md == NULL) {
 		m_free(mh);
+		if (ia != NULL)
+			ifa_free(&ia->ia_ifa);
 		return (ENOMEM);
 	}
 	mh->m_next = md;
@@ -1839,6 +1849,8 @@ mld_v1_transmit_report(struct in6_multi *in6m, con
 
 	mld_dispatch_packet(mh);
 
+	if (ia != NULL)
+		ifa_free(&ia->ia_ifa);
 	return (0);
 }
 
@@ -3136,6 +3148,8 @@ mld_v2_encap_report(struct ifnet *ifp, struct mbuf
 
 	MGETHDR(mh, M_DONTWAIT, MT_HEADER);
 	if (mh == NULL) {
+		if (ia != NULL)
+			ifa_free(&ia->ia_ifa);
 		m_freem(m);
 		return (NULL);
 	}
@@ -3154,6 +3168,8 @@ mld_v2_encap_report(struct ifnet *ifp, struct mbuf
 	ip6->ip6_vfc |= IPV6_VERSION;
 	ip6->ip6_nxt = IPPROTO_ICMPV6;
 	ip6->ip6_src = ia ? ia->ia_addr.sin6_addr : in6addr_any;
+	if (ia != NULL)
+		ifa_free(&ia->ia_ifa);
 	ip6->ip6_dst = in6addr_linklocal_allv2routers;
 	/* scope ID will be set in netisr */
 
@@ -3168,7 +3184,6 @@ mld_v2_encap_report(struct ifnet *ifp, struct mbuf
 	mh->m_next = m;
 	mld->mld_cksum = in6_cksum(mh, IPPROTO_ICMPV6,
 	    sizeof(struct ip6_hdr), sizeof(struct mldv2_report) + mldreclen);
-
 	return (mh);
 }
 
Index: netinet6/in6_src.c
===================================================================
--- netinet6/in6_src.c	(revision 194622)
+++ netinet6/in6_src.c	(working copy)
@@ -245,15 +245,26 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct
 		    (inp->inp_flags & IN6P_IPV6_V6ONLY) != 0))) != 0)
 			return (NULL);
 
-		ia6 = (struct in6_ifaddr *)ifa_ifwithaddr((struct sockaddr *)(&srcsock));
+		ia6 = (struct in6_ifaddr *)ifa_ifwithaddr(
+		    (struct sockaddr *)&srcsock);
 		if (ia6 == NULL ||
 		    (ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
+			if (ia6 != NULL)
+				ifa_free(&ia6->ia_ifa);
 			*errorp = EADDRNOTAVAIL;
 			return (NULL);
 		}
 		pi->ipi6_addr = srcsock.sin6_addr; /* XXX: this overrides pi */
 		if (ifpp)
 			*ifpp = ifp;
+
+		/*
+		 * XXXRW: This returns a pointer into a structure with no
+		 * refcount.  in6_selectsrc() should return it to caller-
+		 * provided memory using call-by-reference rather than
+		 * returning pointers into other memory.
+		 */
+		ifa_free(&ia6->ia_ifa);
 		return (&ia6->ia_addr.sin6_addr);
 	}
 
Index: netinet6/ip6_input.c
===================================================================
--- netinet6/ip6_input.c	(revision 194622)
+++ netinet6/ip6_input.c	(working copy)
@@ -724,6 +724,7 @@ passin:
 				 * to the upper layers.
 				 */
 			}
+			ifa_free(&ia6->ia_ifa);
 		}
 	}
 
Index: netinet6/nd6_rtr.c
===================================================================
--- netinet6/nd6_rtr.c	(revision 194622)
+++ netinet6/nd6_rtr.c	(working copy)
@@ -1307,6 +1307,7 @@ prelist_update(struct nd_prefixctl *new, struct nd
 					    e));
 				}
 			}
+			ifa_free(&ia6->ia_ifa);
 
 			/*
 			 * A newly added address might affect the status
@@ -1597,10 +1598,14 @@ nd6_prefix_onlink(struct nd_prefix *pr)
 	    IN6_IFF_NOTREADY | IN6_IFF_ANYCAST);
 	if (ifa == NULL) {
 		/* XXX: freebsd does not have ifa_ifwithaf */
+		IF_ADDR_LOCK(ifp);
 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
 			if (ifa->ifa_addr->sa_family == AF_INET6)
 				break;
 		}
+		if (ifa != NULL)
+			ifa_ref(ifa);
+		IF_ADDR_UNLOCK(ifp);
 		/* should we care about ia6_flags? */
 	}
 	if (ifa == NULL) {
@@ -1661,6 +1666,8 @@ nd6_prefix_onlink(struct nd_prefix *pr)
 		RT_REMREF(rt);
 		RT_UNLOCK(rt);
 	}
+	if (ifa != NULL)
+		ifa_free(ifa);
 
 	return (error);
 }
@@ -1802,6 +1809,7 @@ in6_ifadd(struct nd_prefixctl *pr, int mcast)
 	/* prefixlen + ifidlen must be equal to 128 */
 	plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL);
 	if (prefixlen != plen0) {
+		ifa_free(ifa);
 		nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s "
 		    "(prefix=%d ifid=%d)\n",
 		    if_name(ifp), prefixlen, 128 - plen0));
@@ -1834,6 +1842,7 @@ in6_ifadd(struct nd_prefixctl *pr, 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]);
+	ifa_free(ifa);
 
 	/* new prefix mask. */
 	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
@@ -1854,7 +1863,10 @@ in6_ifadd(struct nd_prefixctl *pr, 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.
 	 */
-	if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) {
+	ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp,
+	    &ifra.ifra_addr.sin6_addr);
+	if (ifa != NULL) {
+		ifa_free(ifa);
 		/* this should be rare enough to make an explicit log */
 		log(LOG_INFO, "in6_ifadd: %s is already configured\n",
 		    ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr));
@@ -1879,8 +1891,12 @@ in6_ifadd(struct nd_prefixctl *pr, int mcast)
 	}
 
 	ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
-
-	return (ia);		/* this is always non-NULL */
+	/*
+	 * XXXRW: Assumption of non-NULLness here might not be true with
+	 * fine-grained locking -- should we validate it?  Or just return
+	 * earlier ifa rather than looking it up again?
+	 */
+	return (ia);		/* this is always non-NULL  and referenced. */
 }
 
 /*
@@ -2000,6 +2016,7 @@ in6_tmpifadd(const struct in6_ifaddr *ia0, int for
 	}
 	newia->ia6_ndpr = ia0->ia6_ndpr;
 	newia->ia6_ndpr->ndpr_refcnt++;
+	ifa_free(&newia->ia_ifa);
 
 	/*
 	 * A newly added address might affect the status of other addresses.
Index: netinet6/in6_pcb.c
===================================================================
--- netinet6/in6_pcb.c	(revision 194622)
+++ netinet6/in6_pcb.c	(working copy)
@@ -162,10 +162,11 @@ in6_pcbbind(register struct inpcb *inp, struct soc
 			if (so->so_options & SO_REUSEADDR)
 				reuseport = SO_REUSEADDR|SO_REUSEPORT;
 		} else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
-			struct ifaddr *ia;
+			struct ifaddr *ifa;
 
 			sin6->sin6_port = 0;		/* yech... */
-			if ((ia = ifa_ifwithaddr((struct sockaddr *)sin6)) == NULL &&
+			if ((ifa = ifa_ifwithaddr((struct sockaddr *)sin6)) ==
+			    NULL &&
 			    (inp->inp_flags & INP_BINDANY) == 0) {
 				return (EADDRNOTAVAIL);
 			}
@@ -176,11 +177,14 @@ in6_pcbbind(register struct inpcb *inp, struct soc
 			 * We should allow to bind to a deprecated address, since
 			 * the application dares to use it.
 			 */
-			if (ia &&
-			    ((struct in6_ifaddr *)ia)->ia6_flags &
+			if (ifa != NULL &&
+			    ((struct in6_ifaddr *)ifa)->ia6_flags &
 			    (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED)) {
+				ifa_free(ifa);
 				return (EADDRNOTAVAIL);
 			}
+			if (ifa != NULL)
+				ifa_free(ifa);
 		}
 		if (lport) {
 			struct inpcb *t;
Index: contrib/rdma/rdma_cma.c
===================================================================
--- contrib/rdma/rdma_cma.c	(revision 194622)
+++ contrib/rdma/rdma_cma.c	(working copy)
@@ -1337,6 +1337,7 @@ static int iw_conn_req_handler(struct iw_cm_id *cm
 	}
 	dev = ifa->ifa_ifp;
 	ret = rdma_copy_addr(&conn_id->id.route.addr.dev_addr, dev, NULL);
+	ifa_free(ifa);
 	if (ret) {
 		cma_enable_remove(conn_id);
 		rdma_destroy_id(new_cm_id);
Index: contrib/rdma/rdma_addr.c
===================================================================
--- contrib/rdma/rdma_addr.c	(revision 194622)
+++ contrib/rdma/rdma_addr.c	(working copy)
@@ -129,13 +129,16 @@ int rdma_translate_ip(struct sockaddr *addr, struc
 	struct ifaddr *ifa;
 	struct sockaddr_in *sin = (struct sockaddr_in *)addr;
 	uint16_t port = sin->sin_port;
+	int ret;
 	
 	sin->sin_port = 0;
 	ifa = ifa_ifwithaddr(addr);
 	sin->sin_port = port;
 	if (!ifa)
 		return (EADDRNOTAVAIL);
-	return rdma_copy_addr(dev_addr, ifa->ifa_ifp, NULL);
+	ret = rdma_copy_addr(dev_addr, ifa->ifa_ifp, NULL);
+	ifa_free(ifa);
+	return (ret);
 }
 
 static void queue_req(struct addr_req *req)
