From nobody@www.freebsd.org  Sat May 25 12:23:41 2002
Return-Path: <nobody@www.freebsd.org>
Received: from nwww.freebsd.org (www.FreeBSD.org [216.136.204.117])
	by hub.freebsd.org (Postfix) with ESMTP id 424D037B406
	for <freebsd-gnats-submit@FreeBSD.org>; Sat, 25 May 2002 12:23:41 -0700 (PDT)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by nwww.freebsd.org (8.12.2/8.12.2) with ESMTP id g4PJNehG054303
	for <freebsd-gnats-submit@FreeBSD.org>; Sat, 25 May 2002 12:23:40 -0700 (PDT)
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.12.2/8.12.2/Submit) id g4PJNeOM054302;
	Sat, 25 May 2002 12:23:40 -0700 (PDT)
Message-Id: <200205251923.g4PJNeOM054302@www.freebsd.org>
Date: Sat, 25 May 2002 12:23:40 -0700 (PDT)
From: Guido Laubner <Guido.Laubner@gmx.de>
To: freebsd-gnats-submit@FreeBSD.org
Subject: changing interface ipaddress doesn't seem to work
X-Send-Pr-Version: www-1.0

>Number:         38554
>Category:       kern
>Synopsis:       [patch] changing interface ipaddress doesn't seem to work
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-net
>State:          analyzed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat May 25 12:30:02 PDT 2002
>Closed-Date:    
>Last-Modified:  Tue Jul 15 05:21:14 UTC 2008
>Originator:     Guido Laubner
>Release:        4.0-RELEASE
>Organization:
>Environment:
FreeBSD gatekeeper.die-insel.germany.net 4.0-RELEASE #2: Sun Mar 11 23:42:23 MET 2001     guido@gatekeeper.die-insel.germany.net:/usr/src/sys/compile/GATEKEEPER i386
>Description:
When I change the IP address of an interface the system continues
to use the old address. Ifconfig does display the new address though.
I've changed the IP address multiple times and the systems seem to love
the very first address for that interface, which was set on boot
time. I do have another system (same version, different HW aparat from
networking interface) which shows the same problem.
>How-To-Repeat:
In a window do this:
prompt# more /tmp/bla
*.* @192.168.0.88
prompt# ifconfig -a
rl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        inet 192.168.1.1 netmask 0xffffff00 broadcast 192.168.1.255
        ether 00:30:84:3a:26:16 
        media: autoselect (100baseTX <full-duplex>) status: active
        supported media: autoselect 100baseTX <full-duplex> 100baseTX 10baseT/UTP <full-duplex> 10baseT/UTP 100baseTX <hw-loopback>
ep0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1492
        inet 192.168.0.1 netmask 0xffffff00 broadcast 192.168.0.255
        ether 00:a0:24:56:f7:e0 
        media: 10baseT/UTP
        supported media: 10base2/BNC 10baseT/UTP 10base5/AUI
sl0: flags=c010<POINTOPOINT,LINK2,MULTICAST> mtu 552
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
        inet 127.0.0.1 netmask 0xff000000 
prompt#   < kill syslogd now >
prompt# syslogd -f /tmp/bla
prompt# tcpdump -n -i ep0
tcpdump: listening on ep0
20:45:49.015965 arp who-has 192.168.0.88 tell 192.168.0.1
20:45:56.968093 arp who-has 192.168.0.44 tell 192.168.0.44
20:48:33.186548 arp who-has 192.168.0.88 tell 192.168.0.1

In other window (on same machine!)
20:45:49# logger test
20:45:56# ifconfig ep0 192.168.0.44
20.48:33# logger test

Watch when the machine arps for it's new ip. The next "logger" doesn't cause a new arp request for the syslog server with the _NEW_ ip, but with the old ip ! It doesn't change when it stop the syslogd and start a new one after changing the ip. 
>Fix:
Sorry...
>Release-Note:
>Audit-Trail:

From: David Malone <dwmalone@maths.tcd.ie>
To: Guido Laubner <Guido.Laubner@gmx.de>
Cc: freebsd-gnats-submit@FreeBSD.org
Subject: Re: kern/38554: changing interface ipaddress doesn't seem to work
Date: Tue, 2 Jul 2002 08:26:55 +0100

 On Sat, May 25, 2002 at 12:23:40PM -0700, Guido Laubner wrote:
 > >Description:
 > When I change the IP address of an interface the system continues
 > to use the old address. Ifconfig does display the new address though.
 
 Have you deleted the old address? You should be able to do it with
 a command like:
 
 	ifconfig inet 192.168.1.1 delete
 
 David.

From: Archie Cobbs <archie@packetdesign.com>
To: freebsd-gnats-submit@FreeBSD.org, Guido.Laubner@gmx.de
Cc:  
Subject: Re: kern/38554: changing interface ipaddress doesn't seem to work
Date: Mon, 11 Nov 2002 17:49:36 -0800

 I've verified that this bug still exists in 4.7-RELEASE. I made sure
 to delete the old address (replacing it) rather than just adding the
 new one.
 
 What happens is that if you have a connected socket, then change the
 interface IP address, packets transmitted as a result of writing to the
 socket still use the old original IP address. This is "logical" because
 the socket is once and for all time bound to its original source IP
 address. Of course, any reply packets coming back from the remote host
 are dropped as they have an unrecognized destination IP address.
 
 My test used a TCP socket (ssh connection) but I'm sure that UDP would
 do the same thing as well. Interestingly, when you change the IP address
 back to its original value the socket comes back alive.
 
 Obviously it would be wrong to force outgoing packets use the new address,
 so probably the right thing to do here is return ENETDOWN to the write(2)
 (or whaveter) system call that prompted the outgoing data.
 
 -Archie
 
 __________________________________________________________________________
 Archie Cobbs     *     Packet Design     *     http://www.packetdesign.com
 

From: Archie Cobbs <archie@packetdesign.com>
To: freebsd-gnats-submit@FreeBSD.org, Guido.Laubner@gmx.de
Cc:  
Subject: Re: kern/38554: changing interface ipaddress doesn't seem to work
Date: Thu, 21 Nov 2002 17:49:40 -0800 (PST)

 Here's a patch to -current that seems to fix the problem.
 I chose EADDRNOTAVAIL as the error code because:
 
 (a) The phrase "Can't assign requested address" seems most appropriate
 (b) It's consistent with what happens when you try to use an IP address
     that never existed in the first place, e.g., with IP_SENDSRCADDR.
 (c) You don't normally get this error from a send/write, which is
     when you'll get it
 
 -Archie
 
 __________________________________________________________________________
 Archie Cobbs     *     Packet Design     *     http://www.packetdesign.com
 
 Index: sys/netinet/in.c
 ===================================================================
 RCS file: /home/cvs/freebsd/src/sys/netinet/in.c,v
 retrieving revision 1.67
 diff -u -r1.67 in.c
 --- sys/netinet/in.c	22 Oct 2002 22:50:38 -0000	1.67
 +++ sys/netinet/in.c	22 Nov 2002 01:27:58 -0000
 @@ -422,6 +422,11 @@
  		 */
  		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;
 +		/*
  		 * XXX horrible hack to detect that we are being called
  		 * from if_detach()
  		 */
 Index: sys/netinet/in_pcb.c
 ===================================================================
 RCS file: /home/cvs/freebsd/src/sys/netinet/in_pcb.c,v
 retrieving revision 1.114
 diff -u -r1.114 in_pcb.c
 --- sys/netinet/in_pcb.c	8 Nov 2002 23:50:32 -0000	1.114
 +++ sys/netinet/in_pcb.c	22 Nov 2002 01:27:58 -0000
 @@ -57,6 +57,7 @@
  #include <net/if.h>
  #include <net/if_types.h>
  #include <net/route.h>
 +#include <net/net_osdep.h>
  
  #include <netinet/in.h>
  #include <netinet/in_pcb.h>
 @@ -199,14 +200,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, td);
 +	    &inp->inp_lport, &inp->inp_locia, td);
  	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);
 @@ -215,24 +219,29 @@
  /*
   * Set up a bind operation on a PCB, performing port allocation
   * as required, but do not actually modify the PCB. Callers can
 - * either complete the bind by setting inp_laddr/inp_lport and
 - * calling in_pcbinshash(), or they can just use the resulting
 + * either complete the bind by setting inp_laddr/inp_lport/inp_locia
 + * and calling in_pcbinshash(), or they can just use the resulting
   * port and address to authorise the sending of a once-off packet.
   *
 - * On error, the values of *laddrp and *lportp are not changed.
 + * 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 error, the values of *laddrp, *lportp, and *iap are not changed.
   */
  int
 -in_pcbbind_setup(inp, nam, laddrp, lportp, td)
 +in_pcbbind_setup(inp, nam, laddrp, lportp, iap, td)
  	struct inpcb *inp;
  	struct sockaddr *nam;
  	in_addr_t *laddrp;
  	u_short *lportp;
 +	struct in_ifaddr **iap;
  	struct thread *td;
  {
  	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);
 @@ -280,7 +289,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;
 @@ -403,6 +413,8 @@
  		return (EINVAL);
  	*laddrp = laddr.s_addr;
  	*lportp = lport;
 +	if (iap != NULL)
 +		*iap = ia;
  	return (0);
  }
  
 @@ -420,13 +432,14 @@
  {
  	u_short lport, fport;
  	in_addr_t laddr, faddr;
 +	struct in_ifaddr *locia;
  	int anonport, error;
  
  	lport = inp->inp_lport;
  	laddr = inp->inp_laddr.s_addr;
  	anonport = (lport == 0);
  	error = in_pcbconnect_setup(inp, nam, &laddr, &lport, &faddr, &fport,
 -	    NULL, td);
 +	    NULL, &locia, td);
  	if (error)
  		return (error);
  
 @@ -444,6 +457,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);
 @@ -457,7 +473,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.
 @@ -468,7 +486,7 @@
   * is set to NULL.
   */
  int
 -in_pcbconnect_setup(inp, nam, laddrp, lportp, faddrp, fportp, oinpp, td)
 +in_pcbconnect_setup(inp, nam, laddrp, lportp, faddrp, fportp, oinpp, iap, td)
  	register struct inpcb *inp;
  	struct sockaddr *nam;
  	in_addr_t *laddrp;
 @@ -476,10 +494,11 @@
  	in_addr_t *faddrp;
  	u_short *fportp;
  	struct inpcb **oinpp;
 +	struct in_ifaddr **iap;
  	struct thread *td;
  {
  	struct sockaddr_in *sin = (struct sockaddr_in *)nam;
 -	struct in_ifaddr *ia;
 +	struct in_ifaddr *ia = NULL;
  	struct sockaddr_in sa;
  	struct ucred *cred;
  	struct inpcb *oinp;
 @@ -506,7 +525,7 @@
  		sa.sin_len = sizeof(sa);
  		sa.sin_family = AF_INET;
  		error = in_pcbbind_setup(inp, (struct sockaddr *)&sa,
 -		    &laddr.s_addr, &lport, td);
 +		    &laddr.s_addr, &lport, &ia, td);
  		if (error)
  			return (error);
  	}
 @@ -608,7 +627,8 @@
  		return (EADDRINUSE);
  	}
  	if (lport == 0) {
 -		error = in_pcbbind_setup(inp, NULL, &laddr.s_addr, &lport, td);
 +		error = in_pcbbind_setup(inp, NULL, &laddr.s_addr, &lport,
 +		    &ia, td);
  		if (error)
  			return (error);
  	}
 @@ -616,6 +636,8 @@
  	*lportp = lport;
  	*faddrp = faddr.s_addr;
  	*fportp = fport;
 +	if (iap != NULL)
 +		*iap = ia;
  	return (0);
  }
  
 @@ -649,6 +671,8 @@
  		(void)m_free(inp->inp_options);
  	if (inp->inp_route.ro_rt)
  		rtfree(inp->inp_route.ro_rt);
 +	if (inp->inp_locia != NULL)
 +		IFAFREE(&inp->inp_locia->ia_ifa);
  	ip_freemoptions(inp->inp_moptions);
  	inp->inp_vflag = 0;
  	INP_LOCK_DESTROY(inp);
 Index: sys/netinet/in_pcb.h
 ===================================================================
 RCS file: /home/cvs/freebsd/src/sys/netinet/in_pcb.h,v
 retrieving revision 1.57
 diff -u -r1.57 in_pcb.h
 --- sys/netinet/in_pcb.h	12 Nov 2002 20:44:38 -0000	1.57
 +++ sys/netinet/in_pcb.h	22 Nov 2002 01:27:58 -0000
 @@ -75,6 +75,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 */
 @@ -113,6 +114,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	inc_route	inc_dependroute.inc4_route
 @@ -151,6 +153,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_route	inp_inc.inc_route
 @@ -315,6 +318,8 @@
  #define	INP_CHECK_SOCKAF(so, af) 	(INP_SOCKAF(so) == af)
  
  #ifdef _KERNEL
 +struct in_ifaddr;
 +
  extern int	ipport_lowfirstauto;
  extern int	ipport_lowlastauto;
  extern int	ipport_firstauto;
 @@ -329,11 +334,11 @@
  int	in_pcballoc(struct socket *, struct inpcbinfo *, struct thread *);
  int	in_pcbbind(struct inpcb *, struct sockaddr *, struct thread *);
  int	in_pcbbind_setup(struct inpcb *, struct sockaddr *, in_addr_t *,
 -	    u_short *, struct thread *);
 +	    u_short *, struct in_ifaddr **, struct thread *);
  int	in_pcbconnect(struct inpcb *, struct sockaddr *, struct thread *);
  int	in_pcbconnect_setup(struct inpcb *, struct sockaddr *, in_addr_t *,
  	    u_short *, in_addr_t *, u_short *, struct inpcb **,
 -	    struct thread *);
 +	    struct in_ifaddr **, struct thread *);
  void	in_pcbdetach(struct inpcb *);
  void	in_pcbdisconnect(struct inpcb *);
  int	in_pcbinshash(struct inpcb *);
 Index: sys/netinet/tcp_output.c
 ===================================================================
 RCS file: /home/cvs/freebsd/src/sys/netinet/tcp_output.c,v
 retrieving revision 1.73
 diff -u -r1.73 tcp_output.c
 --- sys/netinet/tcp_output.c	16 Oct 2002 19:16:33 -0000	1.73
 +++ sys/netinet/tcp_output.c	22 Nov 2002 01:27:58 -0000
 @@ -53,12 +53,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>
  #ifdef INET6
  #include <netinet6/in6_pcb.h>
  #include <netinet/ip6.h>
 @@ -686,6 +689,16 @@
  	/* this picks up the pseudo header (w/o the length) */
  	tcp_fillheaders(tp, 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;
 +	}
  
  	/*
  	 * Fill in fields, remembering maximum advertised
 Index: sys/netinet/tcp_usrreq.c
 ===================================================================
 RCS file: /home/cvs/freebsd/src/sys/netinet/tcp_usrreq.c,v
 retrieving revision 1.84
 diff -u -r1.84 tcp_usrreq.c
 --- sys/netinet/tcp_usrreq.c	24 Oct 2002 02:02:34 -0000	1.84
 +++ sys/netinet/tcp_usrreq.c	22 Nov 2002 01:27:58 -0000
 @@ -54,6 +54,7 @@
  #include <sys/jail.h>
  
  #include <net/if.h>
 +#include <net/net_osdep.h>
  #include <net/route.h>
  
  #include <netinet/in.h>
 @@ -849,6 +850,7 @@
  	struct socket *so = inp->inp_socket;
  	struct tcpcb *otp;
  	struct rmxp_tao *taop;
 +	struct in_ifaddr *locia;
  	struct rmxp_tao tao_noncached;
  	struct in_addr laddr;
  	u_short lport;
 @@ -867,8 +869,9 @@
  	 */
  	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);
 +	    &inp->inp_faddr.s_addr, &inp->inp_fport, &oinp, &locia, td);
  	if (error && oinp == NULL)
  		return error;
  	if (oinp) {
 @@ -883,6 +886,11 @@
  			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.  */
 Index: sys/netinet/udp_usrreq.c
 ===================================================================
 RCS file: /home/cvs/freebsd/src/sys/netinet/udp_usrreq.c,v
 retrieving revision 1.130
 diff -u -r1.130 udp_usrreq.c
 --- sys/netinet/udp_usrreq.c	20 Nov 2002 19:00:54 -0000	1.130
 +++ sys/netinet/udp_usrreq.c	22 Nov 2002 01:27:58 -0000
 @@ -688,6 +688,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;
 @@ -754,13 +755,14 @@
  		goto release;
  	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);
 +		    &laddr.s_addr, &lport, &locia, td);
  		if (error)
  			goto release;
  	}
 @@ -774,7 +776,7 @@
  			goto release;
  		}
  		error = in_pcbconnect_setup(inp, addr, &laddr.s_addr, &lport,
 -		    &faddr.s_addr, &fport, NULL, td);
 +		    &faddr.s_addr, &fport, NULL, &locia, td);
  		if (error)
  			goto release;
  
 @@ -797,6 +799,15 @@
  			goto release;
  		}
  	}
 +
 +	/*
 +	 * 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 and IP headers.
 @@ -1009,6 +1020,10 @@
  	s = splnet();
  	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;
 +	}
  	INP_UNLOCK(inp);
  	INP_INFO_WUNLOCK(&udbinfo);
  	splx(s);
Responsible-Changed-From-To: freebsd-bugs->bms 
Responsible-Changed-By: bms 
Responsible-Changed-When: Fri Jun 18 03:58:21 GMT 2004 
Responsible-Changed-Why:  
I'll try to look at this 

http://www.freebsd.org/cgi/query-pr.cgi?pr=38554 
State-Changed-From-To: open->analyzed 
State-Changed-By: bms 
State-Changed-When: Sat Jul 3 08:03:47 GMT 2004 
State-Changed-Why:  
I've rejigged Archie's patch for -CURRENT and applied it locally. 
It seems to work well (tested with ntp, syslogd, and Quagga bgpd 
sessions). I'm inclined to commit but wish to follow-up on -net first. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=38554 

From: Bruce M Simpson <bms@spc.org>
To: freebsd-net@freebsd.org
Cc: freebsd-gnats-submit@freebsd.org
Subject: Re: kern/38554: changing interface ipaddress doesn't seem to work
Date: Sat, 3 Jul 2004 09:09:00 +0100

 --jQIvE3yXcK9X9HBh
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 
 Please review the attached patch (which is a reworking of Archie's
 patch for -CURRENT). When the underlying IP address is changed,
 wildcard-bound UDP sockets which are temporarily bound locally for
 a sendto() (by userland apps such as ntp, syslogd etc) will begin
 using the new IP address, whilst apps using TCP (ssh, Quagga bgpd) will
 error out with EADDRINUSE.
 
 I would appreciate any feedback on our adopting this behaviour (which
 strikes me as similar to that of Solaris and a few other OSes).
 
 BMS
 
 --jQIvE3yXcK9X9HBh
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: attachment; filename="archie-current.diff"
 
 Index: in.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/netinet/in.c,v
 retrieving revision 1.75
 diff -u -p -r1.75 in.c
 --- in.c	7 Apr 2004 20:46:13 -0000	1.75
 +++ in.c	3 Jul 2004 07:40:19 -0000
 @@ -420,6 +420,11 @@ in_control(so, cmd, data, ifp, td)
  		 */
  		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;
 +		/*
  		 * XXX horrible hack to detect that we are being called
  		 * from if_detach()
  		 */
 Index: in_pcb.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/netinet/in_pcb.c,v
 retrieving revision 1.150
 diff -u -p -r1.150 in_pcb.c
 --- in_pcb.c	16 Jun 2004 10:02:36 -0000	1.150
 +++ in_pcb.c	3 Jul 2004 07:47:54 -0000
 @@ -53,6 +53,7 @@
  #include <net/if.h>
  #include <net/if_types.h>
  #include <net/route.h>
 +#include <net/net_osdep.h>
  
  #include <netinet/in.h>
  #include <netinet/in_pcb.h>
 @@ -228,14 +229,17 @@ in_pcbbind(inp, nam, cred)
  	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);
 @@ -251,17 +255,19 @@ in_pcbbind(inp, nam, cred)
   * On error, the values of *laddrp and *lportp are not changed.
   */
  int
 -in_pcbbind_setup(inp, nam, laddrp, lportp, cred)
 +in_pcbbind_setup(inp, nam, laddrp, lportp, iap, cred)
  	struct inpcb *inp;
  	struct sockaddr *nam;
  	in_addr_t *laddrp;
  	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);
 @@ -312,7 +318,8 @@ in_pcbbind_setup(inp, nam, laddrp, lport
  		} 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;
 @@ -451,6 +458,8 @@ in_pcbbind_setup(inp, nam, laddrp, lport
  		return (EINVAL);
  	*laddrp = laddr.s_addr;
  	*lportp = lport;
 +	if (iap != NULL)
 +		*iap = ia;
  	return (0);
  }
  
 @@ -468,13 +477,14 @@ in_pcbconnect(inp, nam, cred)
  {
  	u_short lport, fport;
  	in_addr_t laddr, faddr;
 +	struct in_ifaddr *locia;
  	int anonport, error;
  
  	lport = inp->inp_lport;
  	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);
  
 @@ -492,6 +502,9 @@ in_pcbconnect(inp, nam, cred)
  	/* 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);
 @@ -509,7 +522,9 @@ in_pcbconnect(inp, nam, cred)
   * 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.
 @@ -520,7 +535,7 @@ in_pcbconnect(inp, nam, cred)
   * is set to NULL.
   */
  int
 -in_pcbconnect_setup(inp, nam, laddrp, lportp, faddrp, fportp, oinpp, cred)
 +in_pcbconnect_setup(inp, nam, laddrp, lportp, faddrp, fportp, oinpp, iap, cred)
  	register struct inpcb *inp;
  	struct sockaddr *nam;
  	in_addr_t *laddrp;
 @@ -528,10 +543,11 @@ in_pcbconnect_setup(inp, nam, laddrp, lp
  	in_addr_t *faddrp;
  	u_short *fportp;
  	struct inpcb **oinpp;
 +	struct in_ifaddr **iap;
  	struct ucred *cred;
  {
  	struct sockaddr_in *sin = (struct sockaddr_in *)nam;
 -	struct in_ifaddr *ia;
 +	struct in_ifaddr *ia = NULL;
  	struct sockaddr_in sa;
  	struct ucred *socred;
  	struct inpcb *oinp;
 @@ -558,7 +574,7 @@ in_pcbconnect_setup(inp, nam, laddrp, lp
  		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);
  	}
 @@ -648,7 +664,7 @@ in_pcbconnect_setup(inp, nam, laddrp, lp
  	}
  	if (lport == 0) {
  		error = in_pcbbind_setup(inp, NULL, &laddr.s_addr, &lport,
 -		    cred);
 +		    &ia, cred);
  		if (error)
  			return (error);
  	}
 @@ -656,6 +672,8 @@ in_pcbconnect_setup(inp, nam, laddrp, lp
  	*lportp = lport;
  	*faddrp = faddr.s_addr;
  	*fportp = fport;
 +	if (iap != NULL)
 +		*iap = ia;
  	return (0);
  }
  
 @@ -694,6 +712,8 @@ in_pcbdetach(inp)
  		so->so_pcb = 0;
  		sotryfree(so);
  	}
 +	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);
 Index: in_pcb.h
 ===================================================================
 RCS file: /home/ncvs/src/sys/netinet/in_pcb.h,v
 retrieving revision 1.73
 diff -u -p -r1.73 in_pcb.h
 --- in_pcb.h	24 Jun 2004 02:01:48 -0000	1.73
 +++ in_pcb.h	3 Jul 2004 07:49:32 -0000
 @@ -71,6 +71,7 @@ struct in_addr_4in6 {
  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 @@ struct in_conninfo {
  #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
 @@ -142,6 +144,7 @@ struct inpcb {
  	} 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
 @@ -340,6 +343,8 @@ struct inpcbinfo {		/* XXX documentation
  #define	INP_CHECK_SOCKAF(so, af) 	(INP_SOCKAF(so) == af)
  
  #ifdef _KERNEL
 +struct in_ifaddr;
 +
  extern int	ipport_lowfirstauto;
  extern int	ipport_lowlastauto;
  extern int	ipport_firstauto;
 @@ -351,11 +356,11 @@ void	in_pcbpurgeif0(struct inpcbinfo *, 
  int	in_pcballoc(struct socket *, struct inpcbinfo *, const char *);
  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 *);
  int	in_pcbinshash(struct inpcb *);
 Index: tcp_output.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/netinet/tcp_output.c,v
 retrieving revision 1.95
 diff -u -p -r1.95 tcp_output.c
 --- tcp_output.c	23 Jun 2004 21:04:37 -0000	1.95
 +++ tcp_output.c	3 Jul 2004 07:40:19 -0000
 @@ -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>
  #ifdef INET6
  #include <netinet6/in6_pcb.h>
  #include <netinet/ip6.h>
 @@ -804,6 +807,16 @@ send:
        }
  
  	/*
 +	 * 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;
 +	}
 +
 +	/*
  	 * Fill in fields, remembering maximum advertised
  	 * window for use in delaying messages about window sizes.
  	 * If resending a FIN, be sure not to use a new sequence number.
 Index: tcp_usrreq.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/netinet/tcp_usrreq.c,v
 retrieving revision 1.103
 diff -u -p -r1.103 tcp_usrreq.c
 --- tcp_usrreq.c	26 Jun 2004 17:50:50 -0000	1.103
 +++ tcp_usrreq.c	3 Jul 2004 07:51:41 -0000
 @@ -51,6 +51,7 @@
  #include <sys/jail.h>
  
  #include <net/if.h>
 +#include <net/net_osdep.h>
  #include <net/route.h>
  
  #include <netinet/in.h>
 @@ -817,6 +818,7 @@ tcp_connect(tp, nam, td)
  	struct socket *so = inp->inp_socket;
  	struct tcptw *otw;
  	struct rmxp_tao tao;
 +	struct in_ifaddr *locia;
  	struct in_addr laddr;
  	u_short lport;
  	int error;
 @@ -836,8 +838,10 @@ tcp_connect(tp, nam, td)
  	 */
  	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) {
 @@ -852,6 +856,11 @@ tcp_connect(tp, nam, td)
  			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.  */
 Index: udp_usrreq.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/netinet/udp_usrreq.c,v
 retrieving revision 1.156
 diff -u -p -r1.156 udp_usrreq.c
 --- udp_usrreq.c	26 Jun 2004 19:10:39 -0000	1.156
 +++ udp_usrreq.c	3 Jul 2004 07:52:53 -0000
 @@ -724,6 +724,7 @@ udp_output(inp, m, addr, control, td)
  {
  	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;
 @@ -792,13 +793,14 @@ udp_output(inp, m, addr, control, td)
  		goto release;
  	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;
  	}
 @@ -812,7 +814,7 @@ udp_output(inp, m, addr, control, td)
  			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;
  
 @@ -835,6 +837,15 @@ udp_output(inp, m, addr, control, td)
  			goto release;
  		}
  	}
 +
 +	/*
 +	 * 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 and IP headers.
 @@ -1054,6 +1065,10 @@ udp_disconnect(struct socket *so)
  	s = splnet();
  	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;
 +	}
  	INP_UNLOCK(inp);
  	INP_INFO_WUNLOCK(&udbinfo);
  	splx(s);
 
 --jQIvE3yXcK9X9HBh--

From: Andre Oppermann <andre@freebsd.org>
To: Bruce M Simpson <bms@spc.org>
Cc: freebsd-net@freebsd.org, freebsd-gnats-submit@freebsd.org
Subject: Re: kern/38554: changing interface ipaddress doesn't seem to work
Date: Sat, 03 Jul 2004 10:34:58 +0200

 Bruce M Simpson wrote:
 > 
 > Please review the attached patch (which is a reworking of Archie's
 > patch for -CURRENT). When the underlying IP address is changed,
 > wildcard-bound UDP sockets which are temporarily bound locally for
 
 UDP socket which are not bound to a particular IP address would do the
 right thing already?  I thought so.
 
 > a sendto() (by userland apps such as ntp, syslogd etc) will begin
 > using the new IP address, whilst apps using TCP (ssh, Quagga bgpd) will
 > error out with EADDRINUSE.
 
 This error is misleading.  The address is gone, not in use.  Isn't there
 a better fit?
 
 > I would appreciate any feedback on our adopting this behaviour (which
 > strikes me as similar to that of Solaris and a few other OSes).
 
 I have only quickly glanced over it, but it sounds the right thing to
 do.
 
 -- 
 Andre

From: Robert Watson <rwatson@freebsd.org>
To: Andre Oppermann <andre@freebsd.org>
Cc: Bruce M Simpson <bms@spc.org>, freebsd-net@freebsd.org,
	freebsd-gnats-submit@freebsd.org
Subject: Re: kern/38554: changing interface ipaddress doesn't seem to work
Date: Sat, 3 Jul 2004 17:53:33 -0400 (EDT)

 On Sat, 3 Jul 2004, Andre Oppermann wrote:
 
 > Bruce M Simpson wrote:
 > > 
 > > Please review the attached patch (which is a reworking of Archie's
 > > patch for -CURRENT). When the underlying IP address is changed,
 > > wildcard-bound UDP sockets which are temporarily bound locally for
 > 
 > UDP socket which are not bound to a particular IP address would do the
 > right thing already?  I thought so. 
 
 Temporarily connecting sockets/pcbs during a datagram send with an
 explicit address (i.e., sendto()) occurs in both the UDP code and UNIX
 domain socket code.  Since this is expensive, and also increases the
 potential for races of various sorts, it would be nice to do this in a
 more efficient form where possible. 
 
 Robert N M Watson             FreeBSD Core Team, TrustedBSD Projects
 robert@fledge.watson.org      Principal Research Scientist, McAfee Research
 
Responsible-Changed-From-To: bms->freebsd-net 
Responsible-Changed-By: bms 
Responsible-Changed-When: Sat Sep 23 17:36:57 UTC 2006 
Responsible-Changed-Why:  
Back to the world for you, but not after actually doing some work on it... 

http://www.freebsd.org/cgi/query-pr.cgi?pr=38554 

From: Bruce M Simpson <bms@incunabulum.net>
To: freebsd-gnats-submit@FreeBSD.org
Cc:  
Subject: Re: kern/38554: changing interface ipaddress doesn't seem to work
Date: Sat, 23 Sep 2006 18:35:50 +0100

 This is a multi-part message in MIME format.
 --------------030000070707080504040106
 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
 Content-Transfer-Encoding: 7bit
 
 Before I suspend my work on this PR, here's a diff I pulled from trying 
 to port the changes to today's CURRENT.
 The patch doesn't work but haven't tested exhaustively. Need to focus on 
 other things.
 
 --------------030000070707080504040106
 Content-Type: text/x-patch;
  name="archie-locia-20060923.diff"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: inline;
  filename="archie-locia-20060923.diff"
 
 ==== //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);
 
 --------------030000070707080504040106--
>Unformatted:
