==== //depot/user/bms/nethead/sys/netinet/in.c#1 - /home/bms/fp4/nethead/sys/netinet/in.c ====
--- /tmp/tmp.23928.0	Sat Sep 23 18:32:59 2006
+++ /home/bms/fp4/nethead/sys/netinet/in.c	Sat Sep 23 17:37:13 2006
@@ -459,6 +459,11 @@
 		 * a routing process they will come back.
 		 */
 		in_ifadown(&ia->ia_ifa, 1);
+		/*
+		 * Mark the interface address as no longer valid.
+		 * Sockets that are bound to it should notice.
+		 */
+		ia->ia_ifa.ifa_flags |= RTF_REJECT;
 		EVENTHANDLER_INVOKE(ifaddr_event, ifp);
 		error = 0;
 		break;
==== //depot/user/bms/nethead/sys/netinet/in_pcb.c#1 - /home/bms/fp4/nethead/sys/netinet/in_pcb.c ====
--- /tmp/tmp.23928.1	Sat Sep 23 18:32:59 2006
+++ /home/bms/fp4/nethead/sys/netinet/in_pcb.c	Sat Sep 23 18:02:08 2006
@@ -238,14 +238,17 @@
 	anonport = inp->inp_lport == 0 && (nam == NULL ||
 	    ((struct sockaddr_in *)nam)->sin_port == 0);
 	error = in_pcbbind_setup(inp, nam, &inp->inp_laddr.s_addr,
-	    &inp->inp_lport, cred);
+	    &inp->inp_lport, &inp->inp_locia, cred);
 	if (error)
 		return (error);
 	if (in_pcbinshash(inp) != 0) {
 		inp->inp_laddr.s_addr = INADDR_ANY;
 		inp->inp_lport = 0;
+		inp->inp_locia = NULL;
 		return (EAGAIN);
 	}
+	if (inp->inp_locia != NULL)
+		IFAREF(&inp->inp_locia->ia_ifa);
 	if (anonport)
 		inp->inp_flags |= INP_ANONPORT;
 	return (0);
@@ -262,12 +265,13 @@
  */
 int
 in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp,
-    u_short *lportp, struct ucred *cred)
+    u_short *lportp, struct in_ifaddr **iap, struct ucred *cred)
 {
 	struct socket *so = inp->inp_socket;
 	unsigned short *lastport;
 	struct sockaddr_in *sin;
 	struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
+	struct in_ifaddr *ia = NULL;
 	struct in_addr laddr;
 	u_short lport = 0;
 	int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
@@ -319,7 +323,8 @@
 		} else if (sin->sin_addr.s_addr != INADDR_ANY) {
 			sin->sin_port = 0;		/* yech... */
 			bzero(&sin->sin_zero, sizeof(sin->sin_zero));
-			if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
+			if ((ia = (struct in_ifaddr *)ifa_ifwithaddr(
+			    (struct sockaddr *)sin)) == 0)
 				return (EADDRNOTAVAIL);
 		}
 		laddr = sin->sin_addr;
@@ -478,6 +483,8 @@
 		return (EINVAL);
 	*laddrp = laddr.s_addr;
 	*lportp = lport;
+	if (iap != NULL)
+		*iap = ia;
 	return (0);
 }
 
@@ -490,6 +497,7 @@
 int
 in_pcbconnect(struct inpcb *inp, struct sockaddr *nam, struct ucred *cred)
 {
+	struct in_ifaddr *locia;
 	u_short lport, fport;
 	in_addr_t laddr, faddr;
 	int anonport, error;
@@ -501,7 +509,7 @@
 	laddr = inp->inp_laddr.s_addr;
 	anonport = (lport == 0);
 	error = in_pcbconnect_setup(inp, nam, &laddr, &lport, &faddr, &fport,
-	    NULL, cred);
+	    NULL, &locia, cred);
 	if (error)
 		return (error);
 
@@ -519,6 +527,9 @@
 	/* Commit the remaining changes. */
 	inp->inp_lport = lport;
 	inp->inp_laddr.s_addr = laddr;
+	inp->inp_locia = locia;
+	if (inp->inp_locia != NULL)
+		IFAREF(&inp->inp_locia->ia_ifa);
 	inp->inp_faddr.s_addr = faddr;
 	inp->inp_fport = fport;
 	in_pcbrehash(inp);
@@ -536,7 +547,9 @@
  * On entry, *laddrp and *lportp should contain the current local
  * address and port for the PCB; these are updated to the values
  * that should be placed in inp_laddr and inp_lport to complete
- * the connect.
+ * the connect. If iap is not NULL, *iap is set to the interface
+ * address corresponding to *laddrp, if any, but no new reference
+ * to it has been added.
  *
  * On success, *faddrp and *fportp will be set to the remote address
  * and port. These are not updated in the error case.
@@ -549,7 +562,7 @@
 int
 in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam,
     in_addr_t *laddrp, u_short *lportp, in_addr_t *faddrp, u_short *fportp,
-    struct inpcb **oinpp, struct ucred *cred)
+    struct inpcb **oinpp, struct in_ifaddr **iap, struct ucred *cred)
 {
 	struct sockaddr_in *sin = (struct sockaddr_in *)nam;
 	struct in_ifaddr *ia;
@@ -560,6 +573,7 @@
 	u_short lport, fport;
 	int error;
 
+	ia = NULL;
 	INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
 	INP_LOCK_ASSERT(inp);
 
@@ -582,7 +596,7 @@
 		sa.sin_len = sizeof(sa);
 		sa.sin_family = AF_INET;
 		error = in_pcbbind_setup(inp, (struct sockaddr *)&sa,
-		    &laddr.s_addr, &lport, cred);
+		    &laddr.s_addr, &lport, &ia, cred);
 		if (error)
 			return (error);
 	}
@@ -664,7 +678,7 @@
 	}
 	if (lport == 0) {
 		error = in_pcbbind_setup(inp, NULL, &laddr.s_addr, &lport,
-		    cred);
+		    &ia, cred);
 		if (error)
 			return (error);
 	}
@@ -672,6 +686,8 @@
 	*lportp = lport;
 	*faddrp = faddr.s_addr;
 	*fportp = fport;
+	if (iap != NULL)
+		*iap = ia;
 	return (0);
 }
 
@@ -720,6 +736,8 @@
 #endif /*IPSEC*/
 	inp->inp_gencnt = ++ipi->ipi_gencnt;
 	in_pcbremlists(inp);
+	if (inp->inp_locia != NULL)
+		IFAFREE(&inp->inp_locia->ia_ifa);
 	if (inp->inp_options)
 		(void)m_free(inp->inp_options);
 	ip_freemoptions(inp->inp_moptions);
==== //depot/user/bms/nethead/sys/netinet/in_pcb.h#1 - /home/bms/fp4/nethead/sys/netinet/in_pcb.h ====
--- /tmp/tmp.23928.2	Sat Sep 23 18:32:59 2006
+++ /home/bms/fp4/nethead/sys/netinet/in_pcb.h	Sat Sep 23 17:46:41 2006
@@ -71,6 +71,7 @@
 struct in_endpoints {
 	u_int16_t	ie_fport;		/* foreign port */
 	u_int16_t	ie_lport;		/* local port */
+	struct in_ifaddr *ie_locia;		/* locally bound address */
 	/* protocol dependent part, local and foreign addr */
 	union {
 		/* foreign host table entry */
@@ -102,6 +103,7 @@
 #define inc_isipv6	inc_flags	/* temp compatability */
 #define	inc_fport	inc_ie.ie_fport
 #define	inc_lport	inc_ie.ie_lport
+#define	inc_locia	inc_ie.ie_locia
 #define	inc_faddr	inc_ie.ie_faddr
 #define	inc_laddr	inc_ie.ie_laddr
 #define	inc6_faddr	inc_ie.ie6_faddr
@@ -145,6 +147,7 @@
 	} inp_depend4;
 #define	inp_fport	inp_inc.inc_fport
 #define	inp_lport	inp_inc.inc_lport
+#define	inp_locia	inp_inc.inc_locia
 #define	inp_faddr	inp_inc.inc_faddr
 #define	inp_laddr	inp_inc.inc_laddr
 #define	inp_ip_tos	inp_depend4.inp4_ip_tos
@@ -332,6 +335,8 @@
 #define	INP_CHECK_SOCKAF(so, af)	(INP_SOCKAF(so) == af)
 
 #ifdef _KERNEL
+struct in_ifaddr;
+
 extern int	ipport_reservedhigh;
 extern int	ipport_reservedlow;
 extern int	ipport_lowfirstauto;
@@ -346,11 +351,11 @@
 int	in_pcballoc(struct socket *, struct inpcbinfo *);
 int	in_pcbbind(struct inpcb *, struct sockaddr *, struct ucred *);
 int	in_pcbbind_setup(struct inpcb *, struct sockaddr *, in_addr_t *,
-	    u_short *, struct ucred *);
+	    u_short *, struct in_ifaddr **, struct ucred *);
 int	in_pcbconnect(struct inpcb *, struct sockaddr *, struct ucred *);
 int	in_pcbconnect_setup(struct inpcb *, struct sockaddr *, in_addr_t *,
 	    u_short *, in_addr_t *, u_short *, struct inpcb **,
-	    struct ucred *);
+	    struct in_ifaddr **, struct ucred *);
 void	in_pcbdetach(struct inpcb *);
 void	in_pcbdisconnect(struct inpcb *);
 void	in_pcbdrop(struct inpcb *);
==== //depot/user/bms/nethead/sys/netinet/tcp_output.c#1 - /home/bms/fp4/nethead/sys/netinet/tcp_output.c ====
--- /tmp/tmp.23928.3	Sat Sep 23 18:32:59 2006
+++ /home/bms/fp4/nethead/sys/netinet/tcp_output.c	Sat Sep 23 17:47:35 2006
@@ -51,12 +51,15 @@
 #include <sys/sysctl.h>
 
 #include <net/route.h>
+#include <net/if.h>
+#include <net/if_var.h>
 
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
 #include <netinet/in_pcb.h>
 #include <netinet/ip_var.h>
+#include <netinet/in_var.h>
 #include <netinet/ip_options.h>
 #ifdef INET6
 #include <netinet6/in6_pcb.h>
@@ -872,6 +875,16 @@
 		ipov = (struct ipovly *)ip;
 		th = (struct tcphdr *)(ip + 1);
 		tcpip_fillheaders(tp->t_inpcb, ip, th);
+	}
+
+	/*
+	 * Check that our local (source) IP address is still valid.
+	 */
+	if (tp->t_inpcb->inp_locia != NULL
+	    && (tp->t_inpcb->inp_locia->ia_ifa.ifa_flags & RTF_REJECT) != 0) {
+		error = EADDRNOTAVAIL;
+		m_freem(m);
+		goto out;
 	}
 
 	/*
==== //depot/user/bms/nethead/sys/netinet/tcp_usrreq.c#1 - /home/bms/fp4/nethead/sys/netinet/tcp_usrreq.c ====
--- /tmp/tmp.23928.4	Sat Sep 23 18:33:00 2006
+++ /home/bms/fp4/nethead/sys/netinet/tcp_usrreq.c	Sat Sep 23 17:53:09 2006
@@ -1102,6 +1102,7 @@
 {
 	struct inpcb *inp = tp->t_inpcb, *oinp;
 	struct socket *so = inp->inp_socket;
+	struct in_ifaddr *locia;
 	struct in_addr laddr;
 	u_short lport;
 	int error;
@@ -1122,13 +1123,20 @@
 	 */
 	laddr = inp->inp_laddr;
 	lport = inp->inp_lport;
+	locia = inp->inp_locia;
 	error = in_pcbconnect_setup(inp, nam, &laddr.s_addr, &lport,
-	    &inp->inp_faddr.s_addr, &inp->inp_fport, &oinp, td->td_ucred);
+	    &inp->inp_faddr.s_addr, &inp->inp_fport, &oinp, &locia,
+	    td->td_ucred);
 	if (error && oinp == NULL)
 		return error;
 	if (oinp)
 		return EADDRINUSE;
 	inp->inp_laddr = laddr;
+	if (inp->inp_locia != NULL)
+		IFAFREE(&inp->inp_locia->ia_ifa);
+	inp->inp_locia = locia;
+	if (inp->inp_locia != NULL)
+		IFAREF(&inp->inp_locia->ia_ifa);
 	in_pcbrehash(inp);
 
 	/* Compute window scaling to request.  */
==== //depot/user/bms/nethead/sys/netinet/udp_usrreq.c#1 - /home/bms/fp4/nethead/sys/netinet/udp_usrreq.c ====
--- /tmp/tmp.23928.5	Sat Sep 23 18:33:00 2006
+++ /home/bms/fp4/nethead/sys/netinet/udp_usrreq.c	Sat Sep 23 17:51:24 2006
@@ -724,6 +724,7 @@
 {
 	register struct udpiphdr *ui;
 	register int len = m->m_pkthdr.len;
+	struct in_ifaddr *locia;
 	struct in_addr faddr, laddr;
 	struct cmsghdr *cm;
 	struct sockaddr_in *sin, src;
@@ -809,13 +810,14 @@
 
 	laddr = inp->inp_laddr;
 	lport = inp->inp_lport;
+	locia = inp->inp_locia;
 	if (src.sin_addr.s_addr != INADDR_ANY) {
 		if (lport == 0) {
 			error = EINVAL;
 			goto release;
 		}
 		error = in_pcbbind_setup(inp, (struct sockaddr *)&src,
-		    &laddr.s_addr, &lport, td->td_ucred);
+		    &laddr.s_addr, &lport, &locia, td->td_ucred);
 		if (error)
 			goto release;
 	}
@@ -829,7 +831,7 @@
 			goto release;
 		}
 		error = in_pcbconnect_setup(inp, addr, &laddr.s_addr, &lport,
-		    &faddr.s_addr, &fport, NULL, td->td_ucred);
+		    &faddr.s_addr, &fport, NULL, &locia, td->td_ucred);
 		if (error)
 			goto release;
 
@@ -859,6 +861,14 @@
 	}
 
 	/*
+	 * Check that the local (source) IP address is valid.
+	 */
+	if (locia != NULL && (locia->ia_ifa.ifa_flags & RTF_REJECT) != 0) {
+		error = EADDRNOTAVAIL;
+		goto release;
+	}
+
+	/*
 	 * Calculate data length and get a mbuf for UDP, IP, and possible
 	 * link-layer headers.  Immediate slide the data pointer back forward
 	 * since we won't use that space at this layer.
@@ -1088,6 +1098,10 @@
 
 	in_pcbdisconnect(inp);
 	inp->inp_laddr.s_addr = INADDR_ANY;
+	if (inp->inp_locia != NULL) {
+		IFAFREE(&inp->inp_locia->ia_ifa);
+		inp->inp_locia = NULL;
+	}
 	SOCK_LOCK(so);
 	so->so_state &= ~SS_ISCONNECTED;		/* XXX */
 	SOCK_UNLOCK(so);